# fxstore $ fx build app --store /fx/store

A content-addressed build store.

Dhall package set · least-fixed-point closure · `/fx/store/<hash>-<name>`.

The idea

// packages are pure functions of their inputs

fxstore is the storage + build layer of fixpoint-linux. It reads a package-set.dhall, computes the dependency closure as a least fixed point with datalog-dafsa, and gives every package a deterministic, content-addressed home in the store:

/fx/store/<sha256-of-input-closure>-<name>

Because the store path is a hash of the package's entire transitive dependency graph, a change anywhere upstream changes the path — the same inputs always produce the same artifact, and nothing is ever overwritten.

The pipeline

// spec in Dhall · closure in Datalog · build with typed actions
package-set.dhall  # { packages : List Package }
        dhall-c: parse / typecheck / normalize
        datalog-dafsa: closure least-fixed-point + topo-order
        sha256 of the canonical derivation  # /fx/store/<hex64>-<name>
        typed recipe build (bwrap-sandboxed Shell / Run)
        atomic rename + metadata-LAST transaction commit
        gc <root> prunes unreachable artifacts

Each stage is a pure function of the previous stage's typed output. The dependency-closure fixed point is computed by datalog-dafsa's native recursive rules:

closure(X) :- root(X).
closure(Y) :- closure(X), dep(X, Y).

Usage

// init · build · query · gc
$ fxstore init myproject               # scaffold a worked-example package-set.dhall
$ cd myproject
$ fxstore build app --store /fx/store  # build the closure of app (lib first), print paths
$ fxstore query app --store /fx/store  # print app's closure + store path
$ fxstore gc app --store /fx/store     # prune unreachable store dirs

Dependencies are exported to each package's recipe as FX_DEP_<NAME> environment variables. Build again after a source change and only the affected slice of the store rebuilds.

Features

// content-addressed · reproducible · crash-consistent
01

Content-addressed

The store path is a sha256 of the full input closure — a change anywhere upstream changes the path.

02

Closure fixed point

Transitive reachability is computed by datalog-dafsa's native recursive rules; cycles are rejected.

03

Crash-consistent

Build into a temp dir, atomic rename, then metadata-LAST transaction commit — a crash leaves a reapable orphan, never dangling metadata.

04

Typed recipes

Recipes are the same Dhall tagged-union Action values that dhake executes.

05

Sandboxed exec

Shell / Run actions run under bwrap (--unshare-all, network off) with a loud non-hermetic fallback.

06

Time travel, native

Built on datalog-dafsa's versioned snapshots + as-of queries — a timeline / rollback layer slots straight on top.

Security

// trusted-author model · sandboxed exec

The two executing recipe actions (Shell, Run) run under bwrap (--unshare-all --die-with-parent, store + toolchain read-only-bound, network off). The pure-FS actions (Copy, Mkdir, …) run in-process under a trusted-author model — the package-set author is trusted, mirroring how fixpoint-linux treats its own spec.