flake-like toml nix pins, lazily fetched and transformed
maintains pins.toml (what you want), pins.lock.json (what's fetched),
and a vendored default.nix resolver to consume locked inputs without
nix's flake machinery — all tucked into ./.tack/ so your repo root
stays clean.
tack init creates ./.tack/ (override with $TACK_DIR) containing:
pins.tomlinputs and shorturl schemes, hand-editablepins.lock.jsonresolved inputs, written bytack update, read by nixdefault.nixthe resolver;import ./.tackgives a name -> input attrset
let inputs = import ./.tack;
in inputs.nixpkgs.legacyPackages.x86_64-linux.helloor from a flake:
outputs = { self }:
let inputs = import ./.tack; in {
packages.x86_64-linux.default =
inputs.nixpkgs.legacyPackages.x86_64-linux.hello;
};tack keeps default.nix in sync with the running binary while a
tack-managed comment is present at its top; delete that line to fork
the resolver.
legacy ./inputs.nix at repo root is detected and preserved as-is.
tack init [--force]
tack update [names...] [--accept] fetch latest, rewrite lock
tack look [names...] [--verbose|-v] report pins with newer upstream revs
tack add <name> <url> [--fetch|--fixed [--unpack tarball|file]]
[--dir <d>] [--submodules] [--follows c=p]...
tack rm <name>
tack alias <name> <template> define a shorturl scheme
tack alias --rm <name> remove one
tack dedup report inputs reachable from multiple pins
tack dedup reports inputs reachable from more than one of your pins, whether
direct or transitive, and recurses through the pins of your pins indefinitely.
when a top-level pin matches, it suggests an [all_follow] rule to share it.
flake(default) — evaluate the input'sflake.nix, expose its outputsfetch— source tree only, no flake eval. legacyflake = falsefixed— hash-locked download; won't drift,tack updaterefuses to silently relock (use--acceptif you want to)
[inputs.release]
url = "https://example.com/release-1.2.3.tar.gz"
type = "fixed"
# unpack = "tarball" | "file" # auto-detected from the URLgithub:owner/repo[/ref]tarball via codeloadgit+https://.../git+ssh://...any git remote;?ref=<branch>/?rev=<sha>to pin,submodules = trueto recursehttps://.../http://...raw tarball, where the format is inferred from the extension (e.g..tar,.tar.gz/.tgz,.tar.xz/.txz).
scheme:rest expands by substituting rest into the template {path}
[shorturls]
gh = "github:{path}"
[inputs.coolproject]
url = "gh:owner/coolproject"point a pin's input at one of your top-level pins instead of its own lock
[inputs.foo]
url = "gh:owner/foo"
follows = { nixpkgs = "nixpkgs" } # foo's nixpkgs -> your nixpkgs pinall_follow applies a rule to every pin that has a matching input
[all_follow]
nixpkgs = "nixpkgs" # every input named nixpkgs follows your nixpkgs pin
[inputs.bar]
url = "gh:owner/bar"
exclude_follow = ["nixpkgs"] # ...except bar'snix develop # rust toolchain + openssl/libgit2
nix build # the binary
EUPL-1.2. see LICENSE