Manzil Contracts

Manifest contracts

Manzil's bundled linker consumes v3 manifests with an explicit contract section:

{
  "version": 3,
  "contracts": {
    "target_root": "/home/alice",
    "source_roots": ["/nix/store"]
  },
  "files": [
    {
      "type": "symlink",
      "target": "/home/alice/.zshrc",
      "source": "/nix/store/...-zshrc"
    }
  ]
}

Why contracts exist

Contracts make the manifest machine-checkable before any filesystem mutation happens. They let the linker reject manifests that would:

This reduces hidden behavior and makes the linker safer to reuse in tests and automation.

Current contracts

contracts.target_root

Every manifest target must stay under this root. For Manzil-generated manifests, that is the user's managed home directory.

contracts.source_roots

Every source path must stay under one of these roots. For Manzil-generated manifests, that is currently the Nix store.

What gets validated

The bundled linker validates:

Validation happens in 2 layers:

  1. Manifest load: lexical checks on the manifest paths themselves.
  2. Activation/deactivation: resolved-path checks against the live filesystem.

That keeps manifests machine-checkable before mutation while still rejecting symlinked-parent escapes and resolved sources outside the declared roots.

Tmpfiles mode

manzil.linker = null does not use manifest contracts. That mode only supports a reduced subset of the file model and should be treated as a compatibility fallback.

Debugging contract failures

Typical failure cases:

If a build fails, inspect the generated manifest first. The helper library exposes manifestForUser, and the NixOS tests in this repository also exercise contract validation directly.