Core concepts

Policy

Why Warden compiles policy into canonical MIR, where that fits in the pipeline, and the shortest path from a policy source to an enforced decision.

Why compiled policy exists

You describe what a command may do in terms that make sense to you: this directory readable, that one writable, this host reachable. A backend needs something else entirely — an SBPL profile, a namespace layout, a set of mounts. Between those two ends sits a translation problem, and where it happens decides what the system can promise.

Warden resolves it once, ahead of time, rather than in each backend. Your policy source is compiled into a canonical MIR: a single, already-resolved statement of what the workload may do. Precedence between overlapping rules, ordering, normalisation and deduplication are all settled during that compilation. What reaches a backend is unambiguous, and backends enforce it without ever re-interpreting your intent.

That choice buys three properties worth naming, because the rest of Warden depends on them:

  • Portable — the same MIR expresses the same decision on macOS and on Linux. A policy reviewed once is a policy that travels.
  • Backend-agnostic — the planner compares the MIR's requirements against each backend's capabilities, instead of every backend parsing policy on its own. Adding a backend does not mean re-implementing policy semantics.
  • Content-addressed — the MIR has a digest, so the exact decision that was enforced can be named, compared and audited afterwards. This is what makes an execution receipt evidence rather than a log line.

Where policy fits

ARCHITECTUREPolicy in the execution pipeline
    • Policy sourceJSON, inline flags or the C builder
    • Canonical MIRone resolved, digestible decision
    • Plannermatches requirements to backend capabilities
    • Backendenforces the decision as written

Compilation happens once, before anything is enforced. Everything downstream consumes the canonical form: the planner reads its requirements, the backend applies them, and the receipt records its digest.

Policy is the first stage, and it is deliberately the only stage that interprets your intent. Read Architecture for the full picture, including where Egress and receipts attach.

What you actually write

MIR is the compiled form, not the thing you author. In practice you supply one of three sources, and Warden compiles it for you:

SourceYou writeTypical use
Inline flags--ro, --rw, --allow-read, --allow-write, --netone-off commands, scripts, CI steps
JSON policya strict JSON policy source, passed with --policya reviewed policy shared across commands
C buildercalls against the MIR builder APIembedding Warden in another product

The binary .mir file is optional in all three cases. A caller can compile a JSON source in memory and hand Warden the resulting object without ever writing a file to disk.

The shortest path from source to enforcement

Most CLI users never handle a .mir file. --policy takes a strict JSON policy source, compiles it to canonical MIR in memory, and runs the command under it:

CODE
maelys-warden run \
  --policy examples/policies/workspace-readonly.json \
  --emit-mir /tmp/effective.mir \
  --receipt /tmp/execution.json \
  -- make test

--emit-mir serialises exactly the canonical decision that was used, and --receipt records the digest of that decision next to the backend that enforced it. Neither file is written unless you ask for it.

An already-compiled MIR is passed with --plan instead of --policy, which is the right shape for a policy that was reviewed, signed or distributed separately:

CODE
maelys-warden run --plan /tmp/effective.mir -- make test

Because the compilation is deterministic, recompiling the same source reproduces the same digest. That is what lets you prove, after a run, that the policy which was reviewed is the policy that was enforced.

Summary

  • Warden compiles your policy source into canonical MIR — one resolved, unambiguous decision — before anything is enforced.
  • Canonical form is what makes the decision portable across platforms, reusable across backends, and auditable by digest.
  • You author inline flags, a JSON source, or builder calls; you rarely handle MIR directly, and the .mir file is optional.
  • --policy compiles a source in memory; --plan runs an already-compiled MIR; --emit-mir and --receipt capture the decision and the evidence.

Where to go next

  • Execution receipts — what a run proves after the fact, and how a MIR digest appears in it.
  • Architecture — where compilation sits relative to the planner, backends and Egress.
  • Backend capability matrix — which requirements each backend can actually satisfy.
  • CLI reference — every policy source flag and its invalid combinations.
  • policy.maelys.dev — the full authoring reference: the JSON/MIR language, typed permission entries, the C builder API and offline compilation.