Repository navigation
santos/dev: crew family, Pareto crewing and the Model Pool, custom connections - #1108
Conversation
… custom connections (#1194) Lands the integration branch santos/dev (#1108, head 6db5125, 152 commits over dev) on dev as one squash, plus two fixes that kept its touched-packages job red: the pool start-up test empties the CI word it is not about (649bb4b), and a zombie leader no longer keeps a job's process group alive on Linux, which had delayed every finished background job by the two-second termination grace since #1155 (053e6a9). #1108 carries the full account; the 94 change entries under docs/changes/unreleased/ are the per-change record. The commits folded in, oldest first: 5c413ef Keep archived evidence readable while tasks finish 3705a0c Document recovery evidence retrieval change 7834cc7 tui3, manual: a question's own answer box answers to the whole caret vocabulary 99d66e9 task: Add open/all source toggle to crew config c1e4cb5 docs: the change entry for the crew model family toggle e63b439 crew: round-1 review fixes 304a5a2 crew: round-2 review fix 65477c0 task: Add open/all selector to /crew TUI picker 9189ef7 Merge branch 'task/add-open-all-selector-to-crew-tu-9e8cc0' into feat/crew-open-all-toggle ba9c12d crew: reconcile the picker onto config's source helpers ea05bc0 crew: a chosen family counts as an answered crew e1a037e Merge remote-tracking branch 'origin/dev' into feat/crew-open-all-toggle f6c2924 crew: the open table takes the picks we landed on eff44b5 docs: the change entry carries the open-table move and the family gate 71ce9be crew: the family reaches the fallback, the settings skin, and the row's line b8ca5f5 crew: round-1 review fixes on the new table 8db5708 crew: round-2 review fixes ce9759e crew: round-3 review fixes 956e1f5 crew: round-4 review fixes 37ad27f crew: fixes from the first Opus round 6ffb958 crew: the fixes from the Opus confirmation round 72b0274 crew: the comments the atomic write left behind 70d0e20 crew: round-four fixes from the Opus review 234300e Merge branch 'dev' into feat/crew-open-all-toggle 894292f crew: round-five fixes from the Opus review fba77f9 An answered landing carries its answer's fate when it is raised again, and an in-flight settle holds the question down (#1077) e694450 Changelog entry for the landing-answer fate (#1086) 64ab7ea crew: round-six fixes from the Opus review 0700164 crew: round-seven fixes from the Opus review af09aa8 The review round's four findings: claim ownership, decider changes, recordable answers, plain words c24af02 crew: round-eight fixes from the Opus review 289d372 The tests the landing's answer carries: fate, hold-down, redraw, claim doors 7e38346 The take-down comes before every mint, and the tui3 walk reads the newest card dbe1be0 The review rounds' last word: the release owns its claim, and the docs say what the code does 4cc4945 The Opus review: a release owns its generation, and every failed round still says its word a5cce0d The done card says who is deciding, so the clause is a duplication, not the fact 6bd276e Merge fix/1077-landing-reraise into santos/dev 2710169 Merge feat/crew-open-all-toggle into santos/dev b459399 Merge fix/question-answer-box-caret-keys into santos/dev a384920 Merge codex/recovery-evidence into santos/dev dc22e64 cmd/codeaf: the role-door tests read the shipped mastermind instead of a copy of it 39f528f release: the pin-example check reads the guide the examples moved to 6439d3c session, tui3: gofmt the three files santos/dev merged unformatted 8540379 tui3: a question's answer box kills to the end of the line on ctrl+k d93ec61 session: the late-attach proposal test holds the work until the replay is read a81ead4 session: the landing-fate tests read today's clock instead of a fixed date 8fe4fff provider: the retry-avoid list rides the call's context into the knobs a266da3 provider: the retry-avoid veto narrows the wire through one field law 197d893 exec: a node retry asks the router to avoid the lanes that failed it 2d02cc0 provider: the set-servable law's doc comment keeps its paragraph break e1d0e75 exec: the retry test names its helper and spells its wall in time units e7d65a5 docs: the change note for the retry that avoids the failed upstream 11decbd Merge fix/provider-failover into santos/dev c099a51 Merge dev into santos/dev e47d92b provider, exec: the lane a failure names is a wire fact provider reads (#1105) 396be97 Merge dev into santos/dev 3b97f50 Merge dev into santos/dev ea3b5c9 telemetry: the send path drops events that cannot name their version 573b288 cmd/codeaf: keep smoke runs from sending usage counts e8d627c docs: the change note for the usage-count audit fixes 11bec8d chat: a hosted session's usage counts are read off the events it receives b9d75b3 chat: the hosted-count tee is tested against the tally it must produce 39fa08d telemetry: stamp a version in the lifecycle tests 681e2ad chat: count the hosted boot agent once, and conversations opened beside 825ef2c connect, settings: named, multiple, switchable custom connections (#1092) f4d3f9a Merge branch 'dev' into fix/telemetry-audit 76fec37 ci: the Model Pool mirror workflow and the signature check it runs 2fb296b crew: Pareto crewing, the learned picker and the Model Pool (#1093) a065ebb Merge remote-tracking branch 'origin/dev' into santos/dev 80ac250 Merge remote-tracking branch 'origin/feat/pool-mirror-workflow' into santos/dev 6092393 Merge remote-tracking branch 'origin/fix/telemetry-audit' into santos/dev ef808dd session: a decision card under --yolo takes its default (#1117) 70a9e1f session: a task's thread stops its parts before it closes, and a machinery cut says so (#1118) c4df8f3 crew: an auto seat's rung names the pick that ran, once, for both doors (#1119) a9fcf9b crew: a bare auto row under picked from = catalog reads the catalog's figures alone (#1120) 13be0dc relay: accept the exec and run doors, not only task and do (#1121) 90f29ae changes: name the #1120 note by its PR and stamp the pr field 0b77926 do: seat from the settings the run will use (#1122) 32148d8 changes: stamp pr: 1120 on the #1120 note 113ed62 pool: a launch's start-up errands stop when the process closes (#1124) 6c98ddc verify, codeaf: a launch compiles fewer patterns and a surface holds fewer Ps (#1125) 50fe6a3 pool: the min_installs floor counts installs on the client (#1127) 076cde8 relay: fold a resubmitted row once by its nonce (#1128) 8339ae7 relay: carry the acceptable metric beside role_quality (#1129) 0367c44 outbox: a refused row leaves the outbox and the rest of its batch is sent (#1130) 09aecd2 relay: the index holds only the cells that meet the min_installs floor (#1131) ae7c05d outbox: a Send compacts the file to the rows it still holds (#1133) 9e24f72 pool: the errand tracker's critical sections unlock from a defer (#1134) 358a569 relay: fold a submit batch with one read and one write per distinct cell and day (#1136) a1d2eb1 pool: judge landed-but-unjudged runs on the next chat start (#1132) 3c67228 verify: take the finished-tree check at a project cloned into a subdirectory (#1135) 263625b exec: a headless run leaves a pending judge record at its tail (#1137) 8be373d run: the headless task door leaves a pending judge record (#1138) a336b24 do: leave a pending landing for the Model Pool's judge (#1139) 8820a56 cmd/codeaf: one readPendingRows test helper, not two (#1140) 49760fb pool: show and verify print both metrics the index carries (#1141) 6eaeb25 pool: status shows the pending judge records and the last sweep (#1142) 7c00b5f codeaf: a test's crash fixture stays in a profile the test owns (#1145) fc2eb35 manual: the status row's ledger is the tree's, not the conversation's (#1143) a06b53a test: pin the delivery gate over a grown job root (#1147) 7231347 resident: the wall refuses a first replan round it cannot hold (#1144) 5e25755 cmd/codeaf: the package's test floor clears a profile the environment named 4dd1c56 Revert "cmd/codeaf: the package's test floor clears a profile the environment named" 9075f86 pool: the seed index is regenerated from the relay by seedgen (#1148) a5c44f3 pool: show --cells lists the held index's cells with installs and dims (#1149) 8259967 cmd/codeaf: the package test floor clears a profile the environment named (#1150) 81568aa session: report gitignored build products a run leaves, without gating on them (#1152) da49105 internal/tui3: the opening hint test owns its profile and pins both doors 72de3bc docs/changes: #1151 — the opening hint test owns its profile 499083d Revert "docs/changes: #1151 — the opening hint test owns its profile" beb31ec Revert "internal/tui3: the opening hint test owns its profile and pins both doors" 25b8b7d version: an unstamped binary names the condition, not a Makefile target (#1151) c833b42 pool: a dropped row keeps the relay's reason and status shows it (#1154) cbb7d6d processgroup: verify a job group's identity before signalling it (#1155) efe498e internal/tui3: the opening hint test owns its profile and pins both doors (#1153) 17b3b0e do: a continuation continues the plan it has instead of re-planning (#1156) 22cf3ce changes: correct the #1155 and #1156 notes' pr fields (#1157) 8e85b0f cmd/codeaf: a surface runs under a soft memory limit drawn from the machine (#1158) ef1e927 task: status row accounting (#1159) 44f572e pool: status's index line says what this run's fetch did to the cache (#1161) 3600fc9 pool: the pool's copy of a seat's id is the bare vendor/id (#1163) a2ebd13 cmd/codeaf: no test can push pool rows to the default relay (#1164) 4fb7f05 docs: the road a chat door bash push took under --yolo (#1160) 69219a1 cmd/codeaf: the soft memory limit is the smallest real bound, not the host s memory (#1162) 2b155b4 relay: bound judge severity, clamp adjusted scores, publish mean and sd on one scale (#1165) 2fb5532 relay: purge fixture vendors and refuse them at the door (#1167) 5750418 exec: a job's shell cannot reach the tmux server hosting codeaf (#1166) eb7b465 internal/session: an unattended run may not move a branch it did not create (#1168) 80f7706 pool: status says the identity, the judged total and that nothing has landed (#1169) 1cb7333 exec: an exec run's worker spend reaches the usage ledger (#1170) 96bb940 changes: the #1169 note's title parses and reads as one line (#1172) 627236d config: the task door honors a stored crew word, and a pin survives the learned pick (#1171) 593092b internal/tui3: a test may not read a profile it did not create (#1173) ad8be1e session: a landing card under --yolo takes its default instead of parking the run (#1174) 03d49a6 gitignore: the .furrow ids the engine writes into a workspace (#1175) 46edbdd internal/tui3: gofmt the profile-law helpers from #1173 (#1176) 3179e36 relay: ALLOWED_VENDORS names the catalog's vendors and codeaf (#1177) 397a145 docs: why a settled /task leaves commits on task/<slug>, not the worktree branch (#1178) 915ff3a pool: regenerate the seed index from the relay's first clean publish (#1180) d9b4243 cmd/codeaf: the model warm stops when the process closes (#1179) bd2dcf3 session: the auditor's calls say they are the auditor's and which node they check (#1181) c6ed47c task: json unverified branch (#1182) 360352a session: a settle turn runs under the checker's own bound, not the run's wall (#1183) 814e1af session: the tasks text and record line name a failed/unverified node's kept branch and verdict (#1184) 7c25a26 internal/session: the identical-effects test stops riding the turn guard (#1185) 6e7d0ed cmd/codeaf: exec and run envelopes name a non-verified node's kept branch and verdict (#1186) f4079d7 session: bound a worker's park on a promoted command (#1187) 994689f docs: the model pool runbook names the Workers Paid plan and what it costs (#1188) c315be1 docs: the runbook's plan line says metered, not capped, and nothing more (#1189) 2e80c60 internal/tui3: the status word says working while a task subtree turns (#1191) 99363ca session: bound a job subtree's CPU and process count (#1190) 6db5125 docs: what the audit check seat can execute, and where that boundary is set (#1192) 649bb4b cmd/codeaf: the pool start-up test empties the CI word it is not about 053e6a9 processgroup: a zombie leader does not keep a job's group alive b4e66f5 docs/changes: the entry for #1194 Co-Authored-By: Santosh kumar <29346072+santoshkumarradha@users.noreply.github.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Merged into
Nothing on One observation from the smoke, not a blocker: |
The spine draws its samples in concurrent goroutines by design, and two tests counted the fake client's calls with a plain int. Under load an increment could be lost, so no sample saw the third call and the draw read 3,3,3. The counter is now atomic.Int64 in levels_test.go and named_test.go; every assertion is unchanged. Test-only. Evidence (Spark): -race on the unfixed tree reports the race at levels_test.go:87 from spineWithProgress goroutines, product clean; after the fix go test ./internal/plan -race -count=200 ok; build, changes check, guard and namelaw green on 65249bf, tree aa25dee before and after.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…give (#1304) The page said an interrupted row offers two answers, continue it or leave it. Nothing draws them. There are three readers of a task's two answers in the tree and a run's row reaches none of them: it never enters the index the needs panel reads, it never holds the state the landing question requires, and it never matches the question the record card looks for. What is true stays. The row does wear the asking mark and does wait for a person, through the surface's own node rather than through the record, so that clause is kept rather than softened away with the rest. In place of the promise the page states the limit: nothing picks an interrupted run up yet, no key, command or background pass does, and nothing ever will without being asked. That is the sentence a person came to the page for.
* task: benchmark methodology Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * readme: the one-binary claim is measured, not asserted Startup, on-disk footprint and idle memory against six other agent CLIs, placed next to the sentence they substantiate. Memory is PSS because the two-process design shares one binary's text; the metric the fastest competitor wins is in the table rather than only in the linked write-up. Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * readme: cut an opening sentence the window section already makes, and a badge The second sentence of the opening paragraph restated the one-window-and-tasks framing that "One window for every project" and "What a factory is" carry in full. The model-pool badge repeated a link the section's own prose and the design document already give. Kept as its own commit so the cuts can be dropped without losing the measurements above. Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * docs, readme: the footprint method, the full named table, and a five-row summary The cell wrote measure-cli.sh but no methodology, and a three-row table that omitted the two strongest honest rows while keeping two we lose. This adds docs/benchmarks/README.md (method, the four rules the numbers depend on, and the known limits including the wakeup figure being unusable), docs/benchmarks/results-2026-09-17.md (the full table with every CLI named, including the three rows where another binary beats this one and the row where it could not be measured at all), and replaces the README summary with five rows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * changes: note the footprint table entry for #1126 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * readme: restore the hero block the footprint section displaced My own edit script matched from the new heading to the next ## and so removed everything between, which is the hero: the early-preview notice with its Discord and issue links, the overview screenshot and its alt text, the demo video and its caption. They are restored untouched and the footprint section now sits between them and Install, which is where it belongs anyway. The em dash in the closing sentence is gone, and the table ranges read x to y rather than using a dash. The two listed README cuts are unchanged and remain in their own commit (cbc1d0d). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * readme: leave the top-level README as it was; the footprint table stays under docs/benchmarks Santosh reviewed the README hunk and asked for it to go. The method, the script and the full named table remain in docs/benchmarks/ and the change note now says so. * docs/benchmarks: the results file, not the README, is the script's output * changes: name the #1126 note for what it notes * docs/benchmarks: record the machine's load average around every timed phase load1/5/15 land in phase=meta, and again immediately before and after the startup and idle windows, read from /proc/loadavg with a builtin read. Telemetry only: no default changes, no new dependency. Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * docs/benchmarks: the README now says what the script does and how to invoke it The example invocation was flags the script does not have (--name/--home parse as NAME and HOME), cold start was documented as best-of-N with no word of the discarded warm-ups or the warm cache behind it, and the README claimed every table in the results file was this script's output when the on-disk and one-turn tables are not. Load recording documented. Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * docs/benchmarks: the method review — per-column verdicts against the competitor test Three columns fail the read (version rows contradicted by the box, on-disk rule stated nowhere and unreproducible, one-turn sampler uncommitted); the startup, frame, idle and strace columns hold with caveats. Facts 3 and 4 caveated, not invalidating. Evidence named for everything still open. Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * docs/benchmarks: the rerun that tests the review, and what it settles The method review above was taken by reading. This adds the measuring: all seven CLIs again in one session on a quiet box, at ONE build for every column (4f002ca2), with the one-minute load recorded beside every figure and sampled six times across a full minute before the run began. Startup and first frame stand and are published with the load beside them. Several figures move a long way from 2026-09-17 — claude's first frame 572 to 429 ms, cursor-agent's 1,298 to 592, pi's startup 330-360 to 146, omp's first frame 400 to 1,254 the other way — which is the load finding demonstrated rather than argued. The idle memory column's verdict MOVES, from "fair with caveat" to "cannot decide, and not reproducible as it stands". Every one of the seven measured procs=1, where the table has CodeAF at 2 and cursor-agent at 5. It cuts both ways and is nobody's win: CodeAF's PSS came out 38.7 MB against 66.4, and cursor-agent's 194.4 against 412.7. Three explanations were tested and killed — not the sweep or the choice of HOME (sweep_home is teardown only, and a controlled pair under a dedicated home and under the operator's own both gave procs=1), not a product change (cursor-agent is the same version string), and not a different script (the script was committed before the results). What is left is the invocations, which were never recorded. Also records what each CLI actually resolves to. opencode is not on a login PATH at all and exists as two different products; pi is a JavaScript bundle; codex and cursor-agent resolve to different binaries depending on how the measuring shell started. The header's own two-build split needs no caveat: the package-init changes have landed, so measuring at one build removes it. The run's log and the rig it was taken with are committed beside the note, so the next person to ask this question starts from a recorded rig rather than from a reconstruction. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * benchmarks: make CLI teardown workspace-specific * docs: correct defective memory measurement * benchmarks: split teardown survivor accounting * docs: repair benchmark method review prose * docs: record c245 teardown accounting checks * benchmarks: retain launched process ancestry * benchmarks: state which processes the idle figure sums The script sums the processes of the launched tree that are alive at the last sample of the idle window, and the README did not say so. A reader comparing two CLIs could not tell whether a helper that exited during the window was charged or not. The rule is stated with its reason: a steady-state figure must not depend on how long the window was, which is what summing every process ever seen would produce. The transient cost is reported in peak RSS instead, and procs_seen is named beside procs so a CLI that churns helpers is visible rather than hidden behind a single count. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: the 2026-09-20 footprint tables, their drivers, and the hero figure Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * docs: classify benchmarks under docs/benchmarks/performance Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * docs: sharper performance benchmark gist Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * docs: neutral review voice, explicit multiples in the gist Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * docs: gist as bullets Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> --------- Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* docs: resume cost joins the footprint benchmark Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * docs: change note for the resume table Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * docs: the quick table joins the gist Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * docs: table outside the list, blank lines around it Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> --------- Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
…y its work is already in An interrupted run's store holds every step it took and, since the copy record landed, its row knows where that work is. This is the one door that starts work on it again: it adopts the recorded working copy and the store already on disk, hands both to the same engine under the same seats, and lets the supervisor's ordinary next pass release the claims whose owner is gone. No resume machinery, no second scheduler. IT HAS NO CALLER, ON PURPOSE. Continuing seats workers and spends money, and a door that spends money reachable before anything means to reach it is not a smaller version of the feature but a worse thing than no door. The card that offers the choice is the next change; until it lands a person cannot reach this from any surface. The refusals name what is in the way: a run that never stopped, a number with no run behind it, a run that already said its last word, and a copy that was never written down or is gone. The refusal for a run with no copy is the SAME sentence the row shows where the offer would otherwise be, taken from one constant, so the reading and the answer cannot drift into two spellings of one fact. The reading gains that sentence as a sentence rather than as a flag, and the run spec is now built in one place so the start road and this door cannot diverge the day a cap moves. Every refusal is proved twice: that it said no in the person's words, and that nothing started. The test that matters puts a worker's file in a run's copy, carries the run on, and reads the file back: the road this door could have taken instead clears that directory (#1298 shows it doing so). Fourth cell of the settled close-window design (#1224). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ne tested form Three shapes of proof step were each written more than once and each was incapable of reporting the failure it was checking for. gofmt -l prints the files it would reformat and exits 0 whether it printed any or none, so a step reading its exit code reports green on every tree that has ever existed. A pipeline ending in a reader hands back the reader's status, so `cmd 2>&1 | tail -25; echo "exit=$?"` printed exit=0 underneath a screen of FAIL, which does not merely hide a red but manufactures a green directly below the evidence. And a -run pattern is a second copy of the list of tests in a file: when the two drift, go test answers a filter matching nothing with ok, because from its side nothing failed, so a named test that never ran reads exactly like one that passed. scripts/proof.sh is the one written form of all three. THE ACCEPTANCE IS THE FAILING ARM: internal/ci/prooflib_test.go runs each function twice, once where the thing it checks is sound and once where it is broken, and each broken arm also pins what the plain command says about the same situation, because in all three cases the obvious command reports success. A guard against invisible failure that has only ever been seen passing is the thing it was written to prevent, wearing its own name. No caller is converted here, on purpose. If the library is right the conversions are mechanical; if it is wrong, that is better learned on one caller than on all of them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e caret parks where you type (#1321) * task: Implement fzf v2 fuzzy matcher universally Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * fuzzy: land the remaining surface cutover (autonomy, connections, memory, folder search, rewind, registry) and manual pages Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * fuzzy: state the gap price the code and tests charge fzf's own algo.go charges scoreGapStart (3) for the first skipped byte and scoreGapExtension (1) for each byte after it in the same gap; the const-block comment claimed the first byte paid extension too, which the alignment, the gap-price test, and fzf's source all contradict. Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * task: Fuzzy match highlighting across the search surfaces Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * task: Fix the terminal cursor park for the settings search box Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> * changelog: the 1321 change entries, renumbered from the task placeholders, with the caret entry Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com> --------- Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
…es the model (#1325) * exec, session: the commit co-author links to the CodeAF account, and assisted-by names the model The co-author address gains the account's numeric id, 267109073+, the form GitHub renders as a link with the account's avatar, and a new Assisted-by line above it names the model that wrote the commit, so git interpret-trailers can answer who typed it beyond the account. The Assisted-by line is filled at the belt render, the one surface that knows the session's configured model; the leaf loop's standing contract carries the co-author alone, as before, because exec is handed facts about the model and never its name. The manual pages show both lines, and the fixed arm's prefix waiver rises by the 162 bytes the wider belt fact costs. Assisted-by: CodeAF (z-ai/glm-5.3) Co-Authored-By: CodeAF <267109073+agentfield-bot@users.noreply.github.com> * changelog: the co-author links to the CodeAF account, and assisted-by names the model --------- Co-authored-by: CodeAF <267109073+agentfield-bot@users.noreply.github.com>
|
@AbirAbbas heads up, not a review request yet: this branch is now a closed slice at Evidence on that exact head, fresh clone, on Spark:
Landed since the last pass, newest first:
The PR stays in draft on purpose. Work from here goes on the next shared branch so this slice stops growing while it is being read. Say if you would rather have it split before you start. |
…1329) agentfield.ai/github redirects to Agent-Field/agentfield, so every pull request, issue and comment codeaf drafted pointed a reader at the wrong repository. agentfield.ai/github/codeaf redirects to Agent-Field/CodeAF and is already serving, so the three attribution constants, their fixtures and the two manual pages take the longer path. The utm parameters and the rest of each line are unchanged.
The squash of #1329 carried the code and left its entry behind.
) A landing question is raised for unverified and retired for every other state, so a failed node has no question object and never had one. The reading was inventing one out of the ending's shape alone, and a row nobody was waiting on stood in the needs-you group for the rest of the session. Attention goes; the tier, the word, the reason and the take-it-anyway answers stay.
…id for The refactor that made GenerateImage one road for the belt's tool and the command line's image door (the slice landing as #1108) dropped the guard the belt-only tool had carried since it was written: an empty or blank prompt was answered "Invalid arguments: prompt is required" and cost nothing. Without it the request went to the provider, which billed the call and answered with an image that could not be read, and the tool reported that as the provider's fault ("returned an unreadable image"). The guard is back, on the shared road so both doors refuse the same call the same way, beside the model and reference checks that already refuse before the request is sent. The video and music doors never lost theirs. TestGenerateImageRefusesAnEmptyPromptAndCostsNothing pins it: a missing prompt and a prompt of spaces are both tool errors naming the prompt, and the fake painter sees no generation. It fails on the slice's head without the guard. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
AbirAbbas
left a comment
There was a problem hiding this comment.
Reviewed and verified 2026-09-21: gates green locally and in CI, the default road checked live on both roads against a dev baseline, the one regression the slice introduced fixed on the branch with a contract test. Evidence and the full write-up are in the review ledger.
dev carries #1332, #1108, #1333, #1107, #1208, #1071, #1376, #1377, #1381, #1385, #1386, #1387 and #1384. #1108 is the santos/dev slice held at 759d704, which dev2 already descends from, so the tree was merged against 759d704 as its base: the slice counts as already here, and only what dev did beyond it is brought in (the nested-module walk, the image guard's duplicate, and everything from #1333 on). The commit still records origin/dev as its second parent, so a dev2 to dev pull request sees dev as merged. Four files conflicted: - tools_image.go: both sides restored the empty-prompt guard; dev2's comment kept, and dev's second copy of the guard's test dropped because #1372's test pins the same refusal. - surfacedoors_law_test.go: dev2 added one ledger door and #1071 crossed workingNowAgent; the ratchet counts the merged ledger, 22. - tui_e2e_test.go, tuiwords_test.go: the home that #1071 draws is the one in the tree (dev2 never redrew home after the slice), so the suite waits for #1071's words.
* tui3, config: the gate row lands on the conversation you are in, and /status names the gate (#1063)
The three Safety rows — `ask before running`, the tool exceptions and the shell
command rules — wrote the profile and left the running gate alone, while the
YOLO badge read that profile live. So the badge and the gate disagreed in both
directions: `allow` lit the badge over a gate that kept asking, and `prompt` put
it out over a gate that was still wide open, which is the false-safety claim
#322 and #325 exist to prevent.
`applySetting` now pushes those three rows through `ApplyApprovals` — the seam
/permissions already drops a banked rule through — and refreshes the badge on
the same keystroke, on the branch where the push landed. A rebuild that could
not be done is said out loud on the panel's foot line in /permissions' own
words, `saved · from the next session`, and the badge stays with the gate in
force rather than following the file.
And /status carries the posture it never carried: `approvals prompt`, `allow` or
`deny`, in the `ask before running` row's own words, in the note, in --json and
on the phone's status sheet, from the one posture reading the badge uses. The
status row keeps its negative-space badge and the segment is no longer written
into the page twice.
The note's label column is measured from the widest label it carries, so three
crew assertions that spelled `"\ncrew"` plus exactly five spaces were
assertions about every other row on the page. They read the crew line by its
label now.
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* attribution: the footer names CodeAF, and still links to agentfield.ai (#1075)
* attribution: the footer names CodeAF, and still links to agentfield.ai
The pull request, issue and comment footers read "Drafted with agentfield ai".
They now read "Drafted with CodeAF"; the link, its utm parameters and the
"reviewed and owned by the author" tail are unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNBScbyNAbbEQ5jn9G6auy
* docs: the change entry for the CodeAF footer
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNBScbyNAbbEQ5jn9G6auy
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* session, prompt, tui3: a wrong completion check is answered with [no change], and the answer stands (#1065 round 1) (#1067)
* session, prompt: a wrong completion check is answered with [no change], and the answer stands (#1065 round 1)
The end-of-turn reader saw 600 bytes of the last message, so a long table read
as cut off; the carry-on told the model to explain itself, and the explanation
became the only answer left in view under the fold.
The reader now sees up to 8 KB of the last words, and a cut it still has to
make ends with `[clipped by codeaf: N of M bytes]`, which its ask says is never
evidence of a cut-off answer. The carry-on lead says who wrote the note and
offers one exact reply, `[no change]`: it ends carrying on for the ask without
another reading, the transcript keeps it for the model, and neither replay nor
the live feed draws it — so the settled answer before it is what the fold finds.
system.md trades `# Tone` and `# Delivery` for `# The answer`, `# Words or
work`, `# When corrected` and `# Messages from codeaf`, and the two lines that
pushed action on questions are qualified. The lean page keeps all four; the
prefix waivers rise by the 1,705 bytes that cost, dated and named.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs: the change entry takes the pull request's own number
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* session: a quiet landing is asked about the notes it was handed, not the page that names them
The worker's system page now names [silent] and [stuck] under
`# Messages from codeaf`, so a search of the whole request found the tag on
the page. childWasHanded reads the conversation and leaves the page out.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* session, prompt: [no change] answers the note it follows, and a long ask leaves the last words cut by name (#1065 round 1)
Self-review of #1067 found the token honoured on the wrong replies. The gate
read the turn's carry-on count, so a model that made calls in answer to the
note and then said [no change] ended the turn unread on an answer those calls
may have made stale, and a token after a load or ask nudge counted too. It now
reads the transcript: the token must be the very next reply to the reader's
own lead (answeredNoteUnchanged), and the dead declined flag is gone.
An ask up to the whole digest rides in its head, so eight kilobytes of last
words behind a long ask reached the backstop clip and ended in a bare `…`.
checkpointClipSaid takes the room that is left. A turn that ends on the token
no longer starts the route judge or hands the token to the memory reflex, and
a later reading's last words skip it.
`# Messages from codeaf` named `[still asked]`, which only the reader ever
receives, and left out `[stuck]` and `[held]`, which the conversation does; it
now names the tags that arrive and says any other opening, such as
`[image #1]`, is the person's. The waivers sit on the measured 1,779 bytes, and
the manual and the change entry say what the gate actually honours.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* prompt: the new sections keep the rules the old two carried, and say what stays in view (#1065 round 1)
Owner review of #1067. Replacing `# Tone` and `# Delivery` had dropped five
rules; each is back inside the new sections: match the person's task and
vocabulary, choose the safe option under uncertainty, evidence and blocking
details complete, never a compiling scaffold or a narrowed test, never
half-solved work.
`# The answer` said only the last message reaches the person, which `# Planning`
contradicts: the plan and the per-batch sentence are shown while a turn runs. It
now says that once a turn ends only its last message stays in view.
`# Words or work` sat beside `## Work or words`, which spends the same two words
on hand-off sizing; it is `# Answer or change`, and it says an answer asked for
in chat is written in the reply, not a file, unless the person asks for one.
The waivers sit on the new measurement, 2,035 bytes over dev on both arms.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* prompt: the messages-from-codeaf list names every note codeaf writes
The system prompt now distinguishes conversation user-role notes from private reader and tool-result markers. A structural test follows the production constants, and the byte waivers record the exact fixed and lean measurements.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* session: no change skips judgment only when it answers the reader
The completion loop now uses the transcript context before suppressing the route judge or substituting the prior answer for memory. Tests cover the withdrawn and ordinary-token memory paths, and the manual separates counting from display.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* test: the model stub replays the no-change fold
The OpenAI-compatible stub can now drive the real binary through eleven read rounds, a long table, a rejecting reader, and the exact token reply. The recipe records the tmux setup and the expected log and screen evidence.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* prompt: the standing-news tag stays with the event, not on the page
The messages-from-codeaf list had named [something you set up fired], and
TestTheSteeringLineReadsAsNewsAndNotAsARequest refused it: that line says
under the news itself what it is and what not to do about it, so the page's
copy is one law bought on every request of every turn for a turn most
sessions never have. The list keeps the compaction tags, the structural test
now files the standing frame with the private voices the page must not name,
and the waivers fall to the new measurement (fixed 55,280, lean 47,055).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Abir Abbas <abirabbas1998@gmail.com>
* Clean internal experiment records and revive test/ux for codeaf (#1068)
* chore: clean internal experiment records and revive test/ux for codeaf
Public-repository cleanup ahead of opening the docs to outside readers.
- Remove four internal DOE/experiment record directories that reference
private issue and pull-request numbers and are not current-product
documentation: docs/design/pin-doe, plan-gate-doe, turn-wall-share-doe,
and workspace-foundation.
- Neutralize internal machine references in benchmark and design docs:
the bench host ("spark"), its secrets.env path, and a personal working
branch name, all now generic placeholders.
- Revive test/ux/, the user-facing journey suite, for the renamed product:
collapse the removed v1/v2 dual-surface logic into the single v3 surface,
repoint the binary to cmd/codeaf and state to ~/.codeaf/CODEAF_*, and
delete gate.sh whose premise was the v1-vs-v2 parity table.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* chore: drop internal conversation-runtime wave records, keep the measurement contract
The conversation-runtime directory was a local development wave: day-by-day
status, /private/tmp paths, "owner authorized" process notes, draft PR numbers,
and local change logs. None of it is current-product documentation a public
reader needs. Keep PARETO.md, which is the benchmark's cited measurement
contract, trimmed of its dangling calibration link and owner language.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* chore: neutralize the remaining bench-host and work-machine references
A wider sweep found the internal bench host ("Spark"), its secrets path
(fleet/secrets.env), and a scratch ops directory still named in live docs,
bench READMEs and bench scripts that the earlier redaction had not touched.
Rename the host to "benchhost"/"the bench host", drop the secrets path, and
replace "the laptop" as the owner's own machine with a neutral "work machine"
where it meant the internal one. The manual's first-person "the laptop you are
sitting at" is public-facing and left alone.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* chore: fix review findings in the public-cleanup diff
- PERF.md: drop a private tracker issue reference (#846).
- PARETO.md: restore a complete sentence dropped when the calibration link was
removed, and align tense with the remaining present-tense claim.
- home-mission-control/DESIGN.md: drop the internal "fleet" system name and
an owner-framing phrase, consistent with the secrets-path scrub elsewhere.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* docs/design: the two records live code still cites stay in the tree
plan-gate-doe/REPORT.md is the measured evidence behind the plan-gate default
that twelve comments in cmd/codeaf, internal/config, internal/session and
internal/splitgate point at, and turn-wall-share-doe is the run
internal/session/turnwall.go says it was added from. CLAUDE.md keeps the
record on purpose for exactly this reason, and neither folder names a machine,
a secret or a private address.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* test/ux: the revived journey suite goes back out
#991 removed it because it drove the v1 and v2 surfaces, and the revival did
not change that: its journal verb reads graph.db tables (messages, nodes,
usage, commands) that the v3 chat never writes, lib.sh still waits for the
resident, nothing runs it from the Makefile or a workflow, and its only
evidence was bash -n. docs/JOURNEY.md says internal/e2e is the one suite that
drives the binary, and that stays true. A suite that has been run green
against bin/codeaf can come back on its own pull request with a target that
runs it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: entry for #1068
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: the #1068 entry says why the journey suite is out, correctly
The first draft said the v3 chat never writes the graph.db tables the suite
reads. Running the suite showed both message rows landing, so that sentence
was wrong; what is true is that nothing runs the suite, it had never been run,
and its first journey fails on its first screen check (#1072).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
Co-authored-by: Abir Abbas <abirabbas1998@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* session: task commits are authored by the bot account, not codeaf@localhost
The author codeaf stamped on the commits it lands was `codeaf <codeaf@localhost>`, which no GitHub account can link, so every branch codeaf landed failed the CLA check. It now writes `codeaf <agentfield-bot@users.noreply.github.com>` - the identity the Co-Authored-By trailer already used - and keeps `codeaf@localhost` and `aforge@localhost` recognised as legacy by taskCommitIdentity.
GLM 5.3's review caught an unmarked retired name in permissions.md that reddened the namelaw gate, and seven stale test fixtures; both fixed. Laws gate, session, exec and cmd are green.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* README: show the pinned-version install line the release test requires (#1103)
* README: show the pinned-version install line the release test requires
The Install rewrite dropped the VERSION=<tag> pin example, and
TestPublishedPinExamplesGiveVersionToBash reads every published install
surface for `| VERSION=` because `VERSION=<tag> curl ...` is an easy
mistake to copy — it sets the variable for curl instead of the install
script. The pin goes back inline on the same host the section already
uses, with the releases page still linked for tags.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* docs: the change entry for the README pin example
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
---------
Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: anonymous usage counts, off with CODEAF_TELEMETRY=off (#1095)
* telemetry: the package behind anonymous usage counting, per the wire contract
Four typed events (first_run, session_started, session_ended, fault) with the
contract's allowlisted, bucketed props; the opt-out ladder with its off
reasons; a hashed install identity at 0700/0600; a fault fingerprint over
codeaf function names only; a JSON-lines spool with a deadline-bounded flush
of up to 50 events per POST, 7-day age drops and a 1000-line cap; the notice
constant with NoticeShown/MarkNoticeShown gating the flush; and Show() for a
future codeaf telemetry show.
A library only: nothing in cmd/codeaf, internal/session or internal/config
reads it yet.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: tests, doc, and contract fixes for the usage-count package
Adds the package's tests — bucketing edges, the opt-out ladder, install
identity, the notice, fingerprinting, the spool against an httptest relay
(cap, age drop, 50-per-POST splitting, a hard deadline against a hanging
server, silence on failure) and the privacy law that no sentinel string
reaches the wire. docs/TELEMETRY.md documents the notice, what is sent and
how to turn it off, with a test that fails if the doc's property table
drifts from the Go allowlist.
Fixes four drifts from the wire contract found running those tests: the
<1m duration bucket was missing, the fingerprint's argument stripping cut
too much, the rc channel suffix must be a single integer, and under go
test a config-off rung outranks the test rung in the reason reported.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: fix review defects 1-8 with tests
Fingerprint stability (last-( cut, .go:/main./created-by frame rules),
counted-batch flush, guarded and multi-process-safe spool, BucketDuration
edges, Configure-gated write paths, O_EXCL install id, install.json
preservation, buildinfo.Dirty accessor.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* installer: record the install locally and print the telemetry notice
Following the telemetry wire contract: a successful install now writes
telemetry/install.json under the state root (dir 0700, file 0600) with
the install method, channel and UTC timestamp, leaves any existing
install_id alone, and makes no request the download steps did not
already make. At the very end the installer prints the contract's
notice to stderr after one blank line, or one line saying telemetry is
off when CODEAF_TELEMETRY/DO_NOT_TRACK opts out. README gains a plain
Telemetry section pointing at docs/TELEMETRY.md, and a new
test/installer-telemetry.sh proves the marker, the notice and the
opt-out without a network.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* installer: four review corrections to the telemetry commit
The review of 71ff95a6b found four things. Revert the one line that
changed `if [[ -z "${TAG:-}" ]]; then` back to `${TAG:-}`: under
set -u an unset TAG must reach api_problem, not crash. In
write_install_marker the channel lands in JSON verbatim and CHANNEL
can come from the environment, so only stable, rc, staging or dev is
recorded and anything else becomes "unknown" — with test cases for a
valid channel and for we"ird, both asserting the marker parses
(python3 -m json.tool, or jq, else a strict channel check). Fence the
README Telemetry notice in a ```text block so Markdown keeps its
alignment, wording byte for byte. Clear the two shellcheck findings in
test/installer-telemetry.sh with one block disable for SC2016/SC2034 —
ok() evals those strings, so the quoting is deliberate — and export
CODEAF_TELEMETRY/DO_NOT_TRACK where a subshell needs them, without
weakening any assertion.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* release-downloads: daily PostHog report of public GitHub release download counts
A scheduled workflow reads the repository's releases from the public GitHub
API and sends one codeaf:release_downloads event per binary asset
(codeaf-<os>-<arch>[.exe]) — sidecars like checksums.txt are not reported.
Each event carries release_tag, channel (stable or the prerelease suffix),
prerelease, os, arch, the cumulative download_count and the UTC
snapshot_date; the event id is derived from tag, asset and date, so a
same-day rerun deduplicates instead of counting twice. No code in the
binary; counts come only from public release data.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* release-downloads: tests cover the workflow, docs and pagination
The dry-run unittests now also assert the identifiers the wire spec spells
out where the script and the workflow spell them: the schedule, dispatch,
contents-read permissions, built-in token, project-key secret and host
variable in .github/workflows/release-downloads.yml, the public-data
paragraph in docs/rules/promotion.md, stdlib-only imports, pagination
across API pages, the host override and the /batch/ endpoint, sidecar
skipping, draft skipping, and the channel words stable, rc, dev and
staging.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* release-downloads: four review corrections to the script
Channel detection now follows the tag grammar in
cmd/codeaf-release/version.go: stable, rc, dev and staging tags match
their four patterns and anything else reports "unknown", so
dev-20260917-09299019bcdc is no longer mislabelled "stable".
--dry-run works without CODEAF_POSTHOG_PROJECT_KEY, the local and test
path: the batch prints with api_key "<unset>" and exits 0, and only the
sending path stops with the notice.
Every event carries "$geoip_disable": true next to
"$process_person_profile": false, since the sender is a CI runner whose
location is meaningless. The module docstring now names
release-downloads.yml, the file that exists.
The fixture holds one tag of each shape plus an unrecognised one, and
the tests assert the channel for each, including the two real dev and
staging tags.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* release-downloads: test runs on Python 3.9 too
ScriptSourceTest read sys.stdlib_module_names unguarded; the attribute
arrived in Python 3.10, so the suite errored on macOS stock python3
(3.9.6). Guarded with getattr so the pinned import-set check stands on
its own where the attribute is absent; 32 tests pass on 3.9, 3.10 and
3.14.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* installer telemetry: the notice is read from docs/TELEMETRY.md
The test read .telemetry-contract.md, a working note that is not in the
repository and never will be, so it aborted with "telemetry contract is
missing" in a clean checkout. It now extracts the fenced block under
"## The notice" in docs/TELEMETRY.md — the same bytes as the Notice
constant in internal/telemetry/notice.go — and holds the installer's
TELEMETRY_NOTICE to it as before; a new assertion holds the README's
telemetry fence to it too, byte for byte, so the invariant the suite
existed to guard now has its third leg.
Comments in scripts/install.sh, internal/telemetry/telemetry.go and this
test now name docs/TELEMETRY.md as the source of the notice.
No Go code changed and no Go tests were run. shellcheck is clean; the
suite's 33 passing assertions include the two new notice checks, and the
same two stat(1)-related assertions that already failed on this GNU
machine before the change still fail with identical output.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* release-downloads: the download-counts paragraph lives in docs/TELEMETRY.md
docs/rules/promotion.md was the only home the paragraph had, and it came
with a fallback pinning the branch to the state before the telemetry
doc existed. The paragraph moves, byte for byte, into docs/TELEMETRY.md
as a final "## Download counts" section beside the rest of the telemetry
story, and promotion.md returns to its origin/dev content, so this
branch now touches no release docs.
test_no_telemetry_doc_on_this_branch asserted docs/TELEMETRY.md did not
exist and is deleted. The two tests that read the paragraph read it
where it now lives: both require a "## Download counts" section in
docs/TELEMETRY.md naming .github/workflows/release-downloads.yml,
scripts/release_downloads.py and the checksums.txt sidecar, and the
promotion.md fallback is gone.
No Go code changed and no Go tests were run; the property table in
docs/TELEMETRY.md is untouched. The suite passes: 31 tests, OK.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* installer telemetry: the mode check asks GNU stat first
On Linux `stat -f` succeeds and reports the filesystem, so the BSD-first
order never reached the GNU form and both permission checks failed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CqfhxLrrBNQxwPNvEgoBGR
* telemetry: refuse to send to the production relay from a test binary
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: testHome points the endpoint at a dead loopback
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: the orphan-adoption test names the dead relay it now gets
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: a test pins that no test binary reaches the production relay
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: three tests pin the test-binary relay refusal
Each asserts through real calls, not a re-implemented effect: the
newRelay override lands after testHome and a flush reaches that
recorder; a default-endpoint flush is refused like a dead relay
(zero round trips, event still spooled); forcing the ladder on
cannot reopen the path.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: allocation-free session counters
Snapshot returns the SessionStats fields the SessionEnded constructor
takes, so the wiring hands the struct straight over. Cost is stored as
integer micro-dollars and divided back once, in Snapshot. Count* never
ask whether telemetry is enabled and never allocate.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: gofmt the counters test
One alignment fix in the many-goroutine test; no behaviour change.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* config: telemetry setting row (CODEAF_TELEMETRY)
Key "telemetry", on|off, default on, env pin CODEAF_TELEMETRY, in the
interface group beside the history row. TelemetryAtIn walks the ladder —
pin, project file, profile config, default — and TelemetryOffReason
answers whether config turned the pipe off and names which rung did.
The row sits in ProjectKeys so a repository may answer for itself.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* cmd/codeaf: the telemetry command, and the setting it writes
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* cmd/codeaf: session lifecycle events at execute (work in progress)
Configure, notice, first_run and session_started at the start of every session
command, session_ended and a one-second flush at its exit. The end event does
not yet carry the session counters.
* provider: count answered model calls and their spend at the log door
* session: count sealed turns and executed tool calls
* cmd/codeaf: the session-ended event carries the run's counters
telemetryEnd builds the end event from telemetry.Snapshot so turns, model
calls, tool calls and cost reach the spool; the stop-reason switch becomes
a map over the exit ladder; and both lifecycle constructors are gated on
the ladder being on so a disabled run touches no state.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* cmd/codeaf: the counters test says the tally is process-wide
The exact turn, call and cost assertions hold for one run of the package; a
repeated run counts into the same atomic tally again.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* guard: a fault hook Recover calls, for a reporter above this package
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* cmd/codeaf: the fault event at both crash sites, off the current session
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* cmd/codeaf: a test that the crash site spools a fault and not the panic text
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* docs: finish the anonymous usage counts contract and add the 1095 changelog entry
* guard: the fault hook sits behind an atomic pointer
A goroutine recovering a panic read the hook while a test on another
goroutine wrote it, which the race detector reported. SetOnFault stores it
once; Recover loads it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* cmd/codeaf: a task's interrupt word comes from the signal, not the cancelled context
stopSignals cancels the signal context at the end of every errand, so the
flag read from its Err said interrupted for a run that finished cleanly.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* tui3, installer: the telemetry row has a tab, and a custom install writes no marker
TestEverySettingRowHasATab wants every registry row on the settings panel.
TestCustomInstallOutsideTheStateRootDoesNotRunAdoption wants an install
outside the state root to leave the login's state folders alone, so the
install marker is written only when the root exists or the install is in it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* cmd/codeaf: the counters test zeroes the process tally first
Other tests in the package drive model and tool calls through the doors
that count, so the exact bands held only when the test ran alone.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* cmd/codeaf: the version test drives the telemetry lifecycle, not execute
execute starts writers under the state root that outlive the test, and the
temp dir's cleanup raced them. The lifecycle alone is what the test pins.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* cmd/codeaf: gofmt the lifecycle test
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* session: the carry-ladder fixtures wait for the mark's drawing, not race the scheduler (#1104)
* session: the carry-ladder fixtures wait for the mark's drawing, not race the scheduler
TestASuccessfulHandoffJournalsTheRungThatSuppliedTheBrief failed once in a full
make check at line 118: the worker's brief was the running model's draft, not
the mastermind's written handoff.
THE CAUSE IS NOT A STOLEN STEP. Reproduced under load (60 CPU burners, the
fixture run 1500 times), every request the fixture makes is either the turn's
own or one the aside answers: the queue carries only `round`, `draft` and
`writer`, and the errands beside the turn (title, namer, the mark's drawing)
never touch it. What moves is the ROUND COUNT — 41 to 54 across the runs —
because the mark's drawing is a sidecar (sidecar.go) whose landing the scheduler
places, and the turn is never held for it. On a busy machine the turn runs its
rounds off faster than the drawing's goroutine is scheduled onto a core, the gap
between the net firing and the drawing landing outruns the slack the script
carries ([checkpointSlack] says so in its own words), the writer's ask lands
PAST the end of the 53-step script, the scripted completer answers it with its
past-the-end line `(unscripted)` — which is not prose — the handoff rung reads
degenerate, and the carry ladder falls onto the draft. That is #392 exactly, one
mechanism along.
WHAT FIXES IT IS WAITING FOR THE READING. checkpointAgent now puts a watch on
the turn's own context ([watchReadings]) and the handover fixtures submit
through [watchedContext], so [answerWhenQuiet] holds each request that carries
the belt until every reading beside it has landed — the order a real turn has,
where a real model spends seconds on a step and the small readings land inside
it. The gap is then one boundary whatever else the machine is doing, and a
script long enough to cross the mark is long enough.
THE REGRESSION TEST holds the drawing back by a fixed wall time — standing in
for a scheduler that does not reach it in time — and insists on the behaviour:
the turn does not spend its script racing the drawing, and the writer's rung
still supplies the brief. It fails without the watch (the turn makes 54 rounds)
and passes with it.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* docs: the change entry for the carry-ladder drawing race
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
---------
Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
* docs: the install proxy is live, and the manual says so (#1076)
* docs: the install proxy is live, and the manual says so
`https://agentfield.ai/get/codeaf` has served `scripts/install.sh` since
2026-09-16, the day the repository went public, so the compiled-in manual
and docs/GUIDE.md stop saying it is "not serving yet" and stop calling the
repository private. The proxied line goes first, as the README already has
it; the raw GitHub line is described as the script under it. Both pages say
to pipe into `bash`, not `sh`, because the script uses pipefail and `[[ ]]`
and dash rejects them, and both state the channel path (`/dev`, `/staging`,
`/rc`) beside the flags. The manual also says what the proxy refuses: a
script without its channel line exactly once, or a body that is not a shell
script, is a 502 rather than the wrong thing.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: entry for #1076
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* A launch says a newer codeaf is out, and /update installs it and restarts (#1060)
* The release-tag grammar has one home, and it is internal/update
Stable, rc, dev and staging tags are parsed, compared and bumped in exactly one
place now. cmd/codeaf-release keeps its next, kind and prune behaviour and its
tests unchanged; it reads the grammar from the new package rather than owning a
second copy of it.
A second parser is the thing that drifts: the updater about to land needs the
same answer to "is this tag newer than that one" that the release tool gives,
and one source of truth is the only way they cannot disagree.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* internal/update: look up a release, check it, and replace this binary with it
The launch check answers only for a build that could sensibly be behind: a
stable tag, or a release candidate whose stable line has since been published.
A dev or staging build, a make build sha and an unstamped binary make no request
at all, because a channel build is deliberately newer than stable and a source
build belongs to whoever built it. The answer is cached for a day beside the
profile, and every failure is silence.
The install downloads into the target's own directory, matches the sha256 from
checksums.txt, and only then renames over the running file, so a refused
download, a wrong checksum or an unwritable directory all leave the original
binary exactly where it was and no temp file behind. The API token never leaves
the API host: the redirect policy strips it the moment a redirect changes host,
which Go does not do on its own for another port or a subdomain. Windows has no
atomic rename over a running image, so it goes through ReplaceFileW and puts the
original back when Windows reports the one failure that moves it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* tui3: a launch says a newer codeaf is out, and /update installs it
The launch line is one dim transcript note carrying both versions, /update, and
the curl line, because the command is what the owner asked to be given. It
arrives as a command rather than an opening read, so the first frame is drawn
before the network is asked anything and a slow or refused answer draws nothing.
/update — /upgrade is the same road — names the tag, then the checksum and where
it landed, then quits with a restart plan for the door to carry out. Already
newest says so and stays. It refuses while a turn or a task is running, and once
it has started, one shared guard keeps a second /update and a new turn from
beginning underneath it: the restart must never quit on top of live work, and
the home page's Enter roads go through the same guard chat's does.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* codeaf update, and the door that restarts the same conversation
codeaf update --check prints one line and exits 0 when this release is newest,
3 when a newer one exists, 1 when it could not ask. Without --check it installs
stable, or whatever --rc, --dev, --staging or --version names, choosing a
channel build by its own publish time the way the installer does. A binary built
from source refuses in place and names its path rather than replacing something
a developer is holding.
The restart happens here and not inside Bubble Tea: the surface fills a slot,
the door reads it once the frame is down and the terminal is back, and then
execs the new binary with this launch's own arguments plus --session pointing at
this transcript, so the conversation reopens where it was. A linked-local engine
is asked to retire only after the surface has detached, and it still refuses
while another window or any live work is there.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* remote: a window that says it is leaving needs no torn-link grace
The twenty-second grace exists for a terminal that was killed without saying so,
and a deliberate detach is the opposite of that — the window has just announced
its departure. Carrying the grace anyway left a cleanly closed window looking
attached for two more call deadlines, which kept a freshly installed codeaf
waiting behind the engine the old one had already left.
It clears only once the last view is gone. Turns, tasks, unanswered questions,
other views and live work all still refuse retirement, and a refusal still never
stops the work it protects.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* The installer and the updater agree on what a channel tag looks like
Two roads now install codeaf, and they were reading the same release list by
different rules: the shell accepted any dev-* or staging-* tag and semver parts
with leading zeroes, while internal/update accepts only the shapes the release
workflow actually publishes. A malformed tag newer than a real one would send
the two roads to different builds.
One helper carries the grammar to both channel selection and the line that names
the channel, and an unrecognised tag for the asked-for channel now says so
instead of installing whatever came back. The publish-time ordering #1056 added
is untouched: only which candidates are eligible changed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* The manual stops saying that nothing self-updates
That sentence was true until this change and is now the opposite of true, so it
goes, and a section written in the words people bring takes its place: is there
a newer version, how do I update codeaf, why does it say this every time I
start. It states who gets the launch line and who never does, the opt-out
variable, the day the cached answer lasts, the shell exit codes, and both
refusals — a build made from source and an executable nobody may write.
The command table names /update and /upgrade with the argument they take. Four
probes reach the new section, and the remote page keeps its own asker's words in
its heading so the new section cannot take that question from it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs/changes: the update check and /update, for #1060
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* update: --check answers for the channel it was asked about, and a newer build is never downgraded
Two things a hand verification caught. --check parsed whatever tag it had
selected with the stable grammar alone, so --dev, --staging and --rc could
never be "newer" and every one of them answered "you are on the newest codeaf"
and exited 0 while a newer build sat in the list. The check now keeps its
channel all the way through the decision and always names the tag it is talking
about: stable and rc compare as semver, a dev or staging tag is the same tag or
a different one, and --version is equal or it is not.
And a build AHEAD of the newest stable was quietly installed backwards — the
check said newest, the install downgraded it. Both roads refuse now, naming both
versions and the deliberate way past:
this codeaf is v0.3.0, ahead of the newest stable v0.2.0 — pass --version
v0.2.0 to install it anyway
An explicit tag IS that deliberate road, so --version and /update <tag> still
install exactly what was named.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* update: a failure names the asset and the status, and ends with the curl line
A download that failed printed the whole fallback URL, which put the retired
product name on somebody's screen. The line names the asset it asked for and the
status it got back, and nothing about which repository answered — the
compatibility attempts still happen, they are just not the person's business.
Every terminal failure now ends with the curl line, which D9 asked for and the
download path had been missing.
The / list declared no argument for /update while the command page documented
one, so the list gains the second row the way /cache has one. The manual section
now says what the code does about a build ahead of the newest stable, where it
had said such a build "gets nothing" — true of the launch line, and false of the
install until this wave.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* update: the curl line is agentfield.ai/get/codeaf, the supported road
The launch line, the refusals and the terminal door offered the raw
GitHub address of scripts/install.sh. The repository is public and
agentfield.ai/get/codeaf has served that script from main since
2026-09-16, so the constant now spells the supported line, the manual's
update section names it in place of "the curl line below", and the
change entry says so. Asked for on the pull request by Santosh.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* a run's own scratch note no longer fails the delivery gate (#1096)
* codeaf: a run's own note is offered outside the tree it is judged in
leafOutputHint invited a job root to write its overflow document at a
workspace-relative name (exec.SuggestPathFor's task-2-x1-toolchain-checks.md
shape), so a run working in a person's directory left that note untracked at
the root of their working tree. The delivery gate holds the run's record —
the artifact registry, joined by jobArtifacts, plus the delivered tree —
against the request, read the note as part of what was handed over, and
refused the delivery; the run then ended incomplete over complete work.
There is no separate mechanical clean-tree check to exempt, so the fix is
the writer's: where the workspace belongs to the person, the root's file
invitation points at the run's scratch beside its recorders and job logs,
and the message keeps carrying the deliverable.
* codeaf: a person's own file still joins the record the gate reads
TestARootLeafInAPersonsDirectoryPutsItsNotesInScratch baselined the tree
after the note was already written, so its landing read could never have
observed anything: the record stayed empty because of the ordering, not
because of the address. The baseline now happens first, in the executor's
own order, and a hint that ever points into the tree again fails on the
observation, not only on the spelling.
And the other half of the law is pinned down: a file that turns up in the
person's tree while the leaf runs — even at a name wearing the run's own
task-<n>-<slug>.md shape — is still observed and still lands in the record
the delivery gate is held to. Only the run's own note moved; nothing else
about what the tree says was loosened.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* docs: the change note for the root's overflow file moving out of the tree
---------
Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
* chat: the wordmark is drawn CodeAF, four rows, capitals on the d's cap line (#1106)
`┌─┐ / ├─┤ / └─┘` is not an `a`, it is two closed bowls of equal size
stacked on each other, and two equal closed bowls are an `8`. That was
the second-to-last glyph of the product's own name on the first screen
of every fresh install. The owner's answer is to have the two letters
at the end stand up out of the word as capitals: `A` is an apex, a
crossbar and two legs; `F` is the one letter whose case is told by its
arms alone, so its top arm is the longer one.
A CAPITAL'S TOP IS THE ASCENDER'S TOP, and three rows of box-drawing
could not give it that. A bar is drawn at the middle of its cell and a
stem reaches the cell's edge, so the `d` stood half a row over any
capital however it was formed — and a stem in the bottom row hung half
a row under the bowls' baseline the same way. The fourth row is that
half a row made whole: the x-height letters live in the lower three and
leave the top row blank; the capitals and the `d`'s ascender start in
the top row, the ascender as the half-stroke `╷` so its top is the
capitals' bar; and every stem that ends on the baseline ends as `╵`,
which stops where `└─┘` does. A `│` in the bottom row is a descender
and nothing else.
THE WORD IS SPELLED `codeaf` AND DRAWN `CodeAF`. `product` is unchanged,
the glyph table is still keyed by its lowercase letters, and a terminal
that cannot draw boxes still gets the word `codeaf`.
The greeting's centring test read the unit's left edge off the
wordmark's first row, which is now the cap line the x-height letters
leave blank; it reads the second row. The one manual page that draws
the wordmark had been drawing the retired `aforge` letterforms under
the label "the codeaf wordmark" — the name law walks text and cannot
see a name spelled in box-drawing — and draws the shipped forms now.
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* A real release download finishes: the 3-second check clock no longer covers the asset (#1110)
* update: a release download gets its own clock, not the check's
The release client was built as http.Client{Timeout: 3s} because three seconds
is right for the launch check, and Go's Client.Timeout covers the WHOLE
exchange including every body byte. The same client then downloaded the
release asset, so a 57 MB download on a healthy link — about eight seconds
here — was cut off three seconds in and a person read `read the release
response: context deadline exceeded`.
Client.Timeout is gone. The transport bounds only what has made no progress: a
5 s dial, a 5 s TLS handshake, a 10 s wait for response headers. Every call now
takes its deadline from its context. The launch notice and `--check` share the
one CheckTimeout constant, install metadata gets 10 s per request, and the
asset gets a 30-second no-byte stall window plus a 15-minute ceiling — a dead
link fails with a sentence, a slow one finishes.
No Go deadline text reaches a person. A stall says `downloading
codeaf-linux-amd64 stalled — no bytes for 30 s`, the ceiling says `took longer
than 15 minutes`, and late headers say `did not start arriving within 10 s`.
The stall window, the ceiling and the metadata window are injectable, so the
tests prove the clocks with real slow, silent and trickling servers rather than
waiting out the shipped ones.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* update: both doors read the one check constant
`codeaf update` and the chat surface each spelled `3*time.Second` when they
built the release client, which is how a figure meant for one small request
came to govern an install. Both now pass update.CheckTimeout, and the three
seconds live in exactly one place.
The terminal's `--check` takes the client's Check, which is the whole-exchange
check deadline; a plain `codeaf update` keeps Select, so the metadata requests
an install makes get the ten seconds they need.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: the update download's own clock (#1110)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: v0.2.1 rolled up into CHANGELOG.md (#1113)
The 33 entries that landed on dev since the v0.2.0 roll-up are the ## v0.2.1 section of CHANGELOG.md now; docs/changes/unreleased/ keeps only this pull request's own entry. Stable v0.2.1 takes its notes from that section.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* README: telemetry folds under Docs (#1115)
The 23-line Telemetry section between Install and the product tour becomes one collapsed block at the end of Docs: a plain summary line, the notice verbatim, one sentence and the link to docs/TELEMETRY.md. The notice block is unchanged, so it still matches the binary, the installer and docs/TELEMETRY.md. Replaces #1112.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NoeSVN8nqmwNVRXExgoUNN
* santos/dev lands on dev: crew family, Pareto crewing, the Model Pool, custom connections (#1194)
Lands the integration branch santos/dev (#1108, head 6db5125b2, 152 commits over dev) on dev as one squash, plus two fixes that kept its touched-packages job red: the pool start-up test empties the CI word it is not about (649bb4bfd), and a zombie leader no longer keeps a job's process group alive on Linux, which had delayed every finished background job by the two-second termination grace since #1155 (053e6a90f). #1108 carries the full account; the 94 change entries under docs/changes/unreleased/ are the per-change record.
The commits folded in, oldest first:
5c413ef7b Keep archived evidence readable while tasks finish
3705a0cfe Document recovery evidence retrieval change
7834cc7d0 tui3, manual: a question's own answer box answers to the whole caret vocabulary
99d66e98c task: Add open/all source toggle to crew config
c1e4cb57f docs: the change entry for the crew model family toggle
e63b43927 crew: round-1 review fixes
304a5a223 crew: round-2 review fix
65477c0c5 task: Add open/all selector to /crew TUI picker
9189ef764 Merge branch 'task/add-open-all-selector-to-crew-tu-9e8cc0' into feat/crew-open-all-toggle
ba9c12d61 crew: reconcile the picker onto config's source helpers
ea05bc0f5 crew: a chosen family counts as an answered crew
e1a037e0a Merge remote-tracking branch 'origin/dev' into feat/crew-open-all-toggle
f6c2924a7 crew: the open table takes the picks we landed on
eff44b542 docs: the change entry carries the open-table move and the family gate
71ce9bec0 crew: the family reaches the fallback, the settings skin, and the row's line
b8ca5f513 crew: round-1 review fixes on the new table
8db5708ef crew: round-2 review fixes
ce9759ef4 crew: round-3 review fixes
956e1f514 crew: round-4 review fixes
37ad27f4e crew: fixes from the first Opus round
6ffb95813 crew: the fixes from the Opus confirmation round
72b027436 crew: the comments the atomic write left behind
70d0e205b crew: round-four fixes from the Opus review
234300e37 Merge branch 'dev' into feat/crew-open-all-toggle
894292f28 crew: round-five fixes from the Opus review
fba77f92d An answered landing carries its answer's fate when it is raised again, and an in-flight settle holds the question down (#1077)
e69445058 Changelog entry for the landing-answer fate (#1086)
64ab7eae0 crew: round-six fixes from the Opus review
070016419 crew: round-seven fixes from the Opus review
af09aa852 The review round's four findings: claim ownership, decider changes, recordable answers, plain words
c24af0248 crew: round-eight fixes from the Opus review
289d372b9 The tests the landing's answer carries: fate, hold-down, redraw, claim doors
7e38346a9 The take-down comes before every mint, and the tui3 walk reads the newest card
dbe1be03e The review rounds' last word: the release owns its claim, and the docs say what the code does
4cc4945a7 The Opus review: a release owns its generation, and every failed round still says its word
a5cce0dde The done card says who is deciding, so the clause is a duplication, not the fact
6bd276e6c Merge fix/1077-landing-reraise into santos/dev
271016938 Merge feat/crew-open-all-toggle into santos/dev
b459399d3 Merge fix/question-answer-box-caret-keys into santos/dev
a38492026 Merge codex/recovery-evidence into santos/dev
dc22e6461 cmd/codeaf: the role-door tests read the shipped mastermind instead of a copy of it
39f528f70 release: the pin-example check reads the guide the examples moved to
6439d3cb8 session, tui3: gofmt the three files santos/dev merged unformatted
854037967 tui3: a question's answer box kills to the end of the line on ctrl+k
d93ec61ea session: the late-attach proposal test holds the work until the replay is read
a81ead4de session: the landing-fate tests read today's clock instead of a fixed date
8fe4fff38 provider: the retry-avoid list rides the call's context into the knobs
a266da3e2 provider: the retry-avoid veto narrows the wire through one field law
197d89334 exec: a node retry asks the router to avoid the lanes that failed it
2d02cc0b9 provider: the set-servable law's doc comment keeps its paragraph break
e1d0e7524 exec: the retry test names its helper and spells its wall in time units
e7d65a517 docs: the change note for the retry that avoids the failed upstream
11decbd92 Merge fix/provider-failover into santos/dev
c099a51c2 Merge dev into santos/dev
e47d92bde provider, exec: the lane a failure names is a wire fact provider reads (#1105)
396be97be Merge dev into santos/dev
3b97f50c3 Merge dev into santos/dev
ea3b5c9a0 telemetry: the send path drops events that cannot name their version
573b288e4 cmd/codeaf: keep smoke runs from sending usage counts
e8d627c6b docs: the change note for the usage-count audit fixes
11bec8d80 chat: a hosted session's usage counts are read off the events it receives
b9d75b39e chat: the hosted-count tee is tested against the tally it must produce
39fa08d3d telemetry: stamp a version in the lifecycle tests
681e2adf1 chat: count the hosted boot agent once, and conversations opened beside
825ef2c41 connect, settings: named, multiple, switchable custom connections (#1092)
f4d3f9a1a Merge branch 'dev' into fix/telemetry-audit
76fec37e3 ci: the Model Pool mirror workflow and the signature check it runs
2fb296bf1 crew: Pareto crewing, the learned picker and the Model Pool (#1093)
a065ebb1b Merge remote-tracking branch 'origin/dev' into santos/dev
80ac250a0 Merge remote-tracking branch 'origin/feat/pool-mirror-workflow' into santos/dev
6092393ab Merge remote-tracking branch 'origin/fix/telemetry-audit' into santos/dev
ef808dda4 session: a decision card under --yolo takes its default (#1117)
70a9e1f6e session: a task's thread stops its parts before it closes, and a machinery cut says so (#1118)
c4df8f364 crew: an auto seat's rung names the pick that ran, once, for both doors (#1119)
a9fcf9bc8 crew: a bare auto row under picked from = catalog reads the catalog's figures alone (#1120)
13be0dce4 relay: accept the exec and run doors, not only task and do (#1121)
90f29aec1 changes: name the #1120 note by its PR and stamp the pr field
0b77926ca do: seat from the settings the run will use (#1122)
32148d87d changes: stamp pr: 1120 on the #1120 note
113ed628e pool: a launch's start-up errands stop when the process closes (#1124)
6c98ddca3 verify, codeaf: a launch compiles fewer patterns and a surface holds fewer Ps (#1125)
50fe6a3e4 pool: the min_installs floor counts installs on the client (#1127)
076cde8ae relay: fold a resubmitted row once by its nonce (#1128)
8339ae71b relay: carry the acceptable metric beside role_quality (#1129)
0367c441b outbox: a refused row leaves the outbox and the rest of its batch is sent (#1130)
09aecd2f1 relay: the index holds only the cells that meet the min_installs floor (#1131)
ae7c05dcd outbox: a Send compacts the file to the rows it still holds (#1133)
9e24f72d8 pool: the errand tracker's critical sections unlock from a defer (#1134)
358a569aa relay: fold a submit batch with one read and one write per distinct cell and day (#1136)
a1d2eb1f7 pool: judge landed-but-unjudged runs on the next chat start (#1132)
3c6722859 verify: take the finished-tree check at a project cloned into a subdirectory (#1135)
263625b63 exec: a headless run leaves a pending judge record at its tail (#1137)
8be373d39 run: the headless task door leaves a pending judge record (#1138)
a336b246e do: leave a pending landing for the Model Pool's judge (#1139)
8820a5659 cmd/codeaf: one readPendingRows test helper, not two (#1140)
49760fb45 pool: show and verify print both metrics the index carries (#1141)
6eaeb25c9 pool: status shows the pending judge records and the last sweep (#1142)
7c00b5f2c codeaf: a test's crash fixture stays in a profile the test owns (#1145)
fc2eb357a manual: the status row's ledger is the tree's, not the conversation's (#1143)
a06b53a91 test: pin the delivery gate over a grown job root (#1147)
7231347eb resident: the wall refuses a first replan round it cannot hold (#1144)
5e257557f cmd/codeaf: the package's test floor clears a profile the environment named
4dd1c562f Revert "cmd/codeaf: the package's test floor clears a profile the environment named"
9075f863c pool: the seed index is regenerated from the relay by seedgen (#1148)
a5c44f3d2 pool: show --cells lists the held index's cells with installs and dims (#1149)
825996739 cmd/codeaf: the package test floor clears a profile the environment named (#1150)
81568aa82 session: report gitignored build products a run leaves, without gating on them (#1152)
da4910593 internal/tui3: the opening hint test owns its profile and pins both doors
72de3bca7 docs/changes: #1151 — the opening hint test owns its profile
499083d1c Revert "docs/changes: #1151 — the opening hint test owns its profile"
beb31ecf7 Revert "internal/tui3: the opening hint test owns its profile and pins both doors"
25b8b7dea version: an unstamped binary names the condition, not a Makefile target (#1151)
c833b423a pool: a dropped row keeps the relay's reason and status shows it (#1154)
cbb7d6d9e processgroup: verify a job group's identity before signalling it (#1155)
efe498ed0 internal/tui3: the opening hint test owns its profile and pins both doors (#1153)
17b3b0e40 do: a continuation continues the plan it has instead of re-planning (#1156)
22cf3ce17 changes: correct the #1155 and #1156 notes' pr fields (#1157)
8e85b0fe7 cmd/codeaf: a surface runs under a soft memory limit drawn from the machine (#1158)
ef1e92756 task: status row accounting (#1159)
44f572e26 pool: status's index line says what this run's fetch did to the cache (#1161)
3600fc9a5 pool: the pool's copy of a seat's id is the bare vendor/id (#1163)
a2ebd1397 cmd/codeaf: no test can push pool rows to the default relay (#1164)
4fb7f0546 docs: the road a chat door bash push took under --yolo (#1160)
69219a1e1 cmd/codeaf: the soft memory limit is the smallest real bound, not the host s memory (#1162)
2b155b4b4 relay: bound judge severity, clamp adjusted scores, publish mean and sd on one scale (#1165)
2fb55324a relay: purge fixture vendors and refuse them at the door (#1167)
57504187a exec: a job's shell cannot reach the tmux server hosting codeaf (#1166)
eb7b46559 internal/session: an unattended run may not move a branch it did not create (#1168)
80f770639 pool: status says the identity, the judged total and that nothing has landed (#1169)
1cb7333fa exec: an exec run's worker spend reaches the usage ledger (#1170)
96bb9402e changes: the #1169 note's title parses and reads as one line (#1172)
627236d95 config: the task door honors a stored crew word, and a pin survives the learned pick (#1171)
593092be6 internal/tui3: a test may not read a profile it did not create (#1173)
ad8be1ed7 session: a landing card under --yolo takes its default instead of parking the run (#1174)
03d49a678 gitignore: the .furrow ids the engine writes into a workspace (#1175)
46edbdd32 internal/tui3: gofmt the profile-law helpers from #1173 (#1176)
3179e3611 relay: ALLOWED_VENDORS names the catalog's vendors and codeaf (#1177)
397a145a6 docs: why a settled /task leaves commits on task/<slug>, not the worktree branch (#1178)
915ff3a76 pool: regenerate the seed index from the relay's first clean publish (#1180)
d9b42430f cmd/codeaf: the model warm stops when the process closes (#1179)
bd2dcf334 session: the auditor's calls say they are the auditor's and which node they check (#1181)
c6ed47c5a task: json unverified branch (#1182)
360352ad4 session: a settle turn runs under the checker's own bound, not the run's wall (#1183)
814e1af0e session: the tasks text and record line name a failed/unverified node's kept branch and verdict (#1184)
7c25a26d9 internal/session: the identical-effects test stops riding the turn guard (#1185)
6e7d0ed44 cmd/codeaf: exec and run envelopes name a non-verified node's kept branch and verdict (#1186)
f4079d716 session: bound a worker's park on a promoted command (#1187)
994689fe7 docs: the model pool runbook names the Workers Paid plan and what it costs (#1188)
c315be13e docs: the runbook's plan line says metered, not capped, and nothing more (#1189)
2e80c60d8 internal/tui3: the status word says working while a task subtree turns (#1191)
99363ca8f session: bound a job subtree's CPU and process count (#1190)
6db5125b2 docs: what the audit check seat can execute, and where that boundary is set (#1192)
649bb4bfd cmd/codeaf: the pool start-up test empties the CI word it is not about
053e6a90f processgroup: a zombie leader does not keep a job's group alive
b4e66f515 docs/changes: the entry for #1194
Co-Authored-By: Santosh kumar <29346072+santoshkumarradha@users.noreply.github.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* ci: Model Pool mirror workflow (signed index onto the model-pool branch) (#1116)
* ci: the Model Pool mirror workflow and the signature check it runs
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs: the change entry for the Model Pool mirror workflow
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: santoshkumarradha <eng@agentfield.ai>
* chat: the unconnected custom row on /connect keeps its vendored name (#1195)
modelConnectionStatus renamed every custom-id row to the connection's Written word, and the catalog template's Written is the bare id, so a person who had connected nothing yet saw `custom` where the manual, the README and #1107 say `Custom OpenAI-compatible API`. Only a connected instance is called what the person called it now; the contract test draws both rows and is red without the fix. Found verifying the staging build of #1194.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: v0.3.0 rolled up into CHANGELOG.md (#1196)
95 loose entries — the crew family and Pareto crewing, the Model Pool and its relay, custom connections, the telemetry audit, the update door's download clock, and the fixes that followed — become the `## v0.3.0` section the stable release reads its notes from.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* ci: a changed directory in a nested module is not a package of the root module (#1332)
The touched-packages job and the Makefile's test-touched target both derived the test set as every directory holding a changed .go file, and handed a directory under its own go.mod to go test, which answers "main module does not contain package" and fails the job as a setup error. Both walks now stop at the first go.mod above the directory and skip nested modules, so the bench fixtures under bench/bashloop/fixtures are left alone and make pr-ready derives the set the gate will.
Verified on the 621-file diff that surfaced it: 43 directories to 36, the seven dropped are exactly the fixtures, and the two halves print the same list.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* santos/dev lands on dev: the worker harness, stopping and limits, the task page and rail, goroutine ownership at close (#1108)
Integration branch santos/dev, held as a closed slice at d39a4e308 plus the empty-prompt guard for generate_image (3a1f80f9c). Everything through #1192 had already reached dev as #1194; this carries #1193 and #1203 through #1331.
The worker harness: one loop under /task and codeaf do with a plan store per run, a plan seat, a work seat, a check seat and a review round after each piece of work, off unless CODEAF_TASK_BELT=bash is set, so the default road does not move. Stopping and limits: a person's stop reaches a run, a time or dollar limit ends a run and names itself, a run is handed what is left of the conversation's limits, a worker that stops making progress is told once and then ended. The task page and the rail: the plan as a tree, a run's row with its parts under it, step rows cut from the commands as they ran, a press on a run's row opens its page in under 0.2 seconds. The engine host and sign-in, the profile's composed writes across two processes, unread config keys said once. Nothing keeps writing after the process closes: the place sweep, the standing ticker, the usage writers, the pool judge sweep and the catalog warm are each owned, stopped and joined, and a law lists every goroutine a conversation process starts. The heavy-suite lock is a kernel file lock that follows the suite. The lazy lexer registry, one fuzzy matcher for every picker, the drafted-with footer on the CodeAF repository.
Reviewed 2026-09-21: gates green locally and in CI once #1332 taught the touched-packages walk about nested modules; the default road verified live on both roads against a dev baseline; the one regression the slice introduced (generate_image had lost its empty-prompt guard) fixed on the slice with a contract test.
Co-authored-by: Santosh kumar <29346072+santoshkumarradha@users.noreply.github.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* a dev build installs beside codeaf as devaf and follows the dev channel (#1333)
* install: --name installs the binary under another file name beside codeaf
The installer takes --name WORD and CODEAF_INS…
* Honor chat-requested models for task workers and new conversations (#1935)
Preserve explicit worker model selection for joined tasks and descendants. Add model-selected independent and teammate chats, atomic launch claims, updated tool guidance, and regression coverage.
Validated all five live OpenRouter launch scenarios with DeepSeek v4.1 Flash and Kimi K3. All PR checks passed.
Refs #1839.
* Answer and verify the four skill capability questions (#1938)
Add direct skill definition, capability and troubleshooting answers, including memory-independent behavior. Pin the four original queries and verify tool-result delivery through real hosted terminal chats with memory saving on and off.
All eight live cases passed using exact deepseek/deepseek-v4.1-flash. All PR checks passed.
Closes #1937.
* Make All show the current conversation tabs (#1939)
* Scope All to the current conversation tab strip
* Keep screenshot launches guarded and use rendered count grammar
* Guard the screenshot terminal option command
* Expect current-tab scope in the All navigation hint
* Scope the All wall's copy and empty state to open tabs
The in-wall All chip now says the grid holds the tabs in this view
rather than saved conversations, and an empty scoped grid says no
conversations are open here instead of promising saved ones will
appear. wallEmptyText is shared by the live grid and the currently
unused wallEmptyRow, so the two stay in step. The dock test now proves
the label and the mark each open the wall scoped to open tabs, and the
render test pins the scoped empty line.
Assisted-by: CodeAF (deepseek-v4.1-flash-1017)
Co-Authored-By: CodeAF <267109073+agentfield-bot@users.noreply.github.com>
* Make open tabs a property of the open wall
closeWall now clears wall.openTabs with wall.on, so no reader after a
close can mistake a closed scoped wall for an open one. wallOpen still
reads the scope before it closes the wall, which is where the team is
kept.
Assisted-by: CodeAF (deepseek-v4.1-flash-1017)
Co-Authored-By: CodeAF <267109073+agentfield-bot@users.noreply.github.com>
* Open an overview unpicked
A pick outlived a close that was not esc, so a card picked in the wall left
the next overview in selection mode - and in the All scope it could be a card
nobody had picked there. Every overview now opens with nothing picked.
Assisted-by: CodeAF (deepseek-v4.1-flash-1017)
Co-Authored-By: CodeAF <267109073+agentfield-bot@users.noreply.github.com>
* Name the All door as the tabs in view in the manual
places.md still promised all saved conversations from ▦ All, and keys.md
listed alt+v, /wall and the strip door as one thing. They are two views
since this change.
Assisted-by: CodeAF (deepseek-v4.1-flash-1017)
Co-Authored-By: CodeAF <267109073+agentfield-bot@users.noreply.github.com>
---------
Co-authored-by: CodeAF <267109073+agentfield-bot@users.noreply.github.com>
* Run the same program when connecting to another machine (#1940)
* tui3, config: the gate row lands on the conversation you are in, and /status names the gate (#1063)
The three Safety rows — `ask before running`, the tool exceptions and the shell
command rules — wrote the profile and left the running gate alone, while the
YOLO badge read that profile live. So the badge and the gate disagreed in both
directions: `allow` lit the badge over a gate that kept asking, and `prompt` put
it out over a gate that was still wide open, which is the false-safety claim
#322 and #325 exist to prevent.
`applySetting` now pushes those three rows through `ApplyApprovals` — the seam
/permissions already drops a banked rule through — and refreshes the badge on
the same keystroke, on the branch where the push landed. A rebuild that could
not be done is said out loud on the panel's foot line in /permissions' own
words, `saved · from the next session`, and the badge stays with the gate in
force rather than following the file.
And /status carries the posture it never carried: `approvals prompt`, `allow` or
`deny`, in the `ask before running` row's own words, in the note, in --json and
on the phone's status sheet, from the one posture reading the badge uses. The
status row keeps its negative-space badge and the segment is no longer written
into the page twice.
The note's label column is measured from the widest label it carries, so three
crew assertions that spelled `"\ncrew"` plus exactly five spaces were
assertions about every other row on the page. They read the crew line by its
label now.
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* attribution: the footer names CodeAF, and still links to agentfield.ai (#1075)
* attribution: the footer names CodeAF, and still links to agentfield.ai
The pull request, issue and comment footers read "Drafted with agentfield ai".
They now read "Drafted with CodeAF"; the link, its utm parameters and the
"reviewed and owned by the author" tail are unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNBScbyNAbbEQ5jn9G6auy
* docs: the change entry for the CodeAF footer
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GNBScbyNAbbEQ5jn9G6auy
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* session, prompt, tui3: a wrong completion check is answered with [no change], and the answer stands (#1065 round 1) (#1067)
* session, prompt: a wrong completion check is answered with [no change], and the answer stands (#1065 round 1)
The end-of-turn reader saw 600 bytes of the last message, so a long table read
as cut off; the carry-on told the model to explain itself, and the explanation
became the only answer left in view under the fold.
The reader now sees up to 8 KB of the last words, and a cut it still has to
make ends with `[clipped by codeaf: N of M bytes]`, which its ask says is never
evidence of a cut-off answer. The carry-on lead says who wrote the note and
offers one exact reply, `[no change]`: it ends carrying on for the ask without
another reading, the transcript keeps it for the model, and neither replay nor
the live feed draws it — so the settled answer before it is what the fold finds.
system.md trades `# Tone` and `# Delivery` for `# The answer`, `# Words or
work`, `# When corrected` and `# Messages from codeaf`, and the two lines that
pushed action on questions are qualified. The lean page keeps all four; the
prefix waivers rise by the 1,705 bytes that cost, dated and named.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs: the change entry takes the pull request's own number
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* session: a quiet landing is asked about the notes it was handed, not the page that names them
The worker's system page now names [silent] and [stuck] under
`# Messages from codeaf`, so a search of the whole request found the tag on
the page. childWasHanded reads the conversation and leaves the page out.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* session, prompt: [no change] answers the note it follows, and a long ask leaves the last words cut by name (#1065 round 1)
Self-review of #1067 found the token honoured on the wrong replies. The gate
read the turn's carry-on count, so a model that made calls in answer to the
note and then said [no change] ended the turn unread on an answer those calls
may have made stale, and a token after a load or ask nudge counted too. It now
reads the transcript: the token must be the very next reply to the reader's
own lead (answeredNoteUnchanged), and the dead declined flag is gone.
An ask up to the whole digest rides in its head, so eight kilobytes of last
words behind a long ask reached the backstop clip and ended in a bare `…`.
checkpointClipSaid takes the room that is left. A turn that ends on the token
no longer starts the route judge or hands the token to the memory reflex, and
a later reading's last words skip it.
`# Messages from codeaf` named `[still asked]`, which only the reader ever
receives, and left out `[stuck]` and `[held]`, which the conversation does; it
now names the tags that arrive and says any other opening, such as
`[image #1]`, is the person's. The waivers sit on the measured 1,779 bytes, and
the manual and the change entry say what the gate actually honours.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* prompt: the new sections keep the rules the old two carried, and say what stays in view (#1065 round 1)
Owner review of #1067. Replacing `# Tone` and `# Delivery` had dropped five
rules; each is back inside the new sections: match the person's task and
vocabulary, choose the safe option under uncertainty, evidence and blocking
details complete, never a compiling scaffold or a narrowed test, never
half-solved work.
`# The answer` said only the last message reaches the person, which `# Planning`
contradicts: the plan and the per-batch sentence are shown while a turn runs. It
now says that once a turn ends only its last message stays in view.
`# Words or work` sat beside `## Work or words`, which spends the same two words
on hand-off sizing; it is `# Answer or change`, and it says an answer asked for
in chat is written in the reply, not a file, unless the person asks for one.
The waivers sit on the new measurement, 2,035 bytes over dev on both arms.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* prompt: the messages-from-codeaf list names every note codeaf writes
The system prompt now distinguishes conversation user-role notes from private reader and tool-result markers. A structural test follows the production constants, and the byte waivers record the exact fixed and lean measurements.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* session: no change skips judgment only when it answers the reader
The completion loop now uses the transcript context before suppressing the route judge or substituting the prior answer for memory. Tests cover the withdrawn and ordinary-token memory paths, and the manual separates counting from display.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* test: the model stub replays the no-change fold
The OpenAI-compatible stub can now drive the real binary through eleven read rounds, a long table, a rejecting reader, and the exact token reply. The recipe records the tmux setup and the expected log and screen evidence.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* prompt: the standing-news tag stays with the event, not on the page
The messages-from-codeaf list had named [something you set up fired], and
TestTheSteeringLineReadsAsNewsAndNotAsARequest refused it: that line says
under the news itself what it is and what not to do about it, so the page's
copy is one law bought on every request of every turn for a turn most
sessions never have. The list keeps the compaction tags, the structural test
now files the standing frame with the private voices the page must not name,
and the waivers fall to the new measurement (fixed 55,280, lean 47,055).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Abir Abbas <abirabbas1998@gmail.com>
* Clean internal experiment records and revive test/ux for codeaf (#1068)
* chore: clean internal experiment records and revive test/ux for codeaf
Public-repository cleanup ahead of opening the docs to outside readers.
- Remove four internal DOE/experiment record directories that reference
private issue and pull-request numbers and are not current-product
documentation: docs/design/pin-doe, plan-gate-doe, turn-wall-share-doe,
and workspace-foundation.
- Neutralize internal machine references in benchmark and design docs:
the bench host ("spark"), its secrets.env path, and a personal working
branch name, all now generic placeholders.
- Revive test/ux/, the user-facing journey suite, for the renamed product:
collapse the removed v1/v2 dual-surface logic into the single v3 surface,
repoint the binary to cmd/codeaf and state to ~/.codeaf/CODEAF_*, and
delete gate.sh whose premise was the v1-vs-v2 parity table.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* chore: drop internal conversation-runtime wave records, keep the measurement contract
The conversation-runtime directory was a local development wave: day-by-day
status, /private/tmp paths, "owner authorized" process notes, draft PR numbers,
and local change logs. None of it is current-product documentation a public
reader needs. Keep PARETO.md, which is the benchmark's cited measurement
contract, trimmed of its dangling calibration link and owner language.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* chore: neutralize the remaining bench-host and work-machine references
A wider sweep found the internal bench host ("Spark"), its secrets path
(fleet/secrets.env), and a scratch ops directory still named in live docs,
bench READMEs and bench scripts that the earlier redaction had not touched.
Rename the host to "benchhost"/"the bench host", drop the secrets path, and
replace "the laptop" as the owner's own machine with a neutral "work machine"
where it meant the internal one. The manual's first-person "the laptop you are
sitting at" is public-facing and left alone.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* chore: fix review findings in the public-cleanup diff
- PERF.md: drop a private tracker issue reference (#846).
- PARETO.md: restore a complete sentence dropped when the calibration link was
removed, and align tense with the remaining present-tense claim.
- home-mission-control/DESIGN.md: drop the internal "fleet" system name and
an owner-framing phrase, consistent with the secrets-path scrub elsewhere.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* docs/design: the two records live code still cites stay in the tree
plan-gate-doe/REPORT.md is the measured evidence behind the plan-gate default
that twelve comments in cmd/codeaf, internal/config, internal/session and
internal/splitgate point at, and turn-wall-share-doe is the run
internal/session/turnwall.go says it was added from. CLAUDE.md keeps the
record on purpose for exactly this reason, and neither folder names a machine,
a secret or a private address.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* test/ux: the revived journey suite goes back out
#991 removed it because it drove the v1 and v2 surfaces, and the revival did
not change that: its journal verb reads graph.db tables (messages, nodes,
usage, commands) that the v3 chat never writes, lib.sh still waits for the
resident, nothing runs it from the Makefile or a workflow, and its only
evidence was bash -n. docs/JOURNEY.md says internal/e2e is the one suite that
drives the binary, and that stays true. A suite that has been run green
against bin/codeaf can come back on its own pull request with a target that
runs it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: entry for #1068
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: the #1068 entry says why the journey suite is out, correctly
The first draft said the v3 chat never writes the graph.db tables the suite
reads. Running the suite showed both message rows landing, so that sentence
was wrong; what is true is that nothing runs the suite, it had never been run,
and its first journey fails on its first screen check (#1072).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
Co-authored-by: Abir Abbas <abirabbas1998@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* session: task commits are authored by the bot account, not codeaf@localhost
The author codeaf stamped on the commits it lands was `codeaf <codeaf@localhost>`, which no GitHub account can link, so every branch codeaf landed failed the CLA check. It now writes `codeaf <agentfield-bot@users.noreply.github.com>` - the identity the Co-Authored-By trailer already used - and keeps `codeaf@localhost` and `aforge@localhost` recognised as legacy by taskCommitIdentity.
GLM 5.3's review caught an unmarked retired name in permissions.md that reddened the namelaw gate, and seven stale test fixtures; both fixed. Laws gate, session, exec and cmd are green.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* README: show the pinned-version install line the release test requires (#1103)
* README: show the pinned-version install line the release test requires
The Install rewrite dropped the VERSION=<tag> pin example, and
TestPublishedPinExamplesGiveVersionToBash reads every published install
surface for `| VERSION=` because `VERSION=<tag> curl ...` is an easy
mistake to copy — it sets the variable for curl instead of the install
script. The pin goes back inline on the same host the section already
uses, with the releases page still linked for tags.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* docs: the change entry for the README pin example
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
---------
Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: anonymous usage counts, off with CODEAF_TELEMETRY=off (#1095)
* telemetry: the package behind anonymous usage counting, per the wire contract
Four typed events (first_run, session_started, session_ended, fault) with the
contract's allowlisted, bucketed props; the opt-out ladder with its off
reasons; a hashed install identity at 0700/0600; a fault fingerprint over
codeaf function names only; a JSON-lines spool with a deadline-bounded flush
of up to 50 events per POST, 7-day age drops and a 1000-line cap; the notice
constant with NoticeShown/MarkNoticeShown gating the flush; and Show() for a
future codeaf telemetry show.
A library only: nothing in cmd/codeaf, internal/session or internal/config
reads it yet.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: tests, doc, and contract fixes for the usage-count package
Adds the package's tests — bucketing edges, the opt-out ladder, install
identity, the notice, fingerprinting, the spool against an httptest relay
(cap, age drop, 50-per-POST splitting, a hard deadline against a hanging
server, silence on failure) and the privacy law that no sentinel string
reaches the wire. docs/TELEMETRY.md documents the notice, what is sent and
how to turn it off, with a test that fails if the doc's property table
drifts from the Go allowlist.
Fixes four drifts from the wire contract found running those tests: the
<1m duration bucket was missing, the fingerprint's argument stripping cut
too much, the rc channel suffix must be a single integer, and under go
test a config-off rung outranks the test rung in the reason reported.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: fix review defects 1-8 with tests
Fingerprint stability (last-( cut, .go:/main./created-by frame rules),
counted-batch flush, guarded and multi-process-safe spool, BucketDuration
edges, Configure-gated write paths, O_EXCL install id, install.json
preservation, buildinfo.Dirty accessor.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* installer: record the install locally and print the telemetry notice
Following the telemetry wire contract: a successful install now writes
telemetry/install.json under the state root (dir 0700, file 0600) with
the install method, channel and UTC timestamp, leaves any existing
install_id alone, and makes no request the download steps did not
already make. At the very end the installer prints the contract's
notice to stderr after one blank line, or one line saying telemetry is
off when CODEAF_TELEMETRY/DO_NOT_TRACK opts out. README gains a plain
Telemetry section pointing at docs/TELEMETRY.md, and a new
test/installer-telemetry.sh proves the marker, the notice and the
opt-out without a network.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* installer: four review corrections to the telemetry commit
The review of 71ff95a6b found four things. Revert the one line that
changed `if [[ -z "${TAG:-}" ]]; then` back to `${TAG:-}`: under
set -u an unset TAG must reach api_problem, not crash. In
write_install_marker the channel lands in JSON verbatim and CHANNEL
can come from the environment, so only stable, rc, staging or dev is
recorded and anything else becomes "unknown" — with test cases for a
valid channel and for we"ird, both asserting the marker parses
(python3 -m json.tool, or jq, else a strict channel check). Fence the
README Telemetry notice in a ```text block so Markdown keeps its
alignment, wording byte for byte. Clear the two shellcheck findings in
test/installer-telemetry.sh with one block disable for SC2016/SC2034 —
ok() evals those strings, so the quoting is deliberate — and export
CODEAF_TELEMETRY/DO_NOT_TRACK where a subshell needs them, without
weakening any assertion.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* release-downloads: daily PostHog report of public GitHub release download counts
A scheduled workflow reads the repository's releases from the public GitHub
API and sends one codeaf:release_downloads event per binary asset
(codeaf-<os>-<arch>[.exe]) — sidecars like checksums.txt are not reported.
Each event carries release_tag, channel (stable or the prerelease suffix),
prerelease, os, arch, the cumulative download_count and the UTC
snapshot_date; the event id is derived from tag, asset and date, so a
same-day rerun deduplicates instead of counting twice. No code in the
binary; counts come only from public release data.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* release-downloads: tests cover the workflow, docs and pagination
The dry-run unittests now also assert the identifiers the wire spec spells
out where the script and the workflow spell them: the schedule, dispatch,
contents-read permissions, built-in token, project-key secret and host
variable in .github/workflows/release-downloads.yml, the public-data
paragraph in docs/rules/promotion.md, stdlib-only imports, pagination
across API pages, the host override and the /batch/ endpoint, sidecar
skipping, draft skipping, and the channel words stable, rc, dev and
staging.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* release-downloads: four review corrections to the script
Channel detection now follows the tag grammar in
cmd/codeaf-release/version.go: stable, rc, dev and staging tags match
their four patterns and anything else reports "unknown", so
dev-20260917-09299019bcdc is no longer mislabelled "stable".
--dry-run works without CODEAF_POSTHOG_PROJECT_KEY, the local and test
path: the batch prints with api_key "<unset>" and exits 0, and only the
sending path stops with the notice.
Every event carries "$geoip_disable": true next to
"$process_person_profile": false, since the sender is a CI runner whose
location is meaningless. The module docstring now names
release-downloads.yml, the file that exists.
The fixture holds one tag of each shape plus an unrecognised one, and
the tests assert the channel for each, including the two real dev and
staging tags.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* release-downloads: test runs on Python 3.9 too
ScriptSourceTest read sys.stdlib_module_names unguarded; the attribute
arrived in Python 3.10, so the suite errored on macOS stock python3
(3.9.6). Guarded with getattr so the pinned import-set check stands on
its own where the attribute is absent; 32 tests pass on 3.9, 3.10 and
3.14.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* installer telemetry: the notice is read from docs/TELEMETRY.md
The test read .telemetry-contract.md, a working note that is not in the
repository and never will be, so it aborted with "telemetry contract is
missing" in a clean checkout. It now extracts the fenced block under
"## The notice" in docs/TELEMETRY.md — the same bytes as the Notice
constant in internal/telemetry/notice.go — and holds the installer's
TELEMETRY_NOTICE to it as before; a new assertion holds the README's
telemetry fence to it too, byte for byte, so the invariant the suite
existed to guard now has its third leg.
Comments in scripts/install.sh, internal/telemetry/telemetry.go and this
test now name docs/TELEMETRY.md as the source of the notice.
No Go code changed and no Go tests were run. shellcheck is clean; the
suite's 33 passing assertions include the two new notice checks, and the
same two stat(1)-related assertions that already failed on this GNU
machine before the change still fail with identical output.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* release-downloads: the download-counts paragraph lives in docs/TELEMETRY.md
docs/rules/promotion.md was the only home the paragraph had, and it came
with a fallback pinning the branch to the state before the telemetry
doc existed. The paragraph moves, byte for byte, into docs/TELEMETRY.md
as a final "## Download counts" section beside the rest of the telemetry
story, and promotion.md returns to its origin/dev content, so this
branch now touches no release docs.
test_no_telemetry_doc_on_this_branch asserted docs/TELEMETRY.md did not
exist and is deleted. The two tests that read the paragraph read it
where it now lives: both require a "## Download counts" section in
docs/TELEMETRY.md naming .github/workflows/release-downloads.yml,
scripts/release_downloads.py and the checksums.txt sidecar, and the
promotion.md fallback is gone.
No Go code changed and no Go tests were run; the property table in
docs/TELEMETRY.md is untouched. The suite passes: 31 tests, OK.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* installer telemetry: the mode check asks GNU stat first
On Linux `stat -f` succeeds and reports the filesystem, so the BSD-first
order never reached the GNU form and both permission checks failed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CqfhxLrrBNQxwPNvEgoBGR
* telemetry: refuse to send to the production relay from a test binary
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: testHome points the endpoint at a dead loopback
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: the orphan-adoption test names the dead relay it now gets
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: a test pins that no test binary reaches the production relay
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: three tests pin the test-binary relay refusal
Each asserts through real calls, not a re-implemented effect: the
newRelay override lands after testHome and a flush reaches that
recorder; a default-endpoint flush is refused like a dead relay
(zero round trips, event still spooled); forcing the ladder on
cannot reopen the path.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: allocation-free session counters
Snapshot returns the SessionStats fields the SessionEnded constructor
takes, so the wiring hands the struct straight over. Cost is stored as
integer micro-dollars and divided back once, in Snapshot. Count* never
ask whether telemetry is enabled and never allocate.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* telemetry: gofmt the counters test
One alignment fix in the many-goroutine test; no behaviour change.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* config: telemetry setting row (CODEAF_TELEMETRY)
Key "telemetry", on|off, default on, env pin CODEAF_TELEMETRY, in the
interface group beside the history row. TelemetryAtIn walks the ladder —
pin, project file, profile config, default — and TelemetryOffReason
answers whether config turned the pipe off and names which rung did.
The row sits in ProjectKeys so a repository may answer for itself.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* cmd/codeaf: the telemetry command, and the setting it writes
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* cmd/codeaf: session lifecycle events at execute (work in progress)
Configure, notice, first_run and session_started at the start of every session
command, session_ended and a one-second flush at its exit. The end event does
not yet carry the session counters.
* provider: count answered model calls and their spend at the log door
* session: count sealed turns and executed tool calls
* cmd/codeaf: the session-ended event carries the run's counters
telemetryEnd builds the end event from telemetry.Snapshot so turns, model
calls, tool calls and cost reach the spool; the stop-reason switch becomes
a map over the exit ladder; and both lifecycle constructors are gated on
the ladder being on so a disabled run touches no state.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* cmd/codeaf: the counters test says the tally is process-wide
The exact turn, call and cost assertions hold for one run of the package; a
repeated run counts into the same atomic tally again.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* guard: a fault hook Recover calls, for a reporter above this package
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* cmd/codeaf: the fault event at both crash sites, off the current session
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* cmd/codeaf: a test that the crash site spools a fault and not the panic text
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* docs: finish the anonymous usage counts contract and add the 1095 changelog entry
* guard: the fault hook sits behind an atomic pointer
A goroutine recovering a panic read the hook while a test on another
goroutine wrote it, which the race detector reported. SetOnFault stores it
once; Recover loads it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* cmd/codeaf: a task's interrupt word comes from the signal, not the cancelled context
stopSignals cancels the signal context at the end of every errand, so the
flag read from its Err said interrupted for a run that finished cleanly.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* tui3, installer: the telemetry row has a tab, and a custom install writes no marker
TestEverySettingRowHasATab wants every registry row on the settings panel.
TestCustomInstallOutsideTheStateRootDoesNotRunAdoption wants an install
outside the state root to leave the login's state folders alone, so the
install marker is written only when the root exists or the install is in it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* cmd/codeaf: the counters test zeroes the process tally first
Other tests in the package drive model and tool calls through the doors
that count, so the exact bands held only when the test ran alone.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* cmd/codeaf: the version test drives the telemetry lifecycle, not execute
execute starts writers under the state root that outlive the test, and the
temp dir's cleanup raced them. The lifecycle alone is what the test pins.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* cmd/codeaf: gofmt the lifecycle test
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* session: the carry-ladder fixtures wait for the mark's drawing, not race the scheduler (#1104)
* session: the carry-ladder fixtures wait for the mark's drawing, not race the scheduler
TestASuccessfulHandoffJournalsTheRungThatSuppliedTheBrief failed once in a full
make check at line 118: the worker's brief was the running model's draft, not
the mastermind's written handoff.
THE CAUSE IS NOT A STOLEN STEP. Reproduced under load (60 CPU burners, the
fixture run 1500 times), every request the fixture makes is either the turn's
own or one the aside answers: the queue carries only `round`, `draft` and
`writer`, and the errands beside the turn (title, namer, the mark's drawing)
never touch it. What moves is the ROUND COUNT — 41 to 54 across the runs —
because the mark's drawing is a sidecar (sidecar.go) whose landing the scheduler
places, and the turn is never held for it. On a busy machine the turn runs its
rounds off faster than the drawing's goroutine is scheduled onto a core, the gap
between the net firing and the drawing landing outruns the slack the script
carries ([checkpointSlack] says so in its own words), the writer's ask lands
PAST the end of the 53-step script, the scripted completer answers it with its
past-the-end line `(unscripted)` — which is not prose — the handoff rung reads
degenerate, and the carry ladder falls onto the draft. That is #392 exactly, one
mechanism along.
WHAT FIXES IT IS WAITING FOR THE READING. checkpointAgent now puts a watch on
the turn's own context ([watchReadings]) and the handover fixtures submit
through [watchedContext], so [answerWhenQuiet] holds each request that carries
the belt until every reading beside it has landed — the order a real turn has,
where a real model spends seconds on a step and the small readings land inside
it. The gap is then one boundary whatever else the machine is doing, and a
script long enough to cross the mark is long enough.
THE REGRESSION TEST holds the drawing back by a fixed wall time — standing in
for a scheduler that does not reach it in time — and insists on the behaviour:
the turn does not spend its script racing the drawing, and the writer's rung
still supplies the brief. It fails without the watch (the turn makes 54 rounds)
and passes with it.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* docs: the change entry for the carry-ladder drawing race
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
---------
Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
* docs: the install proxy is live, and the manual says so (#1076)
* docs: the install proxy is live, and the manual says so
`https://agentfield.ai/get/codeaf` has served `scripts/install.sh` since
2026-09-16, the day the repository went public, so the compiled-in manual
and docs/GUIDE.md stop saying it is "not serving yet" and stop calling the
repository private. The proxied line goes first, as the README already has
it; the raw GitHub line is described as the script under it. Both pages say
to pipe into `bash`, not `sh`, because the script uses pipefail and `[[ ]]`
and dash rejects them, and both state the channel path (`/dev`, `/staging`,
`/rc`) beside the flags. The manual also says what the proxy refuses: a
script without its channel line exactly once, or a body that is not a shell
script, is a 502 rather than the wrong thing.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: entry for #1076
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* A launch says a newer codeaf is out, and /update installs it and restarts (#1060)
* The release-tag grammar has one home, and it is internal/update
Stable, rc, dev and staging tags are parsed, compared and bumped in exactly one
place now. cmd/codeaf-release keeps its next, kind and prune behaviour and its
tests unchanged; it reads the grammar from the new package rather than owning a
second copy of it.
A second parser is the thing that drifts: the updater about to land needs the
same answer to "is this tag newer than that one" that the release tool gives,
and one source of truth is the only way they cannot disagree.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* internal/update: look up a release, check it, and replace this binary with it
The launch check answers only for a build that could sensibly be behind: a
stable tag, or a release candidate whose stable line has since been published.
A dev or staging build, a make build sha and an unstamped binary make no request
at all, because a channel build is deliberately newer than stable and a source
build belongs to whoever built it. The answer is cached for a day beside the
profile, and every failure is silence.
The install downloads into the target's own directory, matches the sha256 from
checksums.txt, and only then renames over the running file, so a refused
download, a wrong checksum or an unwritable directory all leave the original
binary exactly where it was and no temp file behind. The API token never leaves
the API host: the redirect policy strips it the moment a redirect changes host,
which Go does not do on its own for another port or a subdomain. Windows has no
atomic rename over a running image, so it goes through ReplaceFileW and puts the
original back when Windows reports the one failure that moves it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* tui3: a launch says a newer codeaf is out, and /update installs it
The launch line is one dim transcript note carrying both versions, /update, and
the curl line, because the command is what the owner asked to be given. It
arrives as a command rather than an opening read, so the first frame is drawn
before the network is asked anything and a slow or refused answer draws nothing.
/update — /upgrade is the same road — names the tag, then the checksum and where
it landed, then quits with a restart plan for the door to carry out. Already
newest says so and stays. It refuses while a turn or a task is running, and once
it has started, one shared guard keeps a second /update and a new turn from
beginning underneath it: the restart must never quit on top of live work, and
the home page's Enter roads go through the same guard chat's does.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* codeaf update, and the door that restarts the same conversation
codeaf update --check prints one line and exits 0 when this release is newest,
3 when a newer one exists, 1 when it could not ask. Without --check it installs
stable, or whatever --rc, --dev, --staging or --version names, choosing a
channel build by its own publish time the way the installer does. A binary built
from source refuses in place and names its path rather than replacing something
a developer is holding.
The restart happens here and not inside Bubble Tea: the surface fills a slot,
the door reads it once the frame is down and the terminal is back, and then
execs the new binary with this launch's own arguments plus --session pointing at
this transcript, so the conversation reopens where it was. A linked-local engine
is asked to retire only after the surface has detached, and it still refuses
while another window or any live work is there.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* remote: a window that says it is leaving needs no torn-link grace
The twenty-second grace exists for a terminal that was killed without saying so,
and a deliberate detach is the opposite of that — the window has just announced
its departure. Carrying the grace anyway left a cleanly closed window looking
attached for two more call deadlines, which kept a freshly installed codeaf
waiting behind the engine the old one had already left.
It clears only once the last view is gone. Turns, tasks, unanswered questions,
other views and live work all still refuse retirement, and a refusal still never
stops the work it protects.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* The installer and the updater agree on what a channel tag looks like
Two roads now install codeaf, and they were reading the same release list by
different rules: the shell accepted any dev-* or staging-* tag and semver parts
with leading zeroes, while internal/update accepts only the shapes the release
workflow actually publishes. A malformed tag newer than a real one would send
the two roads to different builds.
One helper carries the grammar to both channel selection and the line that names
the channel, and an unrecognised tag for the asked-for channel now says so
instead of installing whatever came back. The publish-time ordering #1056 added
is untouched: only which candidates are eligible changed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* The manual stops saying that nothing self-updates
That sentence was true until this change and is now the opposite of true, so it
goes, and a section written in the words people bring takes its place: is there
a newer version, how do I update codeaf, why does it say this every time I
start. It states who gets the launch line and who never does, the opt-out
variable, the day the cached answer lasts, the shell exit codes, and both
refusals — a build made from source and an executable nobody may write.
The command table names /update and /upgrade with the argument they take. Four
probes reach the new section, and the remote page keeps its own asker's words in
its heading so the new section cannot take that question from it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs/changes: the update check and /update, for #1060
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* update: --check answers for the channel it was asked about, and a newer build is never downgraded
Two things a hand verification caught. --check parsed whatever tag it had
selected with the stable grammar alone, so --dev, --staging and --rc could
never be "newer" and every one of them answered "you are on the newest codeaf"
and exited 0 while a newer build sat in the list. The check now keeps its
channel all the way through the decision and always names the tag it is talking
about: stable and rc compare as semver, a dev or staging tag is the same tag or
a different one, and --version is equal or it is not.
And a build AHEAD of the newest stable was quietly installed backwards — the
check said newest, the install downgraded it. Both roads refuse now, naming both
versions and the deliberate way past:
this codeaf is v0.3.0, ahead of the newest stable v0.2.0 — pass --version
v0.2.0 to install it anyway
An explicit tag IS that deliberate road, so --version and /update <tag> still
install exactly what was named.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* update: a failure names the asset and the status, and ends with the curl line
A download that failed printed the whole fallback URL, which put the retired
product name on somebody's screen. The line names the asset it asked for and the
status it got back, and nothing about which repository answered — the
compatibility attempts still happen, they are just not the person's business.
Every terminal failure now ends with the curl line, which D9 asked for and the
download path had been missing.
The / list declared no argument for /update while the command page documented
one, so the list gains the second row the way /cache has one. The manual section
now says what the code does about a build ahead of the newest stable, where it
had said such a build "gets nothing" — true of the launch line, and false of the
install until this wave.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* update: the curl line is agentfield.ai/get/codeaf, the supported road
The launch line, the refusals and the terminal door offered the raw
GitHub address of scripts/install.sh. The repository is public and
agentfield.ai/get/codeaf has served that script from main since
2026-09-16, so the constant now spells the supported line, the manual's
update section names it in place of "the curl line below", and the
change entry says so. Asked for on the pull request by Santosh.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* a run's own scratch note no longer fails the delivery gate (#1096)
* codeaf: a run's own note is offered outside the tree it is judged in
leafOutputHint invited a job root to write its overflow document at a
workspace-relative name (exec.SuggestPathFor's task-2-x1-toolchain-checks.md
shape), so a run working in a person's directory left that note untracked at
the root of their working tree. The delivery gate holds the run's record —
the artifact registry, joined by jobArtifacts, plus the delivered tree —
against the request, read the note as part of what was handed over, and
refused the delivery; the run then ended incomplete over complete work.
There is no separate mechanical clean-tree check to exempt, so the fix is
the writer's: where the workspace belongs to the person, the root's file
invitation points at the run's scratch beside its recorders and job logs,
and the message keeps carrying the deliverable.
* codeaf: a person's own file still joins the record the gate reads
TestARootLeafInAPersonsDirectoryPutsItsNotesInScratch baselined the tree
after the note was already written, so its landing read could never have
observed anything: the record stayed empty because of the ordering, not
because of the address. The baseline now happens first, in the executor's
own order, and a hint that ever points into the tree again fails on the
observation, not only on the spelling.
And the other half of the law is pinned down: a file that turns up in the
person's tree while the leaf runs — even at a name wearing the run's own
task-<n>-<slug>.md shape — is still observed and still lands in the record
the delivery gate is held to. Only the run's own note moved; nothing else
about what the tree says was loosened.
Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
* docs: the change note for the root's overflow file moving out of the tree
---------
Co-authored-by: codeaf <agentfield-bot@users.noreply.github.com>
* chat: the wordmark is drawn CodeAF, four rows, capitals on the d's cap line (#1106)
`┌─┐ / ├─┤ / └─┘` is not an `a`, it is two closed bowls of equal size
stacked on each other, and two equal closed bowls are an `8`. That was
the second-to-last glyph of the product's own name on the first screen
of every fresh install. The owner's answer is to have the two letters
at the end stand up out of the word as capitals: `A` is an apex, a
crossbar and two legs; `F` is the one letter whose case is told by its
arms alone, so its top arm is the longer one.
A CAPITAL'S TOP IS THE ASCENDER'S TOP, and three rows of box-drawing
could not give it that. A bar is drawn at the middle of its cell and a
stem reaches the cell's edge, so the `d` stood half a row over any
capital however it was formed — and a stem in the bottom row hung half
a row under the bowls' baseline the same way. The fourth row is that
half a row made whole: the x-height letters live in the lower three and
leave the top row blank; the capitals and the `d`'s ascender start in
the top row, the ascender as the half-stroke `╷` so its top is the
capitals' bar; and every stem that ends on the baseline ends as `╵`,
which stops where `└─┘` does. A `│` in the bottom row is a descender
and nothing else.
THE WORD IS SPELLED `codeaf` AND DRAWN `CodeAF`. `product` is unchanged,
the glyph table is still keyed by its lowercase letters, and a terminal
that cannot draw boxes still gets the word `codeaf`.
The greeting's centring test read the unit's left edge off the
wordmark's first row, which is now the cap line the x-height letters
leave blank; it reads the second row. The one manual page that draws
the wordmark had been drawing the retired `aforge` letterforms under
the label "the codeaf wordmark" — the name law walks text and cannot
see a name spelled in box-drawing — and draws the shipped forms now.
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* A real release download finishes: the 3-second check clock no longer covers the asset (#1110)
* update: a release download gets its own clock, not the check's
The release client was built as http.Client{Timeout: 3s} because three seconds
is right for the launch check, and Go's Client.Timeout covers the WHOLE
exchange including every body byte. The same client then downloaded the
release asset, so a 57 MB download on a healthy link — about eight seconds
here — was cut off three seconds in and a person read `read the release
response: context deadline exceeded`.
Client.Timeout is gone. The transport bounds only what has made no progress: a
5 s dial, a 5 s TLS handshake, a 10 s wait for response headers. Every call now
takes its deadline from its context. The launch notice and `--check` share the
one CheckTimeout constant, install metadata gets 10 s per request, and the
asset gets a 30-second no-byte stall window plus a 15-minute ceiling — a dead
link fails with a sentence, a slow one finishes.
No Go deadline text reaches a person. A stall says `downloading
codeaf-linux-amd64 stalled — no bytes for 30 s`, the ceiling says `took longer
than 15 minutes`, and late headers say `did not start arriving within 10 s`.
The stall window, the ceiling and the metadata window are injectable, so the
tests prove the clocks with real slow, silent and trickling servers rather than
waiting out the shipped ones.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* update: both doors read the one check constant
`codeaf update` and the chat surface each spelled `3*time.Second` when they
built the release client, which is how a figure meant for one small request
came to govern an install. Both now pass update.CheckTimeout, and the three
seconds live in exactly one place.
The terminal's `--check` takes the client's Check, which is the whole-exchange
check deadline; a plain `codeaf update` keeps Select, so the metadata requests
an install makes get the ten seconds they need.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: the update download's own clock (#1110)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: v0.2.1 rolled up into CHANGELOG.md (#1113)
The 33 entries that landed on dev since the v0.2.0 roll-up are the ## v0.2.1 section of CHANGELOG.md now; docs/changes/unreleased/ keeps only this pull request's own entry. Stable v0.2.1 takes its notes from that section.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* README: telemetry folds under Docs (#1115)
The 23-line Telemetry section between Install and the product tour becomes one collapsed block at the end of Docs: a plain summary line, the notice verbatim, one sentence and the link to docs/TELEMETRY.md. The notice block is unchanged, so it still matches the binary, the installer and docs/TELEMETRY.md. Replaces #1112.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NoeSVN8nqmwNVRXExgoUNN
* santos/dev lands on dev: crew family, Pareto crewing, the Model Pool, custom connections (#1194)
Lands the integration branch santos/dev (#1108, head 6db5125b2, 152 commits over dev) on dev as one squash, plus two fixes that kept its touched-packages job red: the pool start-up test empties the CI word it is not about (649bb4bfd), and a zombie leader no longer keeps a job's process group alive on Linux, which had delayed every finished background job by the two-second termination grace since #1155 (053e6a90f). #1108 carries the full account; the 94 change entries under docs/changes/unreleased/ are the per-change record.
The commits folded in, oldest first:
5c413ef7b Keep archived evidence readable while tasks finish
3705a0cfe Document recovery evidence retrieval change
7834cc7d0 tui3, manual: a question's own answer box answers to the whole caret vocabulary
99d66e98c task: Add open/all source toggle to crew config
c1e4cb57f docs: the change entry for the crew model family toggle
e63b43927 crew: round-1 review fixes
304a5a223 crew: round-2 review fix
65477c0c5 task: Add open/all selector to /crew TUI picker
9189ef764 Merge branch 'task/add-open-all-selector-to-crew-tu-9e8cc0' into feat/crew-open-all-toggle
ba9c12d61 crew: reconcile the picker onto config's source helpers
ea05bc0f5 crew: a chosen family counts as an answered crew
e1a037e0a Merge remote-tracking branch 'origin/dev' into feat/crew-open-all-toggle
f6c2924a7 crew: the open table takes the picks we landed on
eff44b542 docs: the change entry carries the open-table move and the family gate
71ce9bec0 crew: the family reaches the fallback, the settings skin, and the row's line
b8ca5f513 crew: round-1 review fixes on the new table
8db5708ef crew: round-2 review fixes
ce9759ef4 crew: round-3 review fixes
956e1f514 crew: round-4 review fixes
37ad27f4e crew: fixes from the first Opus round
6ffb95813 crew: the fixes from the Opus confirmation round
72b027436 crew: the comments the atomic write left behind
70d0e205b crew: round-four fixes from the Opus review
234300e37 Merge branch 'dev' into feat/crew-open-all-toggle
894292f28 crew: round-five fixes from the Opus review
fba77f92d An answered landing carries its answer's fate when it is raised again, and an in-flight settle holds the question down (#1077)
e69445058 Changelog entry for the landing-answer fate (#1086)
64ab7eae0 crew: round-six fixes from the Opus review
070016419 crew: round-seven fixes from the Opus review
af09aa852 The review round's four findings: claim ownership, decider changes, recordable answers, plain words
c24af0248 crew: round-eight fixes from the Opus review
289d372b9 The tests the landing's answer carries: fate, hold-down, redraw, claim doors
7e38346a9 The take-down comes before every mint, and the tui3 walk reads the newest card
dbe1be03e The review rounds' last word: the release owns its claim, and the docs say what the code does
4cc4945a7 The Opus review: a release owns its generation, and every failed round still says its word
a5cce0dde The done card says who is deciding, so the clause is a duplication, not the fact
6bd276e6c Merge fix/1077-landing-reraise into santos/dev
271016938 Merge feat/crew-open-all-toggle into santos/dev
b459399d3 Merge fix/question-answer-box-caret-keys into santos/dev
a38492026 Merge codex/recovery-evidence into santos/dev
dc22e6461 cmd/codeaf: the role-door tests read the shipped mastermind instead of a copy of it
39f528f70 release: the pin-example check reads the guide the examples moved to
6439d3cb8 session, tui3: gofmt the three files santos/dev merged unformatted
854037967 tui3: a question's answer box kills to the end of the line on ctrl+k
d93ec61ea session: the late-attach proposal test holds the work until the replay is read
a81ead4de session: the landing-fate tests read today's clock instead of a fixed date
8fe4fff38 provider: the retry-avoid list rides the call's context into the knobs
a266da3e2 provider: the retry-avoid veto narrows the wire through one field law
197d89334 exec: a node retry asks the router to avoid the lanes that failed it
2d02cc0b9 provider: the set-servable law's doc comment keeps its paragraph break
e1d0e7524 exec: the retry test names its helper and spells its wall in time units
e7d65a517 docs: the change note for the retry that avoids the failed upstream
11decbd92 Merge fix/provider-failover into santos/dev
c099a51c2 Merge dev into santos/dev
e47d92bde provider, exec: the lane a failure names is a wire fact provider reads (#1105)
396be97be Merge dev into santos/dev
3b97f50c3 Merge dev into santos/dev
ea3b5c9a0 telemetry: the send path drops events that cannot name their version
573b288e4 cmd/codeaf: keep smoke runs from sending usage counts
e8d627c6b docs: the change note for the usage-count audit fixes
11bec8d80 chat: a hosted session's usage counts are read off the events it receives
b9d75b39e chat: the hosted-count tee is tested against the tally it must produce
39fa08d3d telemetry: stamp a version in the lifecycle tests
681e2adf1 chat: count the hosted boot agent once, and conversations opened beside
825ef2c41 connect, settings: named, multiple, switchable custom connections (#1092)
f4d3f9a1a Merge branch 'dev' into fix/telemetry-audit
76fec37e3 ci: the Model Pool mirror workflow and the signature check it runs
2fb296bf1 crew: Pareto crewing, the learned picker and the Model Pool (#1093)
a065ebb1b Merge remote-tracking branch 'origin/dev' into santos/dev
80ac250a0 Merge remote-tracking branch 'origin/feat/pool-mirror-workflow' into santos/dev
6092393ab Merge remote-tracking branch 'origin/fix/telemetry-audit' into santos/dev
ef808dda4 session: a decision card under --yolo takes its default (#1117)
70a9e1f6e session: a task's thread stops its parts before it closes, and a machinery cut says so (#1118)
c4df8f364 crew: an auto seat's rung names the pick that ran, once, for both doors (#1119)
a9fcf9bc8 crew: a bare auto row under picked from = catalog reads the catalog's figures alone (#1120)
13be0dce4 relay: accept the exec and run doors, not only task and do (#1121)
90f29aec1 changes: name the #1120 note by its PR and stamp the pr field
0b77926ca do: seat from the settings the run will use (#1122)
32148d87d changes: stamp pr: 1120 on the #1120 note
113ed628e pool: a launch's start-up errands stop when the process closes (#1124)
6c98ddca3 verify, codeaf: a launch compiles fewer patterns and a surface holds fewer Ps (#1125)
50fe6a3e4 pool: the min_installs floor counts installs on the client (#1127)
076cde8ae relay: fold a resubmitted row once by its nonce (#1128)
8339ae71b relay: carry the acceptable metric beside role_quality (#1129)
0367c441b outbox: a refused row leaves the outbox and the rest of its batch is sent (#1130)
09aecd2f1 relay: the index holds only the cells that meet the min_installs floor (#1131)
ae7c05dcd outbox: a Send compacts the file to the rows it still holds (#1133)
9e24f72d8 pool: the errand tracker's critical sections unlock from a defer (#1134)
358a569aa relay: fold a submit batch with one read and one write per distinct cell and day (#1136)
a1d2eb1f7 pool: judge landed-but-unjudged runs on the next chat start (#1132)
3c6722859 verify: take the finished-tree check at a project cloned into a subdirectory (#1135)
263625b63 exec: a headless run leaves a pending judge record at its tail (#1137)
8be373d39 run: the headless task door leaves a pending judge record (#1138)
a336b246e do: leave a pending landing for the Model Pool's judge (#1139)
8820a5659 cmd/codeaf: one readPendingRows test helper, not two (#1140)
49760fb45 pool: show and verify print both metrics the index carries (#1141)
6eaeb25c9 pool: status shows the pending judge records and the last sweep (#1142)
7c00b5f2c codeaf: a test's crash fixture stays in a profile the test owns (#1145)
fc2eb357a manual: the status row's ledger is the tree's, not the conversation's (#1143)
a06b53a91 test: pin the delivery gate over a grown job root (#1147)
7231347eb resident: the wall refuses a first replan round it cannot hold (#1144)
5e257557f cmd/codeaf: the package's test floor clears a profile the environment named
4dd1c562f Revert "cmd/codeaf: the package's test floor clears a profile the environment named"
9075f863c pool: the seed index is regenerated from the relay by seedgen (#1148)
a5c44f3d2 pool: show --cells lists the held index's cells with installs and dims (#1149)
825996739 cmd/codeaf: the package test floor clears a profile the environment named (#1150)
81568aa82 session: report gitignored build products a run leaves, without gating on them (#1152)
da4910593 internal/tui3: the opening hint test owns its profile and pins both doors
72de3bca7 docs/changes: #1151 — the opening hint test owns its profile
499083d1c Revert "docs/changes: #1151 — the opening hint test owns its profile"
beb31ecf7 Revert "internal/tui3: the opening hint test owns its profile and pins both doors"
25b8b7dea version: an unstamped binary names the condition, not a Makefile target (#1151)
c833b423a pool: a dropped row keeps the relay's reason and status shows it (#1154)
cbb7d6d9e processgroup: verify a job group's identity before signalling it (#1155)
efe498ed0 internal/tui3: the opening hint test owns its profile and pins both doors (#1153)
17b3b0e40 do: a continuation continues the plan it has instead of re-planning (#1156)
22cf3ce17 changes: correct the #1155 and #1156 notes' pr fields (#1157)
8e85b0fe7 cmd/codeaf: a surface runs under a soft memory limit drawn from the machine (#1158)
ef1e92756 task: status row accounting (#1159)
44f572e26 pool: status's index line says what this run's fetch did to the cache (#1161)
3600fc9a5 pool: the pool's copy of a seat's id is the bare vendor/id (#1163)
a2ebd1397 cmd/codeaf: no test can push pool rows to the default relay (#1164)
4fb7f0546 docs: the road a chat door bash push took under --yolo (#1160)
69219a1e1 cmd/codeaf: the soft memory limit is the smallest real bound, not the host s memory (#1162)
2b155b4b4 relay: bound judge severity, clamp adjusted scores, publish mean and sd on one scale (#1165)
2fb55324a relay: purge fixture vendors and refuse them at the door (#1167)
57504187a exec: a job's shell cannot reach the tmux server hosting codeaf (#1166)
eb7b46559 internal/session: an unattended run may not move a branch it did not create (#1168)
80f770639 pool: status says the identity, the judged total and that nothing has landed (#1169)
1cb7333fa exec: an exec run's worker spend reaches the usage ledger (#1170)
96bb9402e changes: the #1169 note's title parses and reads as one line (#1172)
627236d95 config: the task door honors a stored crew word, and a pin survives the learned pick (#1171)
593092be6 internal/tui3: a test may not read a profile it did not create (#1173)
ad8be1ed7 session: a landing card under --yolo takes its default instead of parking the run (#1174)
03d49a678 gitignore: the .furrow ids the engine writes into a workspace (#1175)
46edbdd32 internal/tui3: gofmt the profile-law helpers from #1173 (#1176)
3179e3611 relay: ALLOWED_VENDORS names the catalog's vendors and codeaf (#1177)
397a145a6 docs: why a settled /task leaves commits on task/<slug>, not the worktree branch (#1178)
915ff3a76 pool: regenerate the seed index from the relay's first clean publish (#1180)
d9b42430f cmd/codeaf: the model warm stops when the process closes (#1179)
bd2dcf334 session: the auditor's calls say they are the auditor's and which node they check (#1181)
c6ed47c5a task: json unverified branch (#1182)
360352ad4 session: a settle turn runs under the checker's own bound, not the run's wall (#1183)
814e1af0e session: the tasks text and record line name a failed/unverified node's kept branch and verdict (#1184)
7c25a26d9 internal/session: the identical-effects test stops riding the turn guard (#1185)
6e7d0ed44 cmd/codeaf: exec and run envelopes name a non-verified node's kept branch and verdict (#1186)
f4079d716 session: bound a worker's park on a promoted command (#1187)
994689fe7 docs: the model pool runbook names the Workers Paid plan and what it costs (#1188)
c315be13e docs: the runbook's plan line says metered, not capped, and nothing more (#1189)
2e80c60d8 internal/tui3: the status word says working while a task subtree turns (#1191)
99363ca8f session: bound a job subtree's CPU and process count (#1190)
6db5125b2 docs: what the audit check seat can execute, and where that boundary is set (#1192)
649bb4bfd cmd/codeaf: the pool start-up test empties the CI word it is not about
053e6a90f processgroup: a zombie leader does not keep a job's group alive
b4e66f515 docs/changes: the entry for #1194
Co-Authored-By: Santosh kumar <29346072+santoshkumarradha@users.noreply.github.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* ci: Model Pool mirror workflow (signed index onto the model-pool branch) (#1116)
* ci: the Model Pool mirror workflow and the signature check it runs
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs: the change entry for the Model Pool mirror workflow
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: santoshkumarradha <eng@agentfield.ai>
* chat: the unconnected custom row on /connect keeps its vendored name (#1195)
modelConnectionStatus renamed every custom-id row to the connection's Written word, and the catalog template's Written is the bare id, so a person who had connected nothing yet saw `custom` where the manual, the README and #1107 say `Custom OpenAI-compatible API`. Only a connected instance is called what the person called it now; the contract test draws both rows and is red without the fix. Found verifying the staging build of #1194.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: v0.3.0 rolled up into CHANGELOG.md (#1196)
95 loose entries — the crew family and Pareto crewing, the Model Pool and its relay, custom connections, the telemetry audit, the update door's download clock, and the fixes that followed — become the `## v0.3.0` section the stable release reads its notes from.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* ci: a changed directory in a nested modu…
Integration branch
santos/devintodev. Draft: it is the running index of what the branch carries, and it stays a draft until the worker harness is complete, the independent end-to-end pass on Spark is green, and Santosh has tested it himself.State
dev. Everything through docs: what the audit check seat can execute, and where that boundary is set #1192 already reacheddevas santos/dev lands on dev: crew family, Pareto crewing, the Model Pool, custom connections (#1108) #1194 on 2026-09-18, anddevhas been merged back each time it moved (ci: Model Pool mirror workflow (signed index onto the model-pool branch) #1116 mirror workflow, chat: the unconnected custom row on /connect keeps its vendored name #1195 /connect custom row, docs/changes: v0.3.0 rolled up into CHANGELOG.md #1196 v0.3.0 changelog).make checkon Spark, fresh clone, on the exact commit. The check has cross-compiled every release target since build: cross-compile the shipped platforms in make check #1254.CODEAF_TASK_BELT=bashis set, so the default road does not move.The worker harness
One loop under
/taskandcodeaf do, with a plan store per run, a plan seat, a work seat, a check seat, and a review round after each piece of work (#1109)./task,codeaf do, and a task the chat starts by itself all take the same road; a landing wakes no model turn, and a reply comes only when an answer is owed (The chat's role: a landing speaks only when an answer is owed #1205).--check-model,CODEAF_CHECK_MODEL, a pinned seat, then the profile (a belt check runs on the crew checking seat, not the thinking seat #1207). A declared check is read the way a shell reads its quotes (session: a check is one command as the shell reads its quotes, its refusal says what passes, and side-by-side calls are one attempt #1215).codeaf dorun whose root finished itself still gets its review (fix(run): a self-finished codeaf do run seats its review before it ends #1233, run: regression test for seating the check after a self-finished worker returns #1243); a parked task is finished only by a worker woken for it (A parked task is finished only by a worker woken for it #1271).Stopping and limits
A person's stop reaches a run. The stop ends the run's task and everything open under it in one write, cuts the run's context, keeps the work on the run's own branch, puts nothing into the person's folder, and buys no model turn; ctrl+c is read above a page that is loading or open (fix: a person's stop reaches a run #1250). A stopped task reads stopped wherever its state word is drawn (fix: a task you stopped reads stopped wherever its state word is drawn #1258).
A time limit ends a run. A run is handed what is left of the conversation's time; work in flight is ended and its endings are absorbed (run: a time limit a person sets ends a run by the same road as the cost limit #1262).
A dollar limit holds while a worker is still working. A worker tells its run what it has banked as each call is paid for, without ever waiting on the run; a dollar is counted once, and what a run counts as spent never goes down (A run's dollar limit holds while a worker is still working #1268).
A run's dollars reach the conversation's total. The run hands its owner its running total whenever it rises, with or without a dollar limit, and the conversation closes on the run's final figure before any ending splits off, so every ending counts once (session, run: a run's dollars reach the conversation's own total #1280).
An ending a person caused is not a fault. A run ended by a limit says which one,
a time limit you set stopped itora dollar limit you set stopped it, with no fault colouring; the first limit reached names the ending, the tasks that ending cut read the same way, and a task that failed by itself keeps its own reason (run, session: an ending a person caused is not a fault, and it names the limit that caused it #1279).A run is handed what is left. A run's dollar ceiling is the smaller of the conversation's dollar limits, including one typed on the command line, less what the conversation has already spent, so a second run gets the remainder after the first (session: a run is handed what is left of every dollar limit #1281).
A cancelled command is ended by the call that ran it. A cancel that arrived as a command started could leave it running under no parent; the cancel arm now sends the kill itself unless the call was adopted or already reaped (exec/bare: the arm that ends a cancelled call's wait ends its command #1282).
A worker that has stopped making progress is told once, then ended. The same command coming back with the same answer, with nothing moving under the worker's own task, brings one note from the belt saying what the worker can do; three more identical steps end the task with a reason a person can read. A task blocked on another task is parked, not ended (run: a worker that has stopped making progress ends, by an observable property #1266).
The task page and the rail
The engine host and sign-in
The profile
config.jsonthat nothing reads are said once, in the conversation, and never for a key the product itself writes or retired (config: report unread profile config keys once at load #1223, chat: name unread config.json keys once before defaults apply #1239, config: unread notice skips keys the product itself retired #1245).Nothing keeps writing after the process closes
Tests and tooling
scripts/(scripts: a repeatable hosted drive of a run on the real binary #1241).Also on the branch
Landings
santos/devinternal/lanecleared by mechanism, not by rerunStill to come before this leaves draft
Already on
devthrough #1194, kept for the recordWhat follows reached
devon 2026-09-18 as #1194 and is unchanged since.What a person gets
models.crew.source = open|all(defaultall), or the open/all switch in/crew.santos/dev(#1073)auto./crew catalog, ormodels.crew.pick = catalog.santos/dev(#1093, squash 2fb296b)table,catalog,learn/crew table|catalog|learn,models.crew.pick.santos/dev(#1093, squash 2fb296b)/taskrun an independent judge scores every seat (billed to ajudgeseat). Scores go to your own sheet and feed the picker next time, blended with the pool by observation count, so your own runs improve your own picks first. Starts from a seed built from 145 real runs, so learning works on day one. A seat you type by hand is judged too.pick = learn.codeaf pool showlists what the picker knows.santos/dev(#1093, squash 2fb296b)model_pool on|read|off(defaulton, notice shown once).codeaf pool show|status|verify [--json].santos/dev(#1093, squash 2fb296b)relay/with a runbook; it is live athttps://codeaf.agentfield.ai/pool. The signed index is mirrored to themodel-poolbranch of this repo so anyone can watch it update. A team can run its own private relay with its own key (CODEAF_MODEL_POOL_RELAY_URL,_MIRROR_URL,_PUBLIC_KEY).santos/dev(#1093, squash 2fb296b)docs/design/model-pool/pareto-crewing.pdf("Pareto Crewing"): the objective, estimator and picker, with figures from real runs.santos/dev(#1093, squash 2fb296b)/modelgroups models under each connection's name. Switching onto a keyless default service is refused with a reason./connect→ Custom OpenAI-compatible API;/settings→ Providers → add / edit / active connection.santos/dev(#1092, squash 825ef2c; Santosh e2e-tested locally against a local OpenAI-compatible proxy)/taskanddo/taskdoor andcodeaf do.Bug fixes on the branch (question answer-box keys, landing answer fate, retry avoiding the failed upstream, recovery evidence, taxonomy lane read, and, with #1092, mid-session
/connectnow reaching the live conversation on the engine road, a pre-existing hole) are not listed above; each has its own change note underdocs/changes/unreleased/.Known limits, stated on purpose
/taskdoor only;codeaf do,askand remote sessions do not feed the pool yet.codeaf pool verifypulls a fresh copy, read at the next start.Relay status
Live at
https://codeaf.agentfield.ai/pool(healthz 200, index signed,codeaf pool verifygood). Themodel-poolbranch exists and carries the current signed index (refreshed hourly by a stand-in job until #1116 puts the workflow ondev). The pool is primed with the same measured runs the embedded seed encodes, so the published index carries real cells from day one.End-to-end pass on Spark (independent session, done)
All 12 steps pass on #1093's head (cf4ea35; final fd29d79 differs by a runbook sentence). Report:
spark:~/src/e2e-learn-2026-09-17.mdwithKNOWN-LIMITS.mdandevidence/INDEX.mdbeside it; 18 capped runs, about $26.learn, judged tasks, own sheet + outbox flushedreadandoffsend nothing/modeloverride underlearnis still judgedauto/catalog/learn seats resolve on headless doors/crewchooser and/settingspool row with noticecodeaf models,--refresh, daily cachedo/exec under a learn crewFollow-ups from the e2e, now on
santos/dev: a task's thread stops its parts before closing and a machinery cut records its reason (#1118); a decision card under--yolotakes its default (#1117); the auto crew row shows the rung it actually resolved to (#1119); a bareautorow underpicked from = catalogreads the catalog's figures alone (#1120).codeaf doseats from the settings the run will use, so a fresh profile with the key in the environment reads the catalog, not the table (#1122); the relay accepts the exec and run doors (#1121); a launch's pool errands stop when the process closes instead of writing into a closed profile (#1124); a launch compilesinternal/verify's patterns on first use and the engine host runs on a capped scheduler (#1125); the client'smin_installsfloor counts installs, as the relay's does (#1127); the relay folds a retried batch once by its nonce (#1128), carries anacceptablemetric beside the judge score (#1129), publishes only cells that meet the floor (#1131) and writes once per cell per batch (#1136); a refused row leaves the outbox and the file is compacted (#1130, #1133); the pool errand tracker's critical sections unlock from a defer (#1134); a run a process death left unjudged, and any headless door's landing, is judged on the next chat start (#1132). the finished-tree check reads a project cloned into a subdirectory (#1135); the exec, run and do doors leave a pending record for the sweep (#1137, #1138, #1139); the wall admits a first round it cannot cost and refuses an overrun it cannot hold, so a longcodeaf dolands instead of re-planning to the wall (#1144), with the delivery gate over a grown job root pinned by a test (#1147);pool show,pool verifyandpool statusprint both metrics, the pending judge records and the last sweep (#1141, #1142); a test's crash fixture stays in a profile the test owns, and the package's test floor clears any profile the environment named, and the opening-hint test reads a profile it made and pins the greeting contract both ways (#1145, #1150, #1153), and tui3's package law makes every surface-building helper name a profile of its own (#1173); the manual's status row says whose ledger it is (#1143); the seed index is regenerated from the live relay by one in-repo command, so a fresh install's fallback is a verified copy of the pool (#1148);pool show --cellslists the held index's cells with their installs and dims (#1149); a landing that leaves gitignored build products behind stays complete and the reconciled row names them (#1152);codeaf versionon an unstamped binary names the condition, no.gitdirectory for the toolchain to read, instead of blaming a Makefile target (#1151).pool statussays when the relay dropped a row and why, instead of the row vanishing silently (#1154); a job teardown records the group leader's identity at launch and never signals a process group the kernel has since handed to someone else (#1155); acodeaf docontinuation after an overrun continues the plan it has from the recorded turns instead of re-planning from scratch (#1156); the process sets a soft memory limit of half the machine's memory, nothing below a 512 MiB floor, an explicitGOMEMLIMITuntouched, carried intoengine --daemon(#1158), and the bound is the smallest finite one of physical memory and the cgroup v2/v1 limits walked from the process's own level to the root (#1162);pool statussays when this run cached the index, so the seed-to-cache flip is visible in the run that caused it (#1161). The pool's copy of a seat's id is the bare vendor/id, so a fresh install on the default model (whose seat carries codeaf's alias marker) no longer has its first rows refused by the relay, and the judge picker's same-vendor exclusion works on it (#1163); no cmd/codeaf test can push rows to the default relay, the package floor pins a dead address (#1164); the relay bounds each judge's fitted severity to ±10, clamps every adjusted score to the rubric, publishes mean and sd on one scale and falls back to the median when spread is zero, which is what had published a cell at 103.5 (#1165); the relay can purge stored rows from a fixture vendor and refuse vendors not inALLOWED_VENDORS(#1167), withALLOWED_VENDORSset to the catalog's vendors plus codeaf (#1177, Worker version 47102a26; 624 fixture keys purged from the live store); the built-in seed is regenerated from the relay's first clean publish after the purge, 18 cells, no fixture rows (#1180); a job's shell no longer inherits the host's TMUX handle and gets a profile-owned TMUX_TMPDIR, so a command the model runs cannot kill the terminal hosting codeaf (#1166); an unattended run (--yolo, nobody to answer) is refused agit push,mergeorrebasethat would move a branch it did not create, including the branch the checkout began on, while its own task branch stays pushable and attended sessions are untouched (#1168, the road it took is in #1160's note);pool statussays the install's identity, the judged total across all doors, and "none yet" when no landing has been judged (#1169); an exec run's worker spend is minted into the usage ledger at the door, one row per run, so the status row, the cap and the pool row count it (#1170); the task door honours a storedmodels.crewword (every arm had resolved to balanced) and a pinned tier row survivespick=learninstead of being recomputed (#1171); a landing card raised on the check road under--yolotakes its default and records that the dial answered and that the check ran out of time, instead of parking a headless run forever, while conflict, shift and ground landings still park and now say so in the record (#1174); the model catalog warm is seated on the profile's start-up errand tracker so a process close joins it, instead of a warm outliving the process and writing its cache into whatever state root was current (#1179); the auditor's calls tag themselvesauditorwith the node they check, and its usage rows carry the auditor role and the task, so a ledger tells an audit call from a session turn (#1181); a headlessdo --jsonwhose node ends failed or unverified names the kept branch and the verdict in its envelope, so nobody digs through tasks.json for kept work (#1182); the settle turn a landing note wakes undertask.settle autoruns under the checker's own bound, a call ceiling and a share of the run's cap, one call for a clean tree with no declared check, and records "not settled within its bound" instead of running to the wall, which had been a one-to-two-dollar tax on most headless runs (#1183); the chat-sidetaskstext and a resumed session's record line name a failed or unverified node's kepttask/<slug>branch and its verdict word, the same two words the headless envelope carries (#1184); the identical-effects test is deterministic, its forty saves carrying distinct call signatures so the turn's repetition guard cannot end the turn and the leash is the only thing the assertion is about, which closes a margin-of-one race that had read as a load flake since #284 (#1185); a non-verifiedcodeaf execorcodeaf runnames its kept branch and verdict in its envelope through the one result-envelope seam the three headless doors share, so do, exec and run answer alike (#1186); a task worker parked on a command it started (a bash call the 30-second background clock promoted to a job) waited the node's whole allowance when the job never ended, which is what held a DOE run silent for 53 minutes under a live cap; the park now has a bound of its own, a third of the allowance, posts "the park was not settled within its bound" and hands the turn back while the command keeps running, with the diagnosis at docs/notes/yolo-task-worker-parked-on-promoted-bash.md (#1187); the model pool runbook's plan line says metered, not capped (#1188, #1189, docs only); the status row saysworkingwhile the door's task subtree turns, read from the same signal the tab strip draws from so the two cannot disagree, with the manual's screen and task-page sections moved to match (#1191); a job subtree is cut when it passes a CPU or process bound, 60% of the machine sustained for 30 s or 128 processes when nothing else bounds it, the process backstop alone under a cgroup or affinity quota, and the run learns it as "the job subtree was not settled within its bound", which is what a model that spawns infinite loops under a dollar cap had escaped (#1190); a note records what a task's audit step can execute and where that boundary is set, the declared checks plus read-only git and coreutils, which is why a brief that declares no check leaves a cautious auditor nothing it may run (#1192, docs only); the prose lexer registry loads a curated set of forty languages on first use instead of parsing all 279 of chroma's lexers at init, plain text for the rest, which takes about 3 ms off cold start and 2 MB off the binary, with chroma's files and licence carried beside the copies (#1193). Still open, PRs in progress: the footprint benchmark method and table under docs/benchmarks (#1126); Pareto crewing v2 with a model-free grader (#1123, Santosh reviews). The "task-branch merge fails 1 in 3" observation was the test driver killing runs mid-check, not a product defect.Related, not on this branch
devdirectly (must ride staging and the next main release; the website relay fix is already live). Also merged intosantos/devso the e2e covers it.devdirectly (workflow file + verifier only), so themodel-poolbranch is refreshed by Actions; until then a stand-in job on Spark refreshes it hourly. Also onsantos/dev.Before this leaves draft
santos/dev;dev, telemetry: audit fixes — hosted chat counters, no unversioned sends, silent smoke tests #1111's and ci: Model Pool mirror workflow (signed index onto the model-pool branch) #1116's branches merged on top (6092393).santos/dev.make checkon the finalsantos/devhead, on Spark — done atd39a4e308: EXIT 0, 116 packages ok, 0 failures, 0 cached, fresh clone. Pre-checks on the same head: package laws rc 0, 80 change entries all well formed,gofmt -llists nothing,go build ./...andGOOS=windows go build ./...both rc 0.Slice line
This branch is held at
d39a4e308as a reviewable slice. Two landings since the slice was first cut: the drafted-with footer links to the CodeAF repository rather than to agentfield (#1329), and a held landing offers its answer and stops demanding one (#1331).santos/dev2carries the same head and is where work goes once Abir picks this up. Work that lands after this goes on the next shared branch so the slice stops growing under review.