Compile ordered Markdown policy modules into one deterministic, verifiable
AGENTS.md. The target can be global, repository-local, nested, or another
explicit path. The runtime has no dependencies, performs no network access,
invokes no shell, and uses no LLM.
One manifest owns one ordered module set and one default target. The compiler does not need a scope flag because Codex scope comes from the target path and the startup working directory:
| Purpose | Typical target | Verification context |
|---|---|---|
| Global policy | ~/.codex/AGENTS.md |
Isolated empty directory |
| Repository policy | <repo>/AGENTS.md |
Repository root or descendant |
| Nested policy | <repo>/<area>/AGENTS.md |
Target directory or descendant |
| Standalone export | Any new path | No Codex visibility promise |
The same lock, validate, check, install, status, and rollback
workflow applies to every target. verify-codex adds the startup directory
needed to prove that Codex actually discovers project and nested targets.
Codex loads one global instruction file and then builds a project instruction chain from the project root toward its startup working directory. A closer file is applied later. See the official Codex AGENTS.md guide.
Canonical modules are easier to review and reuse than one large hand-maintained file, but Codex needs a self-contained file at startup. This compiler connects those needs without hiding provenance:
- canonical Markdown modules remain the only editable policy sources;
- a strict manifest fixes the source set, order, and target;
- a portable lock records each lexical source path, byte size, and SHA-256;
- rendering preserves every accepted source byte between generated markers;
- checking detects source drift, output drift, a missing target, shadowing, and unmanaged content;
- installation is explicit, atomic, backed up, and concurrency-safe;
- rollback restores exact prior bytes and refuses after an external target edit;
- runtime verification inspects Codex prompt input instead of asking a model what it thinks it read.
The tool does not discover repositories, detect stacks, select targets, or generate multiple files from one manifest. It does not author, rewrite, summarize, lint-fix, normalize, or deduplicate policy prose.
- Python 3.14 or newer.
- Linux, macOS, or Windows.
codexonPATHonly for optional runtime visibility verification.
# Recommended: install as an isolated tool.
uv tool install agents-md-compiler
# Or run without installing.
uvx agents-md-compiler --help
# Or install into an existing environment.
pip install agents-md-compilerBoth invocation forms are equivalent:
agents-md-compiler --help
python -m agents_md_compiler --helpinit defaults to the active global base file and prints the exact lock command
to run next.
# Creates policy/agents-md.toml and policy/modules/*.md.
agents-md-compiler init --directory ./policy --bundle-id personal-policy
# Create the target parent when this is a new Codex home.
mkdir -p ~/.codex
agents-md-compiler lock --manifest ./policy/agents-md.toml
agents-md-compiler validate --manifest ./policy/agents-md.toml
agents-md-compiler render --manifest ./policy/agents-md.toml --locked
agents-md-compiler check --manifest ./policy/agents-md.toml
# Preview writes nothing.
agents-md-compiler install --manifest ./policy/agents-md.toml
# Explicitly mutate the target.
agents-md-compiler install --manifest ./policy/agents-md.toml --apply
# Prove the active global file is visible without project instructions.
agents-md-compiler verify-codex --manifest ./policy/agents-md.tomlRun this from the repository root. The target argument resolves from the current
directory. init serializes it relative to .agents, so the generated manifest
contains the portable value ../AGENTS.md.
agents-md-compiler init \
--directory ./.agents \
--target ./AGENTS.md \
--bundle-id project-policy
agents-md-compiler lock --manifest ./.agents/agents-md.toml
agents-md-compiler validate --manifest ./.agents/agents-md.toml
agents-md-compiler check --manifest ./.agents/agents-md.toml
agents-md-compiler install --manifest ./.agents/agents-md.toml
agents-md-compiler install --manifest ./.agents/agents-md.toml --apply
# Prove the repository file is visible from this startup directory.
agents-md-compiler verify-codex \
--manifest ./.agents/agents-md.toml \
--cwd .For a nested target, use the same layout and pass a working directory equal to or below the target's parent:
agents-md-compiler verify-codex \
--manifest ./.agents/backend/agents-md.toml \
--cwd ./backend/serviceCURRENT means the selected target is byte-identical to a fresh locked render.
It does not claim that Codex discovers that target from every possible working
directory. A successful verify-codex makes the visibility claim only for its
reported startup directory.
- Edit canonical module files, never the generated target.
- Review the module and manifest changes.
- Run
lockexplicitly to refresh source identity. - Run
validateand reviewrender --lockedwhen needed. - Run
checkto see whether the selected target needs installation. - Preview
install, then rerun it with--apply. - Run
verify-codexwith the applicable startup context.
Editing a module after locking produces LOCK_STALE and exit code 2. Read-only
commands never refresh a lock or install a target implicitly.
When --manifest is omitted, the CLI uses ./agents-md.toml. It falls back to
legacy ./global-agents.toml only when the neutral default is absent. If both
exist, the invocation is ambiguous and must use explicit --manifest.
- Manifest
default_targetis the persistent managed destination. A relative value resolves from the manifest directory. A leading~expands through the standard home lookup. --target PATHoverrides the managed destination for one invocation. A relative command-line path resolves from the current working directory.render --locked --output PATHwrites one standalone file only when the path does not exist. It never replaces an existing file or creates its parent.
Codex visibility is promised only for paths Codex actually discovers. A custom file name can still use compilation, checking, installation, and rollback, but a runtime probe will not pass unless Codex includes those bytes through its normal instruction discovery.
An existing file without a recognized generated header is unmanaged and is never replaced silently. First preview the install and capture the current file digest. Then provide both adoption flags:
shasum -a 256 ./AGENTS.md
EXPECTED_TARGET_SHA256=<captured-64-character-digest>
agents-md-compiler install \
--manifest ./.agents/agents-md.toml \
--apply \
--replace-unmanaged \
--expect-target-sha256 "${EXPECTED_TARGET_SHA256}"A digest mismatch refuses the write. A successful adoption stores the exact handwritten predecessor as a backup before replacing it.
All target mutations require --apply. Dry runs create no target, backup,
receipt, deployment directory, or advisory lock.
New operational evidence is scoped by bundle ID and resolved target digest under the user state root:
- Linux and macOS:
${XDG_STATE_HOME:-~/.local/state}/agents-md-compiler/ - Windows:
%LOCALAPPDATA%/agents-md-compiler/
Advisory locks live in one distribution-wide namespace and are keyed only by the resolved protected path. Two different bundle IDs therefore coordinate when they select the same target. Two targets using one bundle ID retain separate receipts, backups, preserved files, and last-install state.
Rollback consumes one explicit install receipt:
agents-md-compiler rollback \
--manifest ./.agents/agents-md.toml \
--receipt <path/to/install-receipt.json> \
--applyRollback refuses unless the target still matches the receipt's installed digest. Backups are never deleted or rotated automatically. When an install created a previously missing target, rollback moves the generated file into private state instead of deleting it irrecoverably.
Other safety boundaries:
- sources and targets that are symbolic links are refused;
- target parents must already exist and be directories;
- a non-empty sibling
AGENTS.override.mdshadows a selectedAGENTS.mdand causesSHADOWED; - a source may not alias the selected output;
- a source containing the compiler marker prefix is rejected;
- an unknown future rendered format is unmanaged and requires explicit adoption.
If a post-replacement step fails, recovery runs under the same target lock. It first proves that the target still contains the operation's bytes, then restores the predecessor from its verified backup or preserves a newly generated file and restores prior absence.
Current releases emit portable lock format 2 and neutral rendered format 2.
- A strict format-1 lock is migration input. Read-only commands report
LOCK_STALE; explicitlockreplaces it atomically with format 2. - Exact format-1 and format-2 rendered targets are managed. A format-1 target is
DRIFTEDand upgrades through ordinary explicit install without unmanaged-file adoption flags. - Upgrade installation backs up exact format-1 bytes. Receipt-based rollback can restore them when the format-2 target has not changed.
- Legacy bundle-only install receipts remain accepted for explicit validated rollback. New evidence is written only to target-qualified deployment state.
Commit the manifest, canonical modules, portable lock, and generated target when the repository chooses to track generated output. A read-only CI gate can run:
agents-md-compiler lock --manifest ./.agents/agents-md.toml --check
agents-md-compiler validate --manifest ./.agents/agents-md.toml
agents-md-compiler check --manifest ./.agents/agents-md.tomlverify-codex is an environment integration gate, not a deterministic unit gate.
Run it where the intended Codex executable and startup context are available.
- Equal manifest and source bytes produce equal format-2 lock and rendered bytes across checkout roots.
- Output contains no timestamp, host name, process ID, random value, temporary path, resolved source path, package version, or working directory.
- Manifest order is output order. Rendering does not enumerate source folders.
- Sources must be non-empty strict UTF-8 with LF line endings and exactly one final LF. BOM, NUL, CR, invalid UTF-8, and marker collisions are rejected.
- Accepted source bytes are copied exactly. The compiler never trims, reflows, normalizes, lint-fixes, summarizes, or deduplicates them.
Digests prove that bytes did not change between locking and rendering. They do
not establish authorship, correctness, or safety. See
docs/security-model.md.
Every command accepts --format json and emits exactly one JSON object to stdout.
Diagnostics remain on stderr.
agents-md-compiler status \
--manifest ./.agents/agents-md.toml \
--format jsonDrive automation from the exit code and inspect state for the reason:
| Code | Meaning |
|---|---|
| 0 | Succeeded; CURRENT when a target state applies |
| 1 | Invalid invocation, input, I/O, or runtime verification failure |
| 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 or requested
render output.
verify-codex resolves codex from PATH, captures codex --version, confirms
that debug prompt-input is available, and searches the returned JSON for the
generated marker, every module boundary, and unique content sentinels from the
first and last modules.
For the active global base or override file, the probe runs from a disposable
empty directory. For a project or nested target, it runs from explicit --cwd or
the target parent. The project directory must be equal to or below the target
parent.
The command sends no model request, requires no API authentication, changes no
Codex configuration, and makes no semantic-compliance claim. Marker presence
proves visibility, not obedience. If the debug interface is missing or changed,
the state is RUNTIME_UNVERIFIED and the exact failing command is reported.
| Document | Contents |
|---|---|
docs/manifest-v1.md |
Manifest schema, path bases, and rejection rules |
docs/rendered-format-v1.md |
Frozen legacy lock and rendered format |
docs/rendered-format-v2.md |
Current portable lock and neutral rendered format |
docs/cli-contract.md |
Commands, options, JSON, states, and exits |
docs/security-model.md |
Trust, path, concurrency, and recovery boundaries |
AGENTS.md |
Generated project contract for repository agents |
CONTRIBUTING.md |
Development, tests, and release boundaries |
MIT. See LICENSE.