agents-md-compiler
Compile an ordered set of Markdown policy modules into one deterministic,
verifiable global AGENTS.md. No runtime dependencies, no network access, no
shell invocation, and no LLM anywhere in the pipeline.
Why this exists
Coding agents read their instruction files once, at startup. Codex selects a
single non-empty global file, builds its project instruction chain from the
project root through the startup working directory, and then stops looking.
Changing directories later does not add instructions to a running session, and
Codex treats a Claude-style @path import as ordinary Markdown rather than as an
include directive.
That leaves two options for a rule that must be available before task scope is known: paste everything into one enormous hand-maintained file, or generate that file from modular sources. Hand-maintaining it means the file drifts from the sources, nobody can tell which version is live, and a careless edit silently deletes a rule.
This tool takes the second option and makes it auditable:
- canonical Markdown modules stay the only editable policy sources;
- one reviewed manifest fixes the module set and its order;
- a lock records each source's resolved path, byte size, and SHA-256;
- rendering emits one self-contained file with stable provenance headers and the exact source bytes between generated markers;
- checking detects source drift, output drift, a missing target, shadowing, and an unmanaged target;
- installation is explicit, backed up, concurrency-safe, and atomic;
- rollback restores the exact prior bytes, and refuses if the target changed;
- verification inspects the model-visible startup input instead of trusting a model to say it read the rules.
It deliberately does not generate nested or project-level AGENTS.md files, and
it never detects your stack and writes rules for it. A repository may keep its own
root AGENTS.md for concrete project facts; this compiler leaves that file alone.
Requirements
- Python 3.14 or newer.
- Linux, macOS, or Windows.
- No runtime dependencies. The package uses the standard library only.
codexonPATHonly for the optionalverify-codexcommand.
Install
# Recommended: install as an isolated tool.
uv tool install agents-md-compiler
# Or run without installing.
uvx agents-md-compiler --help
# Or into an existing environment.
pip install agents-md-compiler
Both invocation forms are supported and equivalent:
agents-md-compiler --help
python -m agents_md_compiler --help
Five minutes end to end
Scaffold an example manifest and modules, then lock, render, check, and install.
# 1. Scaffold. The manifest targets ~/.codex/AGENTS.md by default.
agents-md-compiler init --directory ./policy
# 2. Create the selected target's parent if this is a new Codex home.
mkdir -p ~/.codex
# 3. Record exact source paths, sizes, and digests.
agents-md-compiler lock --manifest ./policy/global-agents.toml
# 4. Validate the manifest, lock, sources, and rendered structure.
agents-md-compiler validate --manifest ./policy/global-agents.toml
# 5. Look at the bytes before writing anything anywhere.
agents-md-compiler render --manifest ./policy/global-agents.toml --locked | head -20
# 6. Compare a fresh locked render against the target.
agents-md-compiler check --manifest ./policy/global-agents.toml
# 7. Preview the install. This writes nothing at all.
agents-md-compiler install --manifest ./policy/global-agents.toml
# 8. Install for real.
agents-md-compiler install --manifest ./policy/global-agents.toml --apply
Editing a canonical module after step 3 makes check exit 2 with LOCK_STALE
until you rerun lock. That coupling is the point: the reviewed manifest, the
lock, and the live file always agree or the tool tells you they do not.
Choose where output goes
Use one of three destination controls according to the operation:
- Set manifest
default_targetfor the persistent managed destination. A relative value resolves from the manifest directory.~expands to the user's home. - Pass
--target PATHtovalidate,check,status,install,rollback, orverify-codexto override the managed destination for one invocation. A relative command-line path resolves from the current working directory. - Pass
render --locked --output PATHto export one new standalone file. This never replaces an existing path and does not create its parent directory.
For example, preview and then install to an explicit managed target:
agents-md-compiler install \
--manifest ./policy/global-agents.toml \
--target ~/.codex/AGENTS.md
agents-md-compiler install \
--manifest ./policy/global-agents.toml \
--target ~/.codex/AGENTS.md \
--apply
The selected target may have another file name, but only a real global
AGENTS.md can be verified through Codex startup input. verify-codex therefore
fails for an otherwise current custom target that Codex does not load globally.
Safety behavior you should know before installing
An existing target that this tool did not generate is never replaced
silently. If the target exists but carries no recognized generated header,
install --apply refuses with UNMANAGED_TARGET and exit code 3. Adopting that
file requires both flags, and the digest must match what you captured from the
dry run:
# Capture the exact current bytes first.
shasum -a 256 ~/.codex/AGENTS.md
EXPECTED_TARGET_SHA256=<the 64-character digest you just captured>
agents-md-compiler install \
--manifest ./policy/global-agents.toml \
--apply --replace-unmanaged \
--expect-target-sha256 "${EXPECTED_TARGET_SHA256}"
If the digest does not match, the install refuses rather than overwriting a file that changed under you.
Every successful install writes an immutable backup and a receipt under the user state root:
- Linux and macOS:
${XDG_STATE_HOME:-~/.local/state}/agents-md-compiler/ - Windows:
%LOCALAPPDATA%/agents-md-compiler/
Rollback takes a specific receipt and refuses if the target changed after installation:
agents-md-compiler rollback --receipt <path/to/receipt.json> --apply
Backups are never deleted or rotated automatically. If installation created a previously missing target, rollback moves the generated file into the state directory instead of deleting it irrecoverably.
Other refusals worth knowing:
render --output PATHwrites only to a path that does not exist. Useinstallwhen you want replacement, backup, and rollback semantics.- The selected output or target parent must already exist and must be a directory. Dry runs reject an unusable parent before describing the target as missing.
- A symlinked target is refused, never followed.
- A symlinked source is refused, with both the lexical and resolved paths reported.
- A non-empty global
AGENTS.override.mdbeside the target is aSHADOWEDfailure, because Codex would load the override instead of the file you just installed.
If an install fails after atomically replacing the target but before all receipt state is committed, recovery runs while the target lock is still held. It first proves the target still contains the bytes written by that operation. It then restores an existing predecessor from its verified backup, or preserves a newly created generated file under the private state root and restores the target to its prior missing state. If either proof fails, the command reports recovery as failed and does not overwrite unknown bytes.
Guarantees
Deterministic output:
- identical manifest bytes, lock bytes, format version, and source bytes produce identical output bytes;
- generated output contains no timestamp, host name, process ID, random value, temporary path, tool version, or working directory, so upgrading this tool cannot change your policy bytes;
- manifest order is output order, and rendering never depends on directory enumeration order.
Source preservation:
- every source is read as strict UTF-8 bytes and must use LF line endings with exactly one final LF;
- a UTF-8 BOM, a NUL byte, a CR byte, or invalid UTF-8 is rejected;
- accepted bytes are copied verbatim between generated markers, never trimmed, reflowed, lint-fixed, normalized, or summarized;
- a source containing a compiler marker line is rejected rather than escaped.
Provenance, not trust: digests prove that bytes did not change between locking
and rendering. They establish neither authorship nor safety. See
docs/security-model.md.
JSON automation
Every command accepts --format json and prints exactly one JSON object to
stdout. Diagnostics stay on stderr, so a pipeline can parse stdout unconditionally.
agents-md-compiler status --manifest ./policy/global-agents.toml --format json
{
"command": "status",
"ok": true,
"schema_version": 1,
"state": "CURRENT"
}
Drive automation from the exit code, and read state for the reason:
| Code | Meaning |
|---|---|
| 0 | Succeeded; CURRENT when a target state applies |
| 1 | Invalid invocation, invalid manifest, lock, or source, or an I/O error |
| 2 | Read-only difference: LOCK_MISSING, LOCK_STALE, DRIFTED, MISSING |
| 3 | Safety refusal: SHADOWED, UNMANAGED_TARGET, CONCURRENT_CHANGE |
--quiet suppresses non-error stderr. It never suppresses JSON output or
requested render output.
Codex verification, and its limits
verify-codex confirms that the installed bundle is actually visible to the
model at startup:
agents-md-compiler verify-codex --manifest ./policy/global-agents.toml
It resolves codex from PATH without a shell, records codex --version,
confirms the CLI exposes debug prompt-input, runs a non-interactive probe from a
disposable directory containing no project instruction file, parses the returned
JSON, and confirms that the generated header, every begin and end module marker,
and unique content sentinels from the first and last modules are all present.
What it does not do:
- send a model request or require API authentication;
- modify Codex configuration or copy policy files into the probe directory;
- claim semantic compliance. Marker presence proves the bytes reached the model's input. It does not prove the model obeyed them.
codex debug prompt-input is a debug interface, not a promised stable API. If the
installed Codex removes or changes it, this command reports RUNTIME_UNVERIFIED
with the exact command and the observed failure, and exits 1. It never falls back
to asking a model to summarize its own instructions.
Documentation
| Document | Contents |
|---|---|
docs/manifest-v1.md |
Manifest schema version 1, path bases, and every rejection rule |
docs/rendered-format-v1.md |
Exact output bytes, markers, and hashing boundaries |
docs/cli-contract.md |
Commands, options, JSON envelopes, states, and exit codes |
docs/security-model.md |
Trust boundaries, path and TOCTOU handling, and recovery |
AGENTS.md |
Project contract for agents working on this repository |
CONTRIBUTING.md |
Setup, commit conventions, and release boundaries |
License
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agents_md_compiler-0.1.0.tar.gz.
File metadata
- Download URL: agents_md_compiler-0.1.0.tar.gz
- Upload date:
- Size: 66.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad28009e55e1546af0a31dbafc8e074ea9a4393b2a5dc404337f739d4072b802
|
|
| MD5 |
3bad68797d6c41d5f8c80bd3aae6cde1
|
|
| BLAKE2b-256 |
4ab3d0a794ae48c226084a79a8ca5441107537b1fab17af38b2a08eccb8f6de0
|
Provenance
The following attestation bundles were made for agents_md_compiler-0.1.0.tar.gz:
Publisher:
release.yml on netopsengineer/agents-md-compiler
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agents_md_compiler-0.1.0.tar.gz -
Subject digest:
ad28009e55e1546af0a31dbafc8e074ea9a4393b2a5dc404337f739d4072b802 - Sigstore transparency entry: 2370791605
- Sigstore integration time:
-
Permalink:
netopsengineer/agents-md-compiler@9a38c9f4f79395890f4660e6d5d9e43bc7d88b1e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/netopsengineer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9a38c9f4f79395890f4660e6d5d9e43bc7d88b1e -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file agents_md_compiler-0.1.0-py3-none-any.whl.
File metadata
- Download URL: agents_md_compiler-0.1.0-py3-none-any.whl
- Upload date:
- Size: 75.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c2a667d133ff06c9650736a7d890a8b7613c977cefa9e64ad970fef5bfe3bb7
|
|
| MD5 |
1301983a6bcf512cbeadc82ff06b54f6
|
|
| BLAKE2b-256 |
1235205cf7cb51c62a371b19290ca4ccb87dfa39e42fe70182fce36c3ec918d2
|
Provenance
The following attestation bundles were made for agents_md_compiler-0.1.0-py3-none-any.whl:
Publisher:
release.yml on netopsengineer/agents-md-compiler
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agents_md_compiler-0.1.0-py3-none-any.whl -
Subject digest:
1c2a667d133ff06c9650736a7d890a8b7613c977cefa9e64ad970fef5bfe3bb7 - Sigstore transparency entry: 2370791641
- Sigstore integration time:
-
Permalink:
netopsengineer/agents-md-compiler@9a38c9f4f79395890f4660e6d5d9e43bc7d88b1e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/netopsengineer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9a38c9f4f79395890f4660e6d5d9e43bc7d88b1e -
Trigger Event:
workflow_dispatch
-
Statement type: