Agent Task Map Language (ATML) captures coding-agent operations into an immutable raw journal and compiles them into an ordered semantic task tree. Its shallow nodes summarize completed outcomes; its deep leaves retain observable evidence such as file changes, exact commands, searches, and verification results.
Codex lifecycle hooks → raw JSONL + hashed blobs → contiguous hierarchy compiler → traces.json
This repository includes:
atml_tui.py— a dependency-free interactive terminal viewer fortraces.json.atml/— raw capture, content-addressed storage, write splitting, segmentation, and replay.atml_cli.py— compile, validate, and reconstruct commands.traces.json— an example ATML trace.tests/— unit coverage for validation, navigation, wrapping, color roles, and command disclosure..skill-staging/— the three Codex skill packages ready to install globally.
From a clone of this repository, run the setup script once:
git clone https://github.com/balalida22/ATML.git
cd ATML
bash scripts/setup-codex-atml.shIt installs the three ATML skills and the capture runtime, then registers one
program for prompt, wildcard tool, compaction, subagent, and Stop lifecycle
events in ~/.codex/hooks.json. Existing unrelated hook entries are preserved
and setup is idempotent. Start a new Codex session afterwards.
The script needs Bash and Python 3, both of which are already required by this
project. To install into a different Codex home, set CODEX_HOME:
CODEX_HOME="$HOME/.config/codex" bash scripts/setup-codex-atml.shThe hooks do not ask the model to reconstruct its actions. They append the
available tool inputs and results as events, snapshot workspace state, and
compile the current run at Stop. traces.json remains the concise ATML 1.0
projection; raw evidence lives under .atml/ and is ignored by Git by default.
ATML registers .* tool matchers so newly hookable tools are captured without
an installer update. At Stop it also reads the Codex rollout at
transcript_path, selects only records carrying the current turn_id, pairs
every tool call with its output, and reconciles statically visible nested tool
names with hook results. Calls absent from the hook journal are recovered into
hashed input/output blobs. Conversation messages and reasoning records are
never imported.
Codex documents the transcript as a non-stable interface. ATML handles that by
recognizing records from their fields rather than assuming a single schema and
by failing closed: capture.complete is true only when hook start/result pairs,
all transcript call/result pairs, transcript parsing, and the final workspace
snapshot reconcile. missing_categories explains any failed proof. Thus a
format change produces an explicit incomplete run instead of silent evidence
loss. state_reconstruction_complete remains independent because the final
content-addressed workspace manifest can still be exact.
.atml/
runs/<session>--<turn>/
events.jsonl # append-only metadata
workspace-state.json # latest capture state
blobs/sha256/<prefix>/<digest>
compiled/<session>--<turn>.json
traces.json # ATML 1.0 TUI export
Large tool payloads, file contents, patches, and manifests are stored by SHA-256
and referenced from the journal. The initial and final manifests include file
mode, content hash, and blob reference. Later snapshots reuse these values when
strong file metadata (size, mode, modification time, and change time) is
unchanged, avoiding repeated content reads and hashes. Cache metadata is
excluded from reproducible manifest hashes. .git, .atml, caches, and the
derived traces.json file are excluded from workspace snapshots.
The dependency-free prototype performs these deterministic stages:
- Normalize hook results and transcript-recovered calls into exact commands, MCP reads/searches, generic tool evidence, and file mutations.
- Parse compound shell commands by executable so search terms cannot be mistaken for test commands, and retain only repository files as artifact features.
- Diff before/after file blobs. Python changes are distributed line-by-line across qualified AST owners; Markdown uses headings; JSON/YAML uses keys; TOML/INI uses sections and keys; CSS uses selectors; and SQL uses statements.
- Extract structured test outcomes such as
8 tests passedwhile retaining the full output blob as raw evidence. - Describe every atom with operation, artifact, symbol, verification, and lexical features.
- Use exact-k dynamic programming to partition only consecutive atoms. The cost rewards shared artifacts, sibling-directory rollouts, repeated symbol shapes, and write/verification closure while penalizing artifact and phase dispersion. Once a multi-file sibling rollout forms, shallow levels preserve it as a coherent objective unless the requested target count forces a merge.
- Derive group and run labels from descendant symbols, capabilities, and artifact scopes. Repeated worker/adaptor rollouts name their concrete files or range instead of reusing a generic capability label; no label may add evidence absent from its descendants.
- Replace every segment with a group, collapse generated unary groups, repeat recursively, and add one run-level objective.
- Aggregate read and verification relations at file-mutation scope. Python test calls add conservative test-to-production symbol coverage. A verification covering more than four mutations targets one inspectable verification-scope node instead of emitting dozens of redundant graph edges.
- Export the rich compiler tree and a backwards-compatible ATML 1.0 tree.
The standard-library splitter remains extensible: Tree-sitter/GumTree and an embedding-backed semantic term can be added later without changing the raw journal or hierarchy invariants.
The Stop hook compiles automatically. To work with a captured run manually:
python3 atml_cli.py validate-raw .atml/runs/<run-id>
python3 atml_cli.py compile .atml/runs/<run-id> --compression 3.5 --top-count 3
python3 atml_cli.py reconstruct .atml/runs/<run-id> /tmp/atml-reconstructedvalidate-raw checks monotonic event sequence numbers and verifies all blob
hashes, including file blobs reachable through workspace manifests.
reconstruct writes the final captured workspace state and compares its
manifest hash. This is exact state reconstruction; re-executing recorded
commands remains best effort because commands may depend on network, time,
environment, randomness, or tool versions.
The Stop hook creates traces.json when a captured run contains atomic
operations. traces.json is ignored in this repository; remove its line from
.gitignore if you want your project to commit its task maps.
- Python 3.10 or newer.
- A terminal with
cursessupport. Most Unix-like Python installations include it. - Codex, if you want to use the ATML skills.
No Python packages need to be installed for the viewer.
Clone the repository and start the viewer from its root:
git clone https://github.com/balalida22/ATML.git
cd ATML
python3 atml_tui.py traces.jsonPass --expand-all to open every branch initially:
python3 atml_tui.py --expand-all traces.jsonValidate a trace without opening the terminal UI:
python3 atml_tui.py --validate traces.json| Key | Action |
|---|---|
| Up / Down | Move to the previous or next sibling |
| Left | Move to the parent without collapsing it |
| Right | Expand a branch and enter its first child |
| Space / Enter | Toggle the selected branch |
e / c |
Expand all / collapse all |
| Home / End | First / last visible node |
q / Esc |
Quit |
Command evidence is displayed in a separate command color. Modified-file leaves append a structured suffix such as (+12, -3 src/auth.ts).
The quick-setup script above is the recommended installation method. To install only the skills manually, copy the three staged skill folders into Codex’s global skill directory:
mkdir -p ~/.codex/skills
cp -R .skill-staging/atml-bootstrap-traces \
.skill-staging/atml-update-traces \
.skill-staging/atml-expand-traces \
~/.codex/skills/Start a new Codex session after installation. Then use:
Use $atml-bootstrap-traces to create traces.json for this repository.
Use $atml-update-traces to validate or recompile the captured run.
Use $atml-expand-traces to make the trace more detailed or concise.
Use the setup script unless you need to manage the configuration yourself. A
Codex lifecycle hook is a command that receives JSON on standard input. Copy
the tracked hook program, then add entries in ~/.codex/hooks.json while
preserving existing hooks. This shows the PostToolUse entry:
mkdir -p ~/.codex/hooks
cp -R atml ~/.codex/hooks/atml
install -m 755 scripts/atml_hook.py ~/.codex/hooks/atml_hook.py{
"hooks": {
"PostToolUse": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "/usr/bin/env python3 /home/you/.codex/hooks/atml_hook.py",
"timeout": 60,
"statusMessage": "Recording ATML tool result"
}
]
}
]
}
}Replace /home/you with your actual home directory and add equivalent entries
for UserPromptSubmit, PreToolUse, PreCompact, PostCompact,
SubagentStart, SubagentStop, and Stop. The setup script is preferred
because it safely upgrades and merges the entries. Restart Codex after changing
the file.
Any retained command activity is represented as a purpose-labeled branch. Each exact invocation is a direct child evidence leaf, allowing a reviewer to expand only the commands they need to inspect.
{
"id": "2.1",
"label": "Verify the completed behavior",
"children": [
{
"id": "2.1.1",
"label": "python3 -m unittest discover -v",
"evidence": {
"kind": "run_command",
"value": "python3 -m unittest discover -v",
"result": "14 tests passed"
}
}
]
}For modified files, use optional file_changes data with only attributable line counts:
"file_changes": [
{
"path": "atml_tui.py",
"action": "modify",
"additions": 48,
"deletions": 14
}
]Use null for a count that cannot be measured safely; do not estimate it.
python3 -m unittest discover -v
python3 -m py_compile atml/*.py atml_cli.py atml_tui.py scripts/*.py
python3 atml_tui.py --validate traces.jsonThe repository is ready to commit once those checks pass.