{"slug": "saw-15-agentrail-correcting-the-record", "title": "Saw #15: agentrail, Correcting the Record", "summary": "Agentrail-rs PR #3 adds three commands to the agentrail tool — `close`, `edit` and `reserve`/`unreserve` — plus a cursor fix and a new report, after the saga on the X_eTaL typed array language grew to 150 steps and drifted from git history. The drift came from work finished in another repository (steps 101 to 104 in X_eTaL-libraries), five steps done in a parallel lane and merged in one pull request, and step 111's prompt describing a `cr\"...\"` form later dropped from the design. The author rejected the existing `reopen`-then-`complete` route because a test on a copy of the saga showed step 100 picking up a new timestamp and an unrelated commit, and fixed a second bug where `complete` advanced the cursor onto already-finished work.", "body_md": "# Saw #15: agentrail, Correcting the Record\n\n*3129 words • 16 min read* • Abstract\n\n| Resource | Link | \n|---|---|\n| **The change** | [agentrail-rs PR #3](https://github.com/sw-vibe-coding/agentrail-rs/pull/3) — close, edit, reserve; the cursor skips finished work | \n| **The tool** | [agentrail-rs](https://github.com/sw-vibe-coding/agentrail-rs) | \n| **Earlier** | [Saw #3: agentrail-rs](https://blog.softwarewrighter.com/2026/03/22/saw-agentrail-rs-icrl-dual-memory/) ·[AI Tools #2: insert, reorder, reopen](https://blog.softwarewrighter.com/2026/04/23/ai-tools-agentrail-rs-mid-saga-flexibility/) | \n| **Comments** | [Discord](https://discord.com/invite/Ctzk5uHggZ) | \n\n## The saga, and its cursor\n\nAn agent starts every session with `agentrail next`, marks the step `begin`, does the work, commits, and runs `agentrail complete`. That records the commit, a summary and a trajectory, then moves the cursor to the next step. The saga is a record of the git history, and the next session trusts it.\n\nThat model assumes the work happens in order, here, by the agent holding the cursor.\n\n## How the record drifted\n\nOn X_eTaL, the typed array language this blog’s Array Languages series follows, the saga had grown to 150 steps, and three things had happened to it:\n\n1. **Work moved to another repository.** Four steps of the equation work, 101 to 104, were finished in X_eTaL-libraries after the library moved there. In X_eTaL’s saga they were still`pending` , and the cursor had moved on to 111.\n2. **Work was done in a parallel lane.** Five steps of readable error messages were done in a lane with its own saga and merged in one pull request. The main saga still listed them as`pending` , ahead of the cursor.\n3. **The plan changed after a step was written.** Step 111’s prompt described a raw form of the new code strings,`cr\"...\"` , that was later dropped from the design.\n\nNone of that is unusual once several agents share a project. Each one is a step whose record no longer matches the history.\n\n## Why the existing commands could not fix it\n\nagentrail already had commands for changing the plan mid-saga, `insert`, `reorder` and `reopen`, all of which protect completed steps. That is right, because completed steps anchor the git history. But the protection also boxed in the stranded steps:\n\n- **`reorder 101 --to 111`** refuses, because steps 105 to 110 between them are completed, and completed steps never renumber.\n- **`reopen 100`, then `complete`,** moves the cursor to 101, but it rewrites step 100’s completion time to today and appends today’s commit to step 100’s record. Completing 101 then credits X_eTaL’s latest commit with work that lives in another repository. It corrupts two records to fix one.\n- **Hand-editing a step’s file** is forbidden by the project’s own rules, and rightly: the saga is append-only state, and a hand edit is how the record and the history drift apart silently.\n\nThe `reopen` route was tried first on a copy of the saga, and the result diffed: step 100 picked up a new timestamp and an unrelated commit. That was enough to decide that the tool, not the saga, needed fixing.\n\nAnd there was a second bug in the same place: `complete` advanced to the step after the current one whether or not that step was already done, so the cursor could land on finished work.\n\n## What changed\n\nThree commands, one fix to the cursor, and one new report.\n\n| Command | What it is for | \n|---|---|\n| `agentrail close N --summary S (--commit REF … \\\\| --elsewhere WHERE)` | complete one step out of order, recording where the work is | \n| `agentrail edit N --prompt P` | replace the prompt of a step not yet done | \n| `agentrail reserve N --for OWNER` /`unreserve N` | hand a step to someone else before the work starts | \n\n### `close`: a step done elsewhere\n\n```\nagentrail close 101 --summary \"Spatial oracle, done in the libraries repo\" \\\n  --elsewhere \"X_eTaL-libraries@0f82f93\"\n\nagentrail close 126 --summary \"Readable errors, lane readable\" \\\n  --commit 7c1e0a2          # a commit in this repository\n```\n\n`close` marks a pending, in-progress or blocked step completed, out of order, and makes the agent say where the work is: `--commit`, repeatable, for commits in this repository, resolved to full SHAs so `agentrail audit` can match them; or `--elsewhere` for anything else, stored with the step as `done_elsewhere`. Passing neither is an error. `close` never records the current commit on its own and never touches another step. If the closed step is the current one, the cursor moves on.\n\n### `edit`: a step whose plan changed\n\n```\nagentrail edit 111 --prompt docs/code-strings-step-111.md\n```\n\nThis replaces the prompt and the description `status` shows. A completed step’s prompt is history, so `edit` refuses one; reopen it first.\n\n### `reserve`: preventing the drift\n\n```\nagentrail reserve 111 --for \"cloud agent, PR to follow\"\n# ... later, after merging their PR:\nagentrail close 111 --summary \"Code strings\" --commit <merge-sha>\n```\n\nWhen a step goes to someone else, another lane, a cloud agent, another repository, it is reserved before the work starts. The cursor skips a reserved step, `complete` never lands on it, and `status` shows it as `[r] … (reserved for cloud agent)`. Closing it ends the reservation; `unreserve` takes it back.\n\n### The cursor, and stranded steps\n\n`complete` now advances to the next open step, one that is neither completed nor reserved, and says what it skipped. If none is left, it creates the next step after the highest number.\n\nAnd `status` and `next` now list every pending, unreserved step behind the cursor, because nothing will ever bring the cursor back to it, with the fix for each:\n\n```\nStranded: 4 pending step(s) behind the cursor (111):\n  101-spatial-oracle\n  102-spatial-capture\n  103-spatial-lowering\n  104-spatial-latex\n  Done elsewhere?  agentrail close N --summary ... --commit REF | --elsewhere WHERE\n  Someone else's?  agentrail reserve N --for OWNER\n  Still to do?     agentrail reorder N --to M (if no completed step lies between)\n```\n\nA silent inconsistency becomes a visible to-do with the command attached.\n\n## Reading the record\n\nAn agent’s full conversation stays on the machine it ran on. What agentrail commits with the code is the part worth keeping: what was planned and what was done, in a few sentences per step. Anyone can read it, on GitHub or in a clone, without agentrail installed.\n\n### Where the words are\n\nEverything is in the `.agentrail/` folder at the top of the repository. In X_eTaL’s, for example, [`.agentrail/steps`](https://github.com/softwarewrighter/X_eTaL/tree/main/.agentrail/steps) holds one folder per step, named by number and slug, `110-macro-contracts`. Four files tell the story:\n\n| File | What it says | \n|---|---|\n| [`.agentrail/plan.md`](https://github.com/softwarewrighter/X_eTaL/tree/main/.agentrail/plan.md) | the saga’s plan, in prose: its goal and what was decided | \n| `steps/NNN-slug/prompt.md` | what the step was asked to do, written before it started | \n| `steps/NNN-slug/summary.md` | what was done, a few lines written when it finished | \n| `steps/NNN-slug/step.toml` | when it finished, the commits it made, or where it was done instead | \n\nSo the way to read a step is in that order: the prompt, then the summary, then a glance at the record for when and where. Step 110 of X_eTaL’s saga, the macro contracts, reads like this. Its prompt, the plan, begins:\n\n```\nThe user (2026-10-17, decided): three contract lines in a macro's doc block, checked by\nthe macro runner ... ## uses: copied (the default: every name and number token of each\nargument appears as a token in the expansion, else error[unused-argument] at the argument\nnaming the text ignored ...) and ## uses: parsed (the macro parses a notation and takes\nresponsibility ...). Test-first ...\n```\n\nIts summary, what was done:\n\n```\nMacro contracts (MC31, D163): xetal-contract crate (## takes:, ## uses: copied|parsed,\n## binds:) checked by the expander around each call; bad-macro-call before the macro runs,\nunused-argument after, bad-contract at load; every standard macro annotated; xetal doc\nshows takes/uses; spec + goldens; docs. ... Commit 57cff932 pushed.\n```\n\nAnd its record says when, and which commit holds the work:\n\n```\ncompleted_at = \"2026-10-17T16:51:51\"\ncommits = [\"57cff93220e03f551567200f8812d78a9f9b1b8a\"]\n```\n\nOn GitHub, the History button on the `.agentrail` folder lists the saga’s own commits, one per finished step, `chore: complete step 110 (macro contracts)`, and each commit in `commits` links to the code itself.\n\n### All of it at once\n\nIn a clone, `agentrail history` prints every step in order, its status, the first line of its prompt and its summary:\n\n```\n108-plain-names [production] (completed)\n  The user (2026-10-17), after a survey of names: rename what reads oddly or de...\n  Summary: Plain names (D161): s:r_ange -> s_pread, demos/sub.xtl -> dyadic.xtl, Macros t_h...\n\n109-spatial-pipeline-macro [production] (completed)\n  Saga 41 step 5b (docs/plan.md, docs/spatial.md Pipelines, D155): e:p_ipe< in ...\n  Summary: Handed to X_eTaL-ML (the user's choice: the pipeline macro lives beside the nn: ...\n\n110-macro-contracts [production] (completed)\n  The user (2026-10-17, decided): three contract lines in a macro's doc block, ...\n  Summary: Macro contracts (MC31, D163): xetal-contract crate (## takes:, ## uses: copied|p...\n```\n\nIt does not print dates. For a diary of what was done when, a few lines of shell put each finished step’s date beside its summary:\n\n```\nfor d in .agentrail/steps/*/; do\n  t=$(sed -n 's/^completed_at = \"\\(.*\\)\"/\\1/p' \"$d/step.toml\")\n  [ -n \"$t\" ] && [ -f \"$d/summary.md\" ] &&\n    printf '%s  %s  %s\\n' \"${t%T*}\" \"$(basename \"$d\")\" \"$(head -c 70 \"$d/summary.md\")\"\ndone | sort\n```\n\nThe last three days of X_eTaL, from that:\n\n```\n2026-10-16  100-raw-strings       Raw strings (ST4, D156): lexer r\"...\" and r#\"...\"# (verbatim, mult\n2026-10-16  106-boxed-macro-text  Boxed broke every macro (expansions captured through the boxed pr\n2026-10-17  107-expand-layout     xetal expand and Expand lay a macro's text out as a program past 8\n2026-10-17  110-macro-contracts   Macro contracts (MC31, D163): xetal-contract crate (## takes:, ##\n2026-10-18  101-spatial-oracle    Done in X_eTaL-libraries as its Saga 12 step 2 (equations-oracle):\n2026-10-18  115-shape-lint        The shape lint (shape-mismatch, shape-check-proven, r_equireShape)\n2026-10-18  126-errors-located    Saga 27 step 1 done in the readable lane (lanes/readable/.agentrai\n```\n\nOne thing to read carefully. A step closed out of order carries the date it was recorded, not the date the work was done: step 101 shows the 18th because that is when the record was corrected. Its summary says where the work is, and its record names the commit, `done_elsewhere = \"X_eTaL-libraries@8197d52 (Saga 12 step 2)\"`, whose own date is when the work happened.\n\n### The correction, told in words\n\nThe correction itself reads the same way. It was the first use of the new commands, a minute after the change merged, and its commit message is a plain account of what was set right and where each piece of work really is:\n\n```\nsaga: correct the record (steps done elsewhere closed, 111's prompt, 119 reserved)\n\nUsing agentrail's new close/edit/reserve (sw-vibe-coding/agentrail-rs\nPR #3), each with where the work is, no other step touched:\n\n- 101-104 (Saga 41 steps 2-5): done in X_eTaL-libraries as its Saga 12\n  (8197d52, 09143d8, cb430d5, ba03d6a); closed --elsewhere.\n- 114 integrals-plan: Saga 42 planned and decided (18c1501f, 6c0bf1c9).\n- 115 shape-lint: merged with PR #130 (dc359072).\n- 120 doc-comment-glyphs: c005fa16.\n- 123 errors-library-calls (ask E5) and 126-130 (Saga 27): done in the\n  readable lane, merged with PR #131 (80087dab).\n- 119 pages-gh-pages reserved for the local agent: the build moved to\n  gh-pages (b025b3d0); switching GitHub Pages' source remains.\n- 111 code-strings: prompt corrected to the decided design (c\"...\" and\n  c#\"...\"#; cr\"...\" was dropped) and docs/code-strings.md's order.\n\nagentrail status reports no stranded steps; the cursor stays at 111.\n```\n\nHalf an hour later the local agent switched the Pages setting and closed step 119, and its summary says what it did, in a sentence:\n\n```\nGitHub Pages' source switched from the main workflow to the gh-pages branch (gh api,\n2026-10-18 07:40) after the first just publish from main 723cd4eb; the site build moved\nthere in b025b3d0 (#128, D164).\n```\n\nReserved, done and closed, and each step of it written down in words someone else can read.\n\n## And the full transcripts\n\nThe record above is the summary. The whole conversation, every request, reply and command, is kept by the coding agent itself, not by agentrail, and since the work runs in parallel it is spread across machines. With Claude Code:\n\n- \n**On a Mac or Linux machine,** each session is a file under`~/.claude/projects/` , in a folder named after the repository’s path with its slashes turned into dashes. For X_eTaL on my Mac:\n\n```\n~/.claude/projects/-Users-mike-github-softwarewrighter-X-eTaL/d545dc14-38c5-4323-80b6-15b75c666593.jsonl\n```\n\n The Arch Linux machine keeps its own sessions the same way, in its own home folder. Each file holds one JSON object per line, and `jq` pulls out the readable part, the agent’s replies with their times:\n\n```\njq -r 'select(.type==\"assistant\") | .timestamp as $t\n       | .message.content[]? | select(.type==\"text\") | \"\\($t)  \\(.text)\"' SESSION.jsonl\n```\n\n From the X_eTaL session above, on the evening step 110 was being built: \n\n```\n2026-10-17T21:13:22.930Z  Libraries step 1 is done and published. Next in the chain: X_eTaL step 110 (macro contracts).\n**Step 110, macro contracts (in progress):** the `xetal-contract` crate is written and green (10 tests),\n```\n\n- \n**In Claude’s cloud,** a session runs on a virtual machine that is gone when it ends, so its transcript is not on any disk of mine; it is in the web interface, at claude.ai/code. A commit made there carries a trailer that links back to it, as the correction above does:\n\n```\nClaude-Session: https://claude.ai/code/session_01Etyh3Gka9iV2U9SJkNnmhm\n```\n\n That trailer is how a commit leads back to the conversation that made it. The screenshot beside this section is one such session, reporting on X_eTaL’s step 111 this morning: it lives only in the web interface, and no folder on my machines holds it.\n\nTranscripts are long, private and scattered; that is why the saga keeps the summary. The record in the repository says what was planned and done, the commits hold the code, and a transcript, wherever it lives, is there for the rare time the reasoning behind a step matters.\n\n## The rules behind it\n\n- **Make the agent say where.** The one thing a record of work must never do is invent where the work came from.`close` refuses to guess, so the record says “done in X_eTaL-libraries at 0f82f93”, not “done at whatever commit happened to be checked out”.\n- **Touch one step.** Every correction changes exactly the step it names. Completed steps still never renumber, and nothing rewrites a neighbor’s history.\n- **Prevent as well as repair.**`close` repairs,`reserve` prevents, and the stranded report finds what slipped through.\n- **Keep every existing saga working.** The two new fields,`reserved_for` and`done_elsewhere` , are optional and left out of the file when unset, so existing step files load and save back byte for byte, which a test checks. Older agentrail binaries ignore the fields.\n- **Teach the agents.** agentrail hands every project a shared set of agent instructions, and the recovery part now says: correct the record with commands, never by hand-editing or by reopening a neighbor, and reserve a step when you hand it off.\n\n## By the numbers\n\n- 3 new commands, 1 fix to the cursor, 1 new report, in one pull request of about 700 lines.\n- 11 new tests; the workspace’s 192 tests pass, with clippy and rustfmt clean.\n- Tried first on a copy of X_eTaL’s real 150-step saga: the report found the 4 stranded steps, and `close` changed only the step it named.\n\n## The lesson\n\nA workflow tool that keeps agents honest has to make it easy to be honest about work it did not see. Once several agents share a project, “done somewhere else” is a normal state, not an exception. The record needs a way to say so, and the tool should require the evidence.\n\n*Part 15 of the Sharpen the Saw Sundays series. [View all parts](https://blog.softwarewrighter.com/series/#sharpen-the-saw-sundays)*\n\n*Comments or questions? [SW Lab Discord](https://discord.com/invite/Ctzk5uHggZ) or [YouTube @SoftwareWrighter](https://www.youtube.com/@SoftwareWrighter).*", "url": "https://wpnews.pro/news/saw-15-agentrail-correcting-the-record", "canonical_source": "https://blog.softwarewrighter.com/2026/10/18/saw-agentrail-correcting-the-record/", "published_at": "2026-10-18 07:15:00+00:00", "updated_at": "2026-10-18 16:19:34.957725+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["agentrail", "agentrail-rs", "X_eTaL", "X_eTaL-libraries", "sw-vibe-coding"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/saw-15-agentrail-correcting-the-record", "markdown": "https://wpnews.pro/news/saw-15-agentrail-correcting-the-record.md", "text": "https://wpnews.pro/news/saw-15-agentrail-correcting-the-record.txt", "jsonld": "https://wpnews.pro/news/saw-15-agentrail-correcting-the-record.jsonld"}}