AG Ledger
Overview
Track agent activity as append-only JSON lines and query prior entries without
editing historical records. Prefer the bundled sync workflow for Codex
conversations so activity tracking happens through a recurring automation rather
than per-conversation AGENTS injection.
Recommended Workflow
- Run a recurring automation with
execution_environment = "local"that executesag-ledger syncfrom the skill directory. Sync does not mutate the repository, so do not create a disposable Git worktree for each run. - Let
syncscan recent Codex rollout transcripts, derive deterministicsession start,notable change, andsession endentries, and persist state so unchanged files are skipped on later runs. - Treat the returned
closeout_stateas terminal for that scheduled run:settled: no missing entries and no failures.live_frontier: entries were appended without failures. Stop and let the next scheduled run verify the moving frontier; do not loop until zero.blocked: at least one file or state write failed. The second consecutive identical blocker fingerprint setsstable_blocked=true.
- If a sandboxed run is blocked only by the shared-ledger write barrier, request one write-capable retry. Stop after that retry and report its state; do not create a multi-rerun convergence loop.
- Use manual
appendorappend-currentonly for explicit ad hoc entries or non-Codex workflows.
Recommended automation cadence:
- hourly
Recommended automation command:
./scripts/ag-ledger sync
CLI Commands
Run from the skill directory or place scripts/ on PATH.
# sync recent Codex conversations into the ledger
ag-ledger sync
ag-ledger sync --lookback-minutes 180
ag-ledger sync --session-root ~/.codex/sessions
ag-ledger sync --state-file ~/.llm/ag-ledger/state/sync-state.json
# inspect the last persisted closeout without scanning transcripts
ag-ledger status
ag-ledger status --state-file ~/.llm/ag-ledger/state/sync-state.json
# append entry (manual session id)
ag-ledger append <session-id> "<message>"
ag-ledger apppend <session-id> "<message>"
ag-ledger append <session-id> --invoked-skill ag-learn --mode review --parent-session-id <parent-session-id> "<message>"
# append entry using current Codex thread (CODEX_THREAD_ID)
ag-ledger append-current "<message>"
ag-ledger appendc "<message>"
ag-ledger append-current --invoked-skill ag-learn --mode review "<message>"
# print current Codex session id (CODEX_THREAD_ID)
ag-ledger session-id
# filter entries
ag-ledger filter --session <session-id>
ag-ledger filter --workspace <workspace-abs-path>
ag-ledger filter --invoked-skill ag-learn
ag-ledger filter --mode review
ag-ledger filter --parent-session-id <parent-session-id>
ag-ledger filter --from YYYY-MM-DD
ag-ledger filter --from "YYYY-MM-DD HH:MM"
ag-ledger filter --from "YYYY-MM-DD HH:MM" --to "YYYY-MM-DD HH:MM"
# legacy compatibility command
ag-ledger init
ag-ledger init is deprecated. It no longer edits AGENTS.md; it prints a
migration note that points callers to the automation-first sync workflow.
Data Layout
- Root directory:
$META_LEDGER_ROOT(default~/.llm/ag-ledger) - Ledger data directory:
$META_LEDGER_ROOT/data - Sync state file:
$META_LEDGER_ROOT/state/sync-state.json - Daily file:
ledger-YYYY-MM-DD.md - Format: append-only JSONL, local timestamp at minute precision
The sync state includes a closeout record:
{
"closeout": {
"state": "blocked",
"reason": "files_failed",
"stable": true,
"blocker_fingerprint": "sha256",
"blocker_occurrences": 2
}
}
Both sync and status print the flattened fields closeout_state,
closeout_reason, and stable_blocked. Blocked output also includes
blocker_fingerprint and blocker_occurrences.
Manual entries use the existing shape:
{"time":"YYYY-MM-DD HH:MM","workspace":"/abs/path","session":"session-id","msg":"task summary"}
Sync-derived entries add source metadata so rows can be traced back to a rollout file:
{
"time":"YYYY-MM-DD HH:MM",
"workspace":"/abs/path",
"session":"session-id",
"msg":"session start: inspect current ag-ledger behavior",
"entry_kind":"session_start",
"source_key":"/abs/rollout.jsonl:42:session_start",
"source_path":"/abs/rollout.jsonl",
"source_line":42,
"source_phase":"commentary",
"source_role":"assistant",
"source_turn_index":1
}
Optional structured fields supported on manual entries and sync-derived rows:
invoked_skill: canonical skill name when the entry is part of a specific skill workflowinvoked_skills: ordered list of skill names when a transcript turn names more than oneinvocation_trigger: heuristic classification such asexplicit,implicit,required-by-repo, orcatalog-onlymode: execution mode such asreview,code, orapplyparent_session_id: parent/fork/root session id for subagent lineage
sync fills invoked_skill and invoked_skills when a transcript message
explicitly names known skills using backticks, $skill, a source path, JSON
metadata, or plain using / running language. It also sets
invocation_trigger so review tooling can filter structured data instead of
parsing prose. Sync and status summaries identify themselves with
invoked_skill=ag-ledger, mode=sync|status, and
invocation_source=ag-ledger-cli.
Notes
syncdefaults to a 24-hour lookback window.syncreads rollout transcripts from$CODEX_HOME/sessionswhenCODEX_HOMEis set, otherwise~/.codex/sessions.syncskips unchanged rollout files by file fingerprint and re-checks changed files without duplicating existing ledger rows.- Sync uses transcript event timestamps, not sync execution time, when choosing the target daily ledger file.
- A successful append run is
live_frontier, notsettled. Settlement requires a later run with zero appended entries and zero failures. - Stable blocker matching uses normalized failure kind, operation, and storage scope so changing rollout filenames do not hide a repeated write barrier.