Repository navigation
Agentry 0.3.0
Agentry 0.3 turns the plugin into a harness for a repo's own board. /agentry:exec builds a task whose
contract is already written, in its own git worktree. A second agent checks the work against the acceptance,
and /agentry:merge lands it only past your repo's gate. Each step is recorded in a ledger, so a cold session
can resume. /agentry:init learns the board you have or scaffolds one, and /agentry:start and
/agentry:close open and end a session the same way each time. The agentry command (board, lane, mem,
draft, run, lock) does the mechanical work; the plugin starts no server and ships no hooks. Memory is
now agentry mem, over the same files as before. The Workbench and the flow server are gone.
Upgrading from 0.2
Restart Claude Code after updating. The commands, agents and skills register on a restart, and a session
started before the update still holds the old servers.
- Memory is
agentry mem; the memory server is gone. Agents, commands and skills runagentry mem <verb>
in Bash (agentry mem --help) instead of themcp__plugin_agentry_mem__*tools. Replace any of those
names in your own prompts orCLAUDE.md. Existing stores read unchanged: the same Markdown files, roots
and environment variables (AGENTRY_GLOBAL_DIR,CLAUDE_PROJECT_DIR,AGENTRY_PROJECT_DIR). agentryis on the Bash tool's PATH while the plugin is enabled. Where it is not, run
node "${CLAUDE_PLUGIN_ROOT}/scripts/mem.mjs"(orboard.mjs,lane.mjs) with the same arguments.lane exec closewrites the lane's episode. It writes the episode to the memory store and stamps its id
in one call; pass the run's--lesson "<text>"and--used-memories <ids>to it. Writing the episode
yourself and passing--episode <id>still works, deprecated, for one version.- No hooks, so nothing primes memory at session start.
/agentry:startprints the ranked memories and
/agentry:goand/agentry:askbegin withagentry mem recall. The newmemory.primesets whatstartand
theexecbriefs carry. - The Workbench and the flow server are removed.
/agentry:workbenchis gone./agentry:go,spec,
plan,splitandfixwrite the spec, plan and task files as plain files under.agentry/work/<run>/,
and review and approval happen in the chat. /agentry:gowith no task asks what to work on. It no longer claims queued work.- The board commands need a board.
/agentry:exec,merge,newandboardread the repo's
.agentry/process.jsonand.agentry/workflow.json. Run/agentry:initonce to learn the board you have
or scaffold one. Every 0.2 command keeps its name,/agentry:workbenchapart. - Memory files land in your repo. Repo memory and each lane's episode now live in
<repo>/.agentry/memory/
in the main checkout, and show up untracked after the firstlane exec close. Commit them to share them
with your team, or add them to.gitignore. - The repo moved to
silentthreadstudio/agentry. GitHub redirects the old path. The marketplace name is
stillagentry-dev. .agentry/config.jsonhas new keys and is read strictly by the lane scripts. See/agentry:config.
A key outsideworkDir,mode,evolution,memory,mergeandlanesstops the step with an error that
names it.
Node 24 or newer is still required.
Added
/agentry:config— shows the effective.agentry/config.json(key, value, default, what it does) and
sets one key withkey=value, validated and merged, never clobbering the others. The keys areworkDir,
mode,evolution,memory.prime,memory.primeLimit,memory.captureCorrections,merge.push(ask,
auto,never;askby default) andlanes.maxWriters(3 by default). The lane scripts read the file
strictly: an unknown top-level key, or a bad value insidemergeorlanes, stops the step with an error
naming it.- The
agentry:conductoragent — the main-session agent for a repo that sets"agent": "agentry:conductor"in.claude/settings.json. It starts the session with/agentry:start, sends board
ids through/agentry:exec, landings through/agentry:merge, questions through/agentry:askand the
wrap-up through/agentry:close, drafts the owner's calls, and does small work itself./agentry:init
offers to set it as the default. lane merge <id> --resolve landedcloses a lane whose work is already on main — a verified lane (or one
stopped on a red gate after a passing verdict) whose commits reached main another way, through a
fast-forward of a combined branch or a squash, can now be closed. It readsgit cherryover the lane's own
commits: with every one on main by patch the ledger is merged (merge.how: "found-on-main",merge.landed
the matching main commits) with nothing picked, no commit made and the board left to the owner. A commit
with no matching patch refuses the close, named with its short SHA and subject, until the owner passes
--checkedafter checking it landed squashed or reworded; that answer is kept inresolutions[]. A stacked
parent closed this way counts as merged for its children,--cleanuptakes the worktree and branch down as
after a land, andboard statusstops nudging the lane as verified but not merged. A stuck land's
--resolve landed|rolled-backis unchanged.lane exec cut <id> --decision <D> [--keep <paths>] [--message "<subject>"] [--apply]— retires a lane
on the owner's call, recorded as a decision the board holds. It previews by default and writes nothing. With
--apply, the--keepfiles and folders land on main from the lane's tip as one commit, through the land's
own steps and the merge role's gate tier (rolled back on red, the lane as it was); the board'scutstatus
(the newlifecycle.on.cut,exec.kinds.<kind>.on.cutfor a debt kind) goes in one board commit, so main
is clean for the next land. The lane is closed, its uncommitted work saved, its worktree removed and its
branch kept asagentry/<id>.cut; the episode is printed andexec close <id>writes it. Without--keepnothing of
the branch lands. A cut killed mid-land is rolled back by the nextexec cut <id> --decision <D> --apply,
only over its own commits and writes; one killed after its board commit refuses and is finished by hand.
An agent out, a decision the board does not hold, a--keeppath the
branch does not change, an unseton.cutand a lane mid-land or merged are refused, with nothing written.lane exec adopt <id> --branch <b>— work built outside exec (an agent's worktree, a hand branch)
becomes the lane:start's checks and board write, a freshagentry/<id>cut from main,main..<b>'s own
commits picked onto it (its merge commits left out and named in the brief) and the uncommitted diff of
<b>'s worktree applied, asrestart --carrydoes.<b>and its worktree are only read, andcleanup:
prints how to remove them once the lane has landed. The first brief lists the adopted commits; commits
outside the contract's owns are a warning with thelane exec owns <id> --add <paths> --applyline. A
conflict leaves the lane building with the conflict in its worktree for the builder; any other error in
the carry takes the new lane down again and names what it could not remove.<b>must be a branch's own
name exactly as git lists it: a revision (<b>~0), another case of a name, a branch with a case twin, the
main branch and a branch a ledger tracks are refused, with nothing written.lane spikeand ways on for unlisted worktrees —agentry lane spike <branch|path> --for <id>files an
agent worktree no ledger knows as work meant for that item,--keep "<why>"keeps it on purpose (shown as
kept, never drift) and--forgetdrops it; with no flag it lists them, a branch gone since markedgone.
The list is local run state (.agentry/run/spikes.json), written at once. Drift now offers an unlisted
agent worktree its ways on, each with its command: land (lane merge <id> --branch <b>), continue (lane exec adopt <id> --branch <b>), file (lane spike) or remove (git worktree remove), never
/agentry:exec. One on a branch they all refuse (a case twin, a branch with no commits yet, a spelling no
branch is named) is offered only remove, with why; an orphanagentry/<id>worktree is offered no continue,
since it is the branch that lane would cut. A spike filed for an item is onespike-for <id>row until a lane takes its branch, an
adopted branch is no drift, and an unreadablespikes.jsonis aspikes-unreadablerow.lane note—agentry lane note <id> --owner "<call>"records a call the owner made on a lane, or on
the spike filed for the item, one line each; with no flag it lists them, and--recorded <n,n|all> --where "<file or section>"marks them written down.exec adoptmoves a spike's calls into the lane and
restartkeeps them; a spike holding calls not written down refuses--forgetand a re-file that changes
its item.exec close's episode counts them, andlane session closelists the ones not written down
(calls,callLines), merged lanes included, until they are marked;/agentry:closewrites them where
the repo keeps decisions and marks them.board next-id <kind> --family <prefix>— the next free id among every board id in that prefix family,
whatever kind holds it (ART-19afterART-18,<prefix>-1when there is none), so a kind whose ids are
chosen by hand no longer takes one another kind already uses. A family ending in a digit needs a separator
(R1does not readR19). The chosen-by-hand refusal names it, and/agentry:newproposes it when the
owner names a prefix.board commits --learn [--min <n>]— reads the last 500 first-parent commits of the default branch and
prints thecommitsrules they keep:subjectPatternwith the Conventional Commits types and each other
type used at least--mintimes (default 3),subjectMax, and whether every subject has a scope. It writes
nothing, and with no history it says why and prints the standard set./agentry:initproposes its rules
instead of a pattern written from the spec alone.- Commit rules in the land and the rebase — when a commit's subject fails
commits.subjectPatternon a
type main already uses, thecommitsrow oflane mergesays how often main uses it and prints the
pattern widened to take it.lane exec rebaselists each commit the land would refuse under## Reword
in the rebase brief (reword <sha> "<subject>": <why>), the one rewording that brief allows. A branch
whose merge commit brings in another open lane's branch names that lane: land it first (nextis its
land), thenlane exec rebase. - Model and agent from the contract and its steps — a step ending
(model: <m>, agent: <designer|implementer>)names its run's builder model and agent, ahead of the contract's- **Model:**
bullet and the new- **Agent:** <designer|implementer>bullet, which win overmodels.buildand the owned
paths. Themodel:anddispatch:lines name the source (opus (step 1),"from": "contract"); an
unmarked dispatch prints as before. Steps of one run that name two models or agents are a steps problem.
exec starthints when the contract's prose names a model that no bullet or marker sets. - The note's age and idle lanes asked once —
lane session startlabels the note with its age once it is
12 h old (note (3d old): …) and calls it stale when the Now it was first read under has moved on (note: stale, written 3d ago when the Now was S1, now S2 → rewrite or clear .agentry/NOTE.md);/agentry:close
then asks the owner to rewrite or clear it. An idle lane is put to the owner once per quiet spell (ask the owner once: park T6?), and later starts print one quietidle: T6 (asked 12:05; …)line until its last
change moves; a lane counts as asked only when the question fits in the 40 lines. Both records are local
(.agentry/run/note-seen.json,idle-asked.json). In--json, the note carrieswrittenAt,now,old
andstaleas{ why: "now-changed" | "ids-done", … }, and eachidle[]laneasked. agentry runand named locks —agentry run --limit <dur> [--lock <name>] [--wait <dur>] -- <cmd>
runs a command (no shell) in its own process group and stops the whole group at the limit (SIGTERM, then
SIGKILL 5 s later; exit 124), since macOS ships notimeout.locksinworkflow.json({ "editor": 1 })
declares locks shared by every worktree:--lockwaits for a slot and holds it while the command's group
lives (exit 75 when it stays busy for--wait, 10 minutes by default).agentry lock take <name>/
drop <name>hold one across tool calls, for a shared editor driven through MCP, until--ttl(30 minutes)
or the session ends;lock showlists the holders andlock drop --orphanfrees a slot only a leftover
process group holds. A command that is agate.tiersargv takes the gate slot the same way. Build and verify
briefs nameagentry run --limitin their time-limit rule, and the lock to take whenlocksis declared.lane merge <id> --resolve landed|rolled-back— closes a land left inmergingthat cannot go on, on
the owner's call, after checking main.landedneeds every recorded pick on main: the ledger is merged and
the board's done row and handoff line are the owner's; any lane stacked on it is named with its
restack --mainstep.rolled-backneeds no pick on main (found by sha, by author, date and message, or by
patch; a reverted pick still counts as on main): the lane is verified again. Both refuse while git is
mid-pick, while the ledger still holds what the land set aside, or when git cannot tell, and touch neither
main nor the board.lane exec startrefuses while a land's picks are on main (a red gate may still take
them off) and names it.lane exec restart <id> [--carry]— a lane that is not merged and has no agent out is archived as
<id>.<n>(its branch kept asagentry/<id>.<n>unless--carrytook all of it) and started again from
main, the old verdict cleared on the board (a verified lane's clean carry keeps it; see Changed). With
--carryits commits and uncommitted diff come along, and the new brief names what was carried and the old
report; a conflict is left in the new worktree for the builder (exit 1). Every refusal (a builder out, a
gate queued, a lane stacked on it, ignored files in the worktree) comes before anything is written. A
stopped lane'sshownames it and the other way on,lane merge <id> --branch agentry/<id>.--carry
brings only the branch's commits that are not on main (merges left out, patches main already has skipped),
so a lane rebased in-branch onto a newer main does not re-apply main's own commits, and it refuses, before
writing anything, a branch whose merge base is not on main's first-parent line. It also keeps the lane's
owner OKs andowns --addgrants, carries a summary of the old rounds and briefs the step the lane stopped
in rather than step 1.- Parking a verified lane and sending it back —
lane exec hold <id> --for lateralso parks a lane that
is verified (merge refuses it while held;resumemakes it verified again), andlane exec fix <id> --owner "<the change>"sends a verified lane back for one builder round on the owner's words, then to the usual
recheck, which judges the change as one more note. The episode counts the owner's fixes.lane session start
prints a parked lane's note, its evidence and the step that resumes it; a park on a lane whose main was
touched is recorded and saysmain moved while parked. - Holds instead of stops — a builder report that finds main touched holds the lane for the guard (its
report saved) instead of stopping it: fix main, thenlane exec report <id>again goes on as the first
would have, andlane session startshows the hold with its reason and that step. A secondNEEDS_CONTEXT
in the same step holds the lane for the owner's fact:lane exec resume <id> --note "<the fact>", or
lane exec owns <id> --add <paths> --applyfor the files the report names outside the contract (the held
line prints it), orrestart --carry. A flagged item whose verdict leaves notes open at the notes cap holds
for the owner:resumecloses it as is,fix --ownersends it back. The cap is read live from the
workflow file, so a raisedexec.noteRoundslets one more notes round go. - Decision drafts take a why — a draft may carry a
why, andboard draft apply <n> --answer "…" --why "…"writes the owner's correction and keeps it on the draft's line with the text it replaced. The
drafts.decision.mapplaceholders are{answer},{why}(the draft's question when it has no why),
{question}and{unpicked}; with nodrafts.decisionin the workflow file,applyfills the decision
kind's owndecision,whyandrejectedfields and says so. lane sweepfrees what killed processes left — temp files whose writer is gone
(<file>.agentry-<pid>.tmp, and the older temp names in the ledger, drafts and gate-locks folders), gate and
lock slots whose holder and riders are gone (each group a run left running is stopped first), and write locks
whose owner is gone;--jsonlists them astemps,slotsandwriteLocks. The preview lists them and
removes nothing, and each is judged again at--apply.lane session startcounts them in a
! stale: <n> lock slot(s), <n> temp file(s) → agentry lane sweep --applyrow, and itslanes:line lists
open lanes only, then· <n> merged today.- The running build in
--version—agentry --versionand the footer of every--helpprint what the
checkout is past its version bump and the short HEAD,0.3.0+141 (22abc92), withdirtywhen the plugin
tree has uncommitted changes, so a session started before a change can tell;(version unknown)when
plugin.jsoncannot be read. - Stacked lanes —
lane exec start <id> --on <parent>cuts a lane from another lane that is verified,
held or at its gate (a chain too), so serial work no longer waits for a land; itsbaseis the parent's
tip, so the briefs, the commit count and the gate tier read only its own commits. Each step prints
stack:with what is due when the parent moves, lands or stops, andexec gaterefuses until
lane exec restack <id> [--main]rebases the branch onto the parent's new tip or main: only with no agent
out, never on a dirty worktree or under the lane's gate, with the repo's rebase stash, squash and
ref-update config off; a conflict is aborted with the branch and ledger as they were. A clean restack gets
the gate on the new tip; one resolved by hand gets the resolution recheck.lane mergelands a stacked
lane only after its parent and its restack onto main; the parent's land restacks each child at rest
itself and names the ones it left.exec show,lane session startand the episode name the stack. - Session checks from the repo's own session skill —
extensionstakesstartandclosebeside
merge, each{ "checks": [<skill>, …] }(one skill may be named in both;extensions: {}is refused).
/agentry:startand/agentry:closerun each named skill (its## Start/## Closesection, or the
whole skill) and record the outcome withlane session <start|close> --check <skill>=pass|fail [--note <t>], appended to.agentry/run/process/session-checks.jsonl(local, never committed).
lane session startlists the checks to run and how the last close's went; start and close--jsoncarry
checks; the handoff names each failed or pending close check.board explainshows the
extensions.start.checksandextensions.close.checksrows./agentry:initoffers to absorb a session
skill the way it absorbs the merge skill, showing its shrunk text.board instructions-lintis no longer a
subcommand of its own;board instructions --lintis unchanged. - Competing-line lint and a local trigger block —
board instructions --lintreadsAGENTS.md,
CLAUDE.md,.claude/CLAUDE.md,CLAUDE.local.mdand the conductor prompt and points at lines that
compete with the Agentry block (every task through/agentry:go, a session routine, landing by hand, the
gate run by hand), each with the replacement to offer; it only suggests and never writes (exit 1 with
findings).board instructions --target localputs the block inCLAUDE.local.mdinstead ofAGENTS.md,
for a repo that is public: no import is added, a block already in the other file moves (removed there and
written here in one all-or-nothing write), and a note says when git tracks or does not ignore the file.
A block in both files is refused.board explainreads the trigger block from either file./agentry:init
asks where the block should live and offers each lint replacement one at a time. - Workflow presets for the exec lane —
exec.preset(lean,standardby default,strict) sets
exec.verify,exec.noteRounds(0 / 1 / 3 notes-fix rounds),exec.final(never,after-fix,
always),exec.rebase(gate,recheck) and thegate.rolesdefaults; a key in the file wins, the
roles per role.board explainshows each resolved value with its source (presetorset), an
exec.verifyand amodelsrow, and·for an absent optional key;exec startandshowprint the
workflow:line. The ledger fixes the route at start, so an edit mid-lane changes no running lane, except
noteRounds, which each step reads live from the workflow file. Underfinal: after-fixa recheck that
passes every note sent back (N1: PASS …lines) on a tip moved only by fix commits closes with no final
verifier. Notes past the budget are kept asopenNotesin the ledger,showand the episode. With no
execkeys a lane runs thestandardpreset: one notes-fix round, and no final verifier after a recheck
that covered every note on a fix-only tip. Setexec.preset: "strict"(ornoteRounds,final) for three
rounds and an always-fresh final. - Rebase and the resolution recheck — a land conflict on an exec lane names
lane exec rebase <id>:
the builder rebases onto main, the range-diff goes tologs/range-diff-<n>.txt, and a fresh verifier
checks only its changed pairs (exec.rebase: "recheck") before the gate on the new tip. A land on a
branch moved past the tip its lane closed on is refused with the same pointer.lane exec reverify <id>
sends a verifier to a lane the route closed without one, and a flagged one's merge names it. exec.flagFieldandexec.idleMinutes— the field the verify route reads (defaultflag, checked
on every kind exec runs) and the idle threshold (whole minutes ≥ 5, default 20).- Steps and the owner's holds in a lane — a contract may carry a
**Steps:**part: numbered steps, an
owner gate on any step ending→ owner OK, and acceptance items taggedStep N:.lane execbuilds the
steps in runs (one round up to each owner gate), holds the lane for the owner's review at a gate, and sends
one fresh verifier over the whole contract after the last step, with the owner's approvals in its brief.
lane exec hold <id> --for ownerholds a round whose reply is saved;--for laterparks a lane whose
builder was stopped, its worktree kept, and--agentnames the builder the resume goes back to.lane exec resume <id> --note "<the OK>"records the answer and resumes the builder (--redobuilds the run again,
--freshsends a new builder). A held lane is no writer, writes no board cell and is refused by merge and
close;lane session startlists it first.exec showandlane session startflag a building lane with
no change for 20 minutes as idle. Build and verify briefs cap every command but the gate at 10 minutes. An
item ending→ owner OKis a gate, and so are-> owner OK,— owner OK,– owner OKand**owner OK**;
a trailing(note)is kept as the gate's note. An item that mentions an owner gate (OK,okay,review,
approve,approval,sign-off,gate, also inflected) without ending that way is a steps problem naming
the spelling to write, andstartrefuses it rather than merging the steps into one run. - Search-ready website — icons from the tape mark (
favicon.ico, 192/512 and maskable PNGs, the
Apple icon, a web manifest,theme-color; icon URLs carry a version),robots.txt,
sitemap-index.xml,llms.txtandllms-full.txtbuilt from the docs pages, JSON-LD
(SoftwareApplicationandWebSiteon the home page,BreadcrumbListon docs pages), a canonical,
og:urlandog:localeon every page except the 404, meta descriptions of at most 160
characters, and avercel.jsonwith cache rules and safe headers. - Fewer round trips in a lane —
exec.verifyin the process file (allby default,flagged,
none) sends an item whoseflagfield is not set from built straight to the gate; a flagged item
keeps its independent verifier and a flagged item with no verdict does not land.flaggedneeds a
flagfield on the lifecycle kind and is refused at load without it. The route shows inexec start
andshow, and the episode records it.modelsnames the model each dispatch prints (model:):
build, andverify.default,verify.ui,verify.flagged. Each is a name or{ "default": …, "paths": [{ "when": { "any": [<globs>] }, "model": … }] }, the first entry matching an owned file winning, and a
contract line- **Model:** <model>(- **Model (verify):** <model>for the verifier) beats both; the
model:line names where it came from, e.g.opus (models.build.paths[0]: src/main/**).board explain
andexec startwarn! models.verify.ui is unusedwhen the route never sends a UI task to a verifier. A
verify, recheck or final brief on a tip whose gate is already recorded green says to read that gate, not
to re-run it (exec gaterewrites the waiting verify brief).lane mergeno longer stops on the owner's uncommittedguard.allowfiles: it
sets them aside, recorded in the ledger first, lands, and puts them back; a stop or a rerun after a kill
puts them back too, and an edit that no longer applies is saved to a patch file. - Board and briefs —
board lifecycle/lane mergewrite several commits into the Commit cell
with the separator the board's done rows already use (a field'sjoinpins it;first…lastwhen
nothing is learned). An old--json '{…}'onboard add/board setexits 2 with a pointer to
the new form, and every--helpends with the plugin version.board explainlists
worktrees.keep,guard.allow,cleanup.disposable,gate.flakyandgate.concurrencywhen set,
with what they match.lane session startflags.agentry/NOTE.mdstale when every id it names
is done. An exec brief also quotes decisions whose row names the task, andexec start --cite
adds decisions by id.exec owns --applykeeps a section appended after the brief's last section. - Owned files read from a contract — a path that is the tail of exactly one tracked file
resolves to it (merge/gating.mjs), several are listed as ambiguous, none is new; brace globs
(commands/{go,spec}.md) expand, and a glob or folder resolves by its folders.a.b.csymbols are
not paths unless a tracked file matches, andMakefile,Dockerfile,LICENSEand tracked
extensionless files are..astrofiles and globs underweb,apporuisuggest the designer.
exec startwarns, without refusing, when its owned files overlap a running lane's:
! owns overlap with T-4: plugin/commands/go.md. A path that leaves the repository is dropped with
! owns names a path outside the repository, a bare extension after+,,orand(`src/a.ts` + `.test.ts`) owns the sibling file, a path the clause says is out of scope (stops, needs context, never,
ask first) is not owned, and! owns names tests but no test filesays when no owned path is one. agentrycommand — the plugin'sbin/agentryis on the Bash tool's PATH while the plugin is
enabled:agentry board …,agentry lane …,agentry draft …,--version,--help. Next
steps the CLIs print name it when it is this plugin's bin, and the docs use it; hosts without it
keepnode "${CLAUDE_PLUGIN_ROOT}/scripts/board.mjs"./agentry:initsuggests the rule
Bash(agentry:*).lane exec fix <id> --notes N1,N3— a verified lane (PASS WITH NOTES) goes back to its builder on the
notes the conductor names, then to the usual recheck. Verifiers label their notesN1,N2, and so on. It
takes the notes a lane kept open as well as the latest verifier's.- Gate queue, flaky re-run and the queued gate's log —
gate.concurrency(default 1) makes lanes queue
their gates behind a lock in.agentry/run/, with stale-process recovery, so timing tests stop failing
under load.gate.flakynames tests that may fail under load: a red whose log fails only in them is re-run
alone once, and both runs are recorded.lane mergeappliesgate.flakyasexec gatedoes: a red only in
listed tests is re-run alone once and both runs are recorded; a re-run that fails again stops without
sending the builder back.gate.flakyLogs(globs from the gate's cwd or$TMPDIR/, files newer than the
run) are read when the gate's own output prints only a summary: a line there counts only if it names a
failing test (FAILED TEST: <name>,not ok N - <name>,✗ <name>,FAIL <name>); noise is ignored and a
red that names no test stays real. A queued gate writeswaiting for gate slot N (held by … since HH:MM)
andslot acquiredto its log, andlane session startlists held slots. gatesin the exec output —gateandverdictprint "1 green, 1 red on this tip", so a
green run no longer hides a later red on the same commit./agentry:exec <task-id>— builds a task whose contract is already written. It finds the
contract in the repo's task files, briefs the implementer (or the designer for UI work) in a
worktree, has an independent verifier check the acceptance, allows one fix round, and hands off
the worktree, commits and verdict. No spec, plan or split, no Flow run state, no merge or push./agentry:ask <question>— answers with one read-only specialist (explorer, researcher or
architect) and cited sources. No worktree, no Flow run state, no edits./agentry:init— the setup front door for a repo's own process. In a new repo it scaffolds
a board from templates; in a repo with a board it learns how that board is written into
.agentry/process.json, checked against the files at every step; in a repo already set up it
shows the setup and offers repairs for drift. Asks only what it can't infer, never commits./agentry:new <kind>— adds one item of any kind the process file knows (task, sprint,
question, decision…) to every place that kind lives, asking only that kind's fields, then
reports what changed in the board check./agentry:board— the board's derived status, then every rule finding, from the repo's own
files.--fixfills mechanical drift once the harness writers ship.processskill — the process file format, the learn procedure and fresh-repo templates./agentry:merge <task-id>— lands one task on main: preflight, the repo's checks,
cherry-pick, the gate, then the board's done row, SHA and handoff line in one commit. It writes
its plan to the task's ledger before acting, so a killed merge can be rerun without losing the
board writes it carries or picking twice, and it rolls back withreset --keep. Pushes only
per the repo's push policy./agentry:startand/agentry:close— open and close a working session.startprints
the current sprint, work in flight, nudges, drafts and ranked memory in a few lines.close
applies drafts, runsboard fix, offers a sweep, writes pending episodes and a short note.lane sweep— reports, and with--applyremoves, the worktrees of merged lanes and stops stray
processes started under.agentry/run/. Unknown, live or dirty worktrees, and worktrees holding ignored
files, are kept. It stops only what it can prove is a stray's, never an interactive shell or a live lane's
process.modeconfig key — read bystart.board status --ready— open tasks per sprint, with whether each has a contract and
whether its dependencies are done.board status --why <id>says what an item is blocked by.- Process file keys:
worktrees.keep(worktrees kept on purpose are shown as kept, not
drift),status(a hand-written status file whose "next" section is checked against the
board), and amentionsfield type sorefs-resolvechecks ids cited in text. ready-has-contractrule — an open task in an active sprint must have a contract that
board contractfinds.- A fresh builder for each step, and
resume --same— theresumethat approves a step of a multi-step
lane dispatches the next step's first round to a fresh builder, its brief naming the last report and its
model and agent following that step's(model:, agent:)marker.--samekeeps the old builder instead. A
--redo, a fix, a needs-context round and the carry-on of a hold during a round still resume the builder
they belong to, and a one-step lane builds as before. The brief that answers a context hold now names the
step the round is on and says it is done only when its own work is. BLOCKED: external: <reason>holds the lane — a builder whose report starts with that line, for a cause
the owner can clear (a key not issued, a service down), holds the lane (held: blocked: <reason>) instead
of stopping it: no verdict is spent and the step does not move.exec resume <id> --note "<what changed>"
sends the round it stopped on again, as it was dispatched (a fix still points at the verifier's report), to
a fresh builder unless--same. A plainBLOCKEDstill stops the lane.exec holdon a blocked lane is
refused, and so isfix --owneron any held lane, naming the resume that carries the change.- Import-direction check —
scripts/check-plugin.mjsfails when a module underplugin/scripts/lib/process/
imports one underlib/lane/(static, re-export and dynamic imports). The process kit no longer depends on the
lane: the leaves it needed moved toprocess/or to neutrallib/modules (lib/id.mjs,lib/text/shell.mjs). - SHA-256 repositories — commit cells, evidence and handoff lines accept 7 to 64 hex digits, so a board in a
SHA-256 repo reads its full commit ids.
Changed
- Comments stand on their own — code comments no longer cite internal design documents or task ids; the
plugin check fails on such a citation in a comment underplugin/,packages/orscripts/. - Memory is the
agentry memCLI; the memory MCP server is gone — every agent, command and skill now runs
agentry mem <verb>in Bash (recall,write,search,feedback,episode,stats,distill,
consolidate,update,forget,recover,resync;agentry mem --help) instead of calling
mcp__plugin_agentry_mem__*tools. The plugin starts no MCP server, and its 1 MB bundle (plugin/mem/) and
packages/memoryare removed. Existing stores read unchanged: the same Markdown files, roots and env
(AGENTRY_GLOBAL_DIR,CLAUDE_PROJECT_DIR,AGENTRY_PROJECT_DIR); with no project dir in the env, the
project store is the main checkout's of the current git repo, from any of its worktrees.lane exec close
writes the lane's episode to that store and stamps its id in one call, with the run's--lesson "<text>"and
--used-memories <ids>when given;--episode <id>still stamps an id
written elsewhere, deprecated, for one version.check-pluginfails on a leftovermcp__plugin_agentry_mem__
name in the payload, and its dist-lockstep check is gone with the bundle. - A verified lane's restart —
lane exec restart <id> --carryof a lane whose last verdict passed, on the
tip it settled on and with no uncommitted work, that carries cleanly goes on as a rebase does instead of
briefing a build round for work already done: underexec.rebase: "recheck"a changed carry goes to a fresh
verifier reading the range-diff, any other carry to the gate on the new tip (or the close). The board's
verdict is kept,builtis written, and the old lane's verdicts open the new ledger, so a flagged item
lands with no second verifier; they do not count toward the three-verdict stop. A conflict, aFAIL, no
verdict or work after the verdict keeps the build round. A restart that stops after the archive clears the
old verdict on the board, or names theboard setcall that does. - Inline steps are a steps problem —
- **Steps:** 1. Build it 2. Ship itis never parsed:exec start
refuses it, and the message ends with a one-step-per-line rewrite to check before pasting.board check
reports any Steps problem as aready-has-contractfinding (contract <id>: …), so it shows before
startdoes. - Land and resume — a
board setorboard add --applymade on main is carried into the board commit
(it was put back uncommitted after it, so a verdict the board check needed, a flagged task's PASS, stopped
the land); one the check refuses stops the land and goes back on main as it was. Once the gate has passed, a
rerun accepts the owner's commit of a board fix (board files and.agentry/*.jsononly) and puts the board
commit on top; any other commit after the picks still stops it. - Lifecycle writes check the board — a lane's
dispatched,builtorfailedstatus write that would
add a finding the board did not have is skipped, with the rule and its message. - Gate commands die with their holder —
lane exec gateandlane mergerun the gate under a watchdog
that stops its process group within about a second once the process holding the slot is gone (akill -9
included) and frees the slot, so a second gate never starts beside a leftover. Agentry's git calls are
bounded too (120 s, orAGENTRY_GIT_TIMEOUT_MS), so a stuck one cannot hold the gate, and a timed-out git's
helpers go with it. - Lane guards — an uncommitted edit of
.agentry/process.jsonorworkflow.jsonthat changes the
guardorgatekey trips the main guard (commit it between lanes); a lane held for the owner after a
step can no longer be parked; a hold's evidence must be a file; a commit list git cannot read at a
report is a read failure to check, never a subject to reword; the land and the lane read the newest gate
record of the tier they need, and a recorded green is trusted only for the tier's current argv; the
idle line says(the last commit)when that is the newest change. - Gate tiers, a gate per role, a manual checklist —
gate.commandandgate.quickare replaced by
gate.tiers: named tiers in precedence order, each an argv, every one but the last with awhen
(onlyglobs,anyglobs,flag: true; any one holding is enough), the last the fallback. An old
workflow file is refused at load with where each key goes now (the command becomes the last tier, a
quick tier a tier withwhen.onlybefore it).gate.rolessays which tierbuild,verifyand
mergerun (pick,fullor a tier name;verifyalsonone, the default, so a verifier runs no
gate andlane exec gatewhile one is out exits 2). Gate records carry theirroleandcommand; the
land skips only on a green worktree record of the tier and argv it needs, so a record from before tiers
never skips.gate.checklistitems are manual checks the land waits on when theirwhenholds,
recorded withlane merge --check <name>=pass|faillike a skill check.gate.flakynames are also
read fromFAILED <name>, a<path>::<test>token and JSON test events, and a listed name counts only
whole.board explainshowsgate.tiers,gate.rolesandgate.checklist;/agentry:init
proposes tiers. - Commits on main during a lane — a commit that touches none of the lane's owned files and none of the
files its worktree changed no longer stops the lane, whoever made it, and neither does one touching only
guard.allowpaths that no running lane owns (the report saysmain moved by allowed commits: <n> (<shas>)); a commit that overlaps names it:<sha> touches <paths>, this lane's files. A lane rebased by
its builder starts its guard at the commit it sits on, so main's commits under the branch are not judged
again. The process file, its workflow file and.agentry/config.jsonin use count asguard.allowpaths
unless a running lane owns them, as does every board location the process file names. A red gate after a
green one on the same tip now saysthe latest is red, and the waiting verify brief carries the full gate
line again. A ledger with no parsed owned list reads its contract against its worktree, asstartdoes. /agentry:execnow drives the build and verify rounds throughlane exec, records the
gate, and stops a lane whose builder edited main outside its own board cells.board fixwritesdoneonly from alane mergerecord whose commits are still on main.
A hand merge is a nudge toboard fix --accept <id>, which the owner confirms./agentry:go,/agentry:askrecall memory first; the newmemory.primesets whatstartand
execbriefs carry.- One convention for
boardandlane. Every subcommand has--help(usage, purpose, args,
flags, exit codes, an example) and takes--json. A command that writes previews by default and
writes only with--apply:board fix --dry-runand--writeoninstructionsand
default-agentare gone, and/agentry:board fixpreviews beforefix --apply. Item fields go
in--fields(board add,board draft add). Exit codes mean the same everywhere (0 ok, 1
findings or stopped, 2 refused, usage or bad config), errors are one✗ what: why → nextline,
and ids are read in any case and in their cited form (D7). extensions.merge.checks: []is accepted and names no repo check.board contractfinds a task's real contract on a lived-in board: shared blocks under
every id they lead, contracts written as table rows, contracts in a file the task's row links,
and a later one-line amendment no longer wins over the titled contract. Ids are read in any
case./agentry:execbriefs carry those later notes after the contract.board addfills a pattern id itself;explainandcheckrefuse a conductor prompt or
rules heading that doesn't exist, andexplainlists which lanes are set up.board fixproves work is still on main by line history and file mode, not a text match,
and asks git a fixed number of times per run.lane mergeputs a carried board write back cell by cell, and a rerun after a kill acts
only on what it can prove it wrote.board statusshows what is on you, blocked and ahead even on a clean board;start
prints the count first and the repo's.agentry/NOTE.md.lane execprints readable text by default;--jsonprints the one object.startlists the
owned files it parsed (new ones marked) and how to amend them.- Owned files are paths only: symbols, string keys and spans after a negation ("no line in
x") are left out, andpath:linesreads as the path. They are parsed once atstartinto the
ledger, so every later brief uses the same list. lane exec owns <id> [--set a,b | --add a,b] [--apply]shows or replaces the owned files, or adds
to them (--add, for a builder that asked for a file it does not own), and rewrites the brief still
waiting for its agent.lanes.maxWritersno longer counts worktrees the repo keeps (worktrees.keep) or the host's
.claude/worktrees/agent worktrees that no lane owns.nestedlists only worktrees inside the lane's own worktree, not every worktree created
while it ran.- The main-touched guard lets the conductor work on main while lanes run: a
board addor
board set --applythere is recorded and stops no lane (a hand edit of the same file still
does), and files listed in the newguard.allowkey may change, except a file a running
lane's contract owns. lane merge --cleanupdiscards ignored files the newcleanup.disposableglobs match (build output,
import caches) without asking; any other ignored file still stops it./agentry:initproposes the globs
from.gitignore.restart, the land's cleanup andlane sweepread ignored files through the same
filter: a cache the globs cover no longer stops them, and a folder with no file at any depth never counts.lane execbriefs and gate lock — a notes-fix brief keeps its "Notes to fix" after
owns --apply, and the recheck brief names the notes the builder was sent back on. Notes rounds
stop at theexec.noteRoundsbudget. A bare file name in a contract's owns is looked up among the
worktree's tracked files, and a bracketed aside no longer drops the next owned path. An empty or
unreadable gate lock file is taken over, a lock refusal names the file, and the land's own gate
on main waits behind the same lock.- Small fixes —
board scanwith no directory ends with a line naming the git-ignored folders that hold
markdown it did not read.--helpexamples readagentry board …when the bin is on PATH. A
cleanup.disposableglob naming a folder covers the files under it.exec closetakes the episode's task
line from the last build report.lane session startcounts gate slots that do not fit (+2 more) and puts
the stale-note step before its id list. A flaky re-run the land refused is recorded on the first gate run
and named in the gate row. Ajoinholding a line break or another control character is refused when the
process file loads./agentry:initoffers lifecycle board writes once, saying what they write. - The guard follows an in-branch rebase — when a builder rebases onto, or merges, a newer main, the
guard's start moves to the merge base, recorded instartMoves[], so a main commit the branch already holds
no longer trips it, and main's own changes are no longer counted as the lane's files. A main commit that
touches an owned file still trips. After a moved start the report's commits count and subject check read
<moved start>..<listed tip>. The build and fix briefs now tell the builder never to rebase or merge main in
a lane, but to ask forexec rebaseorexec restart --carry. lane mergeand its preflight refuse a land over an open dependency — the newdepsrow runs the
board'sdeps-donerule on the item as the land would leave it, before any pick, and prints theboard set
line that clears it (a list of two dependencies stays one word). Only the item's own findings count, a
refused land leaves the ledger alone, and the row is absent without adeps-donerule.- Restart archives live in dot folders — an archived ledger is
ledger/.archive/<id>.<n>.jsonand its run
folderruns/.archive/<id>.<n>/, where no valid task id can reach, so a task namedT-1.2no longer collides
with the second archive ofT-1. Archives in the old flat layout are still read as archives, andledger
lists name any file they skip. - One code-fence reader — every markdown reader (board, contracts, briefs, steps, notes, instruction files)
masks fences through one scanner: a fence opens at any indent, nests by character and length, and closes only
on the same character at least as long with nothing after it. Fences inside list items and longer fences
holding shorter ones now read as code everywhere. board contract --kindandfind-contract.mjs --kindexit 2 on a kind the process file does not have,
naming the kinds it has.- Atomic file writes refuse a read-only file — the board writer now writes through the same temp-then-rename
helper as the ledgers, and that helper refuses (EACCES) a file the process may not write, before writing
anything, as an in-place write does; a rename alone would have replaced it. A replaced file keeps its mode. agentry mem updateapplies the side effects of the dedicated verbs or refuses with the verb to use:
supersedesretires its target,status: "superseded"leaves search, an archived fact back to active
points atagentry mem recover, a superseded fact cannot become active again, a fact superseding itself and
a scope that moves a fact to another root are refused. Re-sending a fact's own scope is accepted.board scannames the git-ignored folders in its hint without walking them (no markdown counts), and skips
more build folders.- A handoff line matches its commit in either case, and status, evidence and
board fixread hand-written
upper-case commit cells again;board fixno longer takes a hex run glued to letters (g1b72454) for a commit. - Eval:
selfevalstartsclaudewith--plugin-dir <repo>/plugin. Bench results recorded before this
change ran without the plugin loaded. The README's reproduce steps use pnpm and the commands the CLI has, and
warn that the bench runsclaude -pwithbypassPermissionson your machine.--k,--concurrencyand
--timeoutrefuse a non-number or a value below 1 (exit 2). - Structure, no behavior change: the lane's
execcommand is split intolane/exec/domain modules and
one module per step, with the brief builder, the land's carry and the cut (underlane/exec/cut/) as
separate modules, and the git mid-operation checks, the path check, the commit content id and the printed
lane command line each have one copy;process/drift.mjsandprocess/git.mjsare split by concern; one
glob matcher, one commit token, one path display helper and one phase list replace their copies; every git
call inprocess/goes throughgit.mjswith its timeout.
Fixed
- Carried board writes stay inside the board — a lane's carried rows and cells are written only to the board's
own files, before anything is read: a crafted ledger path through a symlink (or its case twin on macOS) can no
longer write outside the repository, and a carried path with..or an absolute path is refused. - Branch names that differ only in case — on a case-insensitive filesystem a read by name could open
another branch's ref.lane merge --branchtakes only a branch's own name exactly as git lists it, its tip
from that line, and refuses a revision, a case twin, a branch with no commits yet and a worktree on a
spelling no branch is named, with nothing written. Every merge call,--checkincluded, reads the
ledger's branch and tip from the branch list again, so a twin made since is refused, never landed.
lane merge --cleanupandlane sweepdelete a branch at its listed tip and keep one with a case twin,
and the sweep says why it kept a removed worktree's branch (kept <b>: it has a case twin <other>, or
work not on main).lane exec restartmoves the branch at its listed tip and refuses, before writing
anything, a lane branch or a kept name that clashes with another only in case. - The guard after a rebase — a rebase that moves a lane's start no longer holds the lane for a board row
that was mid-write at its start and committed since; an edit on main that was discarded rather than
committed still trips. lane exec restartno longer counts an ignored empty directory as a file to lose.- Leftover temp files — a gate's release removes the temp file a writer killed mid-write left beside its
slot, andlane sweepalso frees dead writers' temp files in.agentry/run/itself. - Locks and slots — a lock or gate slot is freed on every exit of
agentry run(a normal exit, an error,
SIGINT, SIGTERM, SIGHUP) and stays held while the command's group has a member; slot files are written whole
and every rewrite is serialized, so a reader never sees one empty and two riders are never lost. A holder's
start time is read in UTC, so another time zone never frees a live holder, and a holder whose start cannot
be read counts as alive. lane sweepfreezes a stray and everything it started (SIGSTOP, looking again for new children) before
it kills them, so a process that forks in its handler leaves nothing behind. Its preview no longer sweeps the
temp files it reports.- Stacked lanes — a restack and a queued gate no longer undo each other (the gate marks its intent before
it reads the ledger and a restack refuses while the mark is live); a killed restack is read from its plan
only when the old base is gone from the branch;exec rebaserefuses a lane stacked on an unmerged parent
and points atrestack. board—board addrefuses a field value holding a line break;board fixlists a landed item of a
kind it does not write with theboard setthat records it; a process file whoseexec.kindsnames a kind
another kind lists as its children is refused at load.agentry runholds its command until the slot records it — the command used to start before its
process group was written to the slot, so akill -9of the run in that window left it running while the
slot read free and a second run of the lock could start beside it. It now starts held and runs only once the
record is written; if the run dies first it never runs. The gate watchdog records its own group before it
spawns its command, for the same reason.agentry runon a command that cannot start exits 127 (not found) or 126 (found, but not executable or
a directory) with thecannot start <command>: <why>line on every platform; a command that was found but
not executable used to exit 127, and a missing path exited 126 on macOS. A command named like an option
(-x) is run as a command, not taken as an option.restarton an owner hold with no run no longer crashes.- Flaky lock, gate, sweep and eval tests under load — the sweep forker tests count and kill only the
sleeps their own process forked, and the eval test tells a decompose kill from a grace expiry by a 2 s
grace. - A cut stopped mid-land is never landed by
lane merge— every merge mode refuses a ledger holding a stopped
cut and namesexec cut <id> --decision <D> --apply, which rolls it back;--pushand--cleanupon a cut
lane write nothing. When a cut cannot keep its branch it prints only the steps still owed. - Printed commands quote their paths — the restart diff in a carry conflict, a brief or a stopped restart's
steps pastes as is in a repo whose path holds a space. - Memory writes survive a kill — a fact or episode file is written to a temp file and renamed into place,
so a process killed mid-write no longer loses the record; its permission bits are kept, also when a text
change renames the file. A memory file with no readable header is reported inagentry mem stats
(readErrorsin--json) instead of skipped. Search after an update reads the store's own write. - A commit that arrives later is found — git lookups no longer remember a missing commit for the life of the
process; a board report asks git once for the commits it names. Short SHAs come from onegit rev-parse. - Eval report data keeps
$sequences, and the direct-run check works on paths that need URL encoding.
Removed
- All plugin hooks. Their work moved into the commands above; the plugin check fails if a
hooks.jsonreturns. - The Workbench (
/agentry:workbench, its server and web app). Unused in practice: the board
in markdown and/agentry:startshow the same state without a second source of truth. - The flow MCP server and the channels that rode on it.
/agentry:go,spec,plan,split
andfixkeep their shapes and write the spec, plan and task files as plain files under
.agentry/work/<run>/; review and approval happen in the chat. The plugin check fails if
plugin/names either again. /agentry:gowith no task claiming queued work. It now asks what to work on, and points to
agentry board statusand/agentry:execwhen the repo has a board.- The memory MCP server and its
plugin/mem/bundle. Memory is theagentry memCLI; see Changed.
Install: /plugin marketplace add silentthreadstudio/agentry then /plugin install agentry@agentry-dev, or download agentry-v0.3.0.zip below. Full history: CHANGELOG.md.