Repository navigation
Conversation
…way net (Agent-Field#923) * The turn decides, informed; promotion inherits; the ceiling is a runaway net A one-line read-only design question read home-panel files for ten rounds in 48 seconds and was taken away from the conversation that was answering it. The round-10 ceiling fired, a summary reader said `split`, and a cold worker opened on a brief plus stub pointers: its first six calls re-read the chat's own results, then fourteen more files, 551k input tokens at 24% cached over 393 seconds, and it never ticked an item. Three things were wrong at once. The decision was made by the wrong party — a reader of a summary rather than the model holding the context. It was made on the wrong signal — a count of rounds, which measures nothing about whether the work is going anywhere. And the move threw away everything the turn had read. So the count no longer moves anything, and what it buys instead is a sentence. THE TURN DECIDES, INFORMED. The rungs below the last one call nobody and move nothing. They put one note into the running turn at its next step, through the one ambient door a loop nudge already uses: the facts it cannot see about itself (rounds so far, distinct files read, bytes of results held) and the three roads on, in plain words — answer now; carry the rest on in a room with `quick_task` and `inherit`; hand out what it has not read. The cost is stated once, where the choice is: a worker that does not inherit opens on a brief about your work instead of on your work, and reads it all again. No timer, no model call, no message[0]. PROMOTION INHERITS. `quick_task` gains `inherit`: the worker is a read-only fork of the caller's transcript, so its first request carries the caller's messages and tool results verbatim and it reads nothing twice. It is bounded by a property rather than a number — refused, in a result the model reads, when the caller's context does not fit the worker model's own working room (`compactThresholdOf`, the build's own line for how far a conversation may grow), and the refusal names the road still open. THE RUNAWAY NET. `readMark` survives as the last rung only, and it no longer asks about rounds: it fires when the turn's context has passed the room it can still work in, when the loop detector has already nudged twice, or when the wall has run out. Each of those is a fact the build already had. A turn reading ten files in 48 seconds reaches none of them. AND THE CARRY-ON ROAD PROMOTES. When the net does fire, the carry-on goes through the same admission door as the tool, with the drawn items as its checklist and the context inherited. The brief road survives only where inheritance cannot go — the rung that fired because the context is too big to carry — and there the brief now carries the compiled results themselves rather than pointers at calls the worker would have to run again. Deleted with it: `checkpointSplitNote` and the `split` decision, the seam mark, `quickFromDrawing`'s bare-spec path, and the stub-pointer section for an inherited worker. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The late-drawing fixture buys its reading at the net, not at the first mark Agent-Field#962's fixture holds a drawing past the turn's last step, and it opened that window by crossing the FIRST mark. With the rungs below the last one buying nothing, the first mark asks nobody, so the fixture now takes the turn to THE RUNAWAY NET instead: every scripted round reports a fuller window ([checkpointFillAt]) until the context bound fires, and the note rungs' own rows are dropped from what it returns, because a row that cost no call is not a row about a drawing landing late. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * manual: the page about a brief that could not be written carries the asker's words in its heading The probe "the run said the brief could not be written, what happened" reached adaptive-runs in the last of four slots on dev and lost that slot once this change's task pages said more about briefs. Retrieval is the feature, so the heading now says it the way a person asks it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…Field#935) * The person's word wins at the request, never at the next turn A model a person names while work is running used to land at the next TURN. For a conversation that is seconds; for a task step it is up to twenty minutes. On 2026-09-11 a step sat thirteen minutes into a wait, the owner picked another model and typed continue, the room answered `its next turn takes it`, and the step was still talking to the model they had moved off a minute later. The pick now reaches the work at the next REQUEST, within lane.SpokenWithin, through one door: - activeGeneration carries the turn's own partial buffer, so `productive()` — has this request produced anything a person could use — is a state read of the text already on their screen rather than a second count of the same deltas. - Agent.hearModelLocked is the one place a person's model reaches running work: it records the word for the boundary and, when the request has produced nothing, cuts it through cutGenerationLocked with a third cause, errPersonCut. It answers ModelLandsNow or ModelLandsNextRequest. - runTurn re-reads the word at ONE site, the top of the request ladder, and starts the chain again from the model they named. freshModel is now the one place a model gets a whole budget of its own; the rescue hop calls it too. - The room says which of the two happened — `switching now` or `the next request takes it` — and never the word "turn". RetargetTask carries the landing, over the wire as well. generation_law_test.go fails the build on a second place that cancels a generation. The manual's five claims about "the task's next turn" are replaced by what is true, and models-and-cost.md gains the section somebody asks for when they press a model mid-reply. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * docs: the change entry for Agent-Field#935 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * The beat law follows the door to the function it hands to SetModel is one line now — the work and the answer to when the pick lands live in setModel beside it — and the law that says a picked model reaches the lane beat was reading the door's own body. It reads the road the pick takes, and still cannot be satisfied by a door that does nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * The model-latch fixture pins the arm that is still true TestSetModelAppliesFromTheNextTurn asserted the contract this change replaces — a swap landing at the next TURN — so it was the defect written down as a test. What is still true from that seat is the case with nothing in flight to let go of: a word said while a tool is running is cut from nothing and rides the very next request. personsword_test.go holds the other two arms. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * The person's word is the head of every chain A failing step walked its own fallback ladder past a model the person had just named, and a step whose completer offers no chain ended the turn on "there is nowhere else to try" with their choice unasked. The move takes the word where the move is really made, so the line a person reads names the model their reply actually went to rather than a rung the boundary was about to overrule. takeTheModel is the one place a step changes model, and `root` — whose chain this is, a fact about the move and not about who made it — is the only thing that differs between the two roads. The reading of whether a step can move at all PEEKS at the word, because it runs on every failure including the ones that ask the same model again. Three stale comments go with it: SetReasoning claiming a level latches "exactly as the model does" when the two rules are now deliberately different, auxiliary.go's errand floor, and completeWithRetry's "2s, 4s, 8s, max 3 retries" — budgets deleted before the recovery wave. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSshDkszBQ9RpR4dPsC5fQ * Agent-Field#925's two conversation sentences are false now, so they go The rebase carried Agent-Field#925's words onto a tree where the cut makes them untrue. `a pick in a conversation you are sitting in front of still lands on your next message` and `a model you pick with /model does not redirect a rescue that is already happening` were both true on the day they were written and neither survives the request boundary: a pick lands on the next REQUEST, and a person's word is the head of the chain. The room's own sentence loses its rescue clause with them. It was worth a clause while the pick had to wait for a move somebody else made; now the next request carries the pick whether that request is a rescue, a retry or the step's own next step, so naming the rescue would name one road out of three. Agent-Field#925's `TaskNode.picked` is untouched. It owns where a node's NEXT WORKER is built and this owns the request already out — two scopes, no second mechanism. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * One reading of what the person has read, and one door for every word Four things the review found, and all four are the same shape: a rule stated in one place and answered in two. ONE READING. `has anything reached the person` had two answers five lines apart in the same stream observer. The recall's gate counted a reasoning delta; the person's word did not, and said so on the page — `thinking where nobody can read`, which the code contradicts, because visible thinking is drawn and Agent-Field#760 made a reasoning-only turn something somebody watches. `reachedThePerson` is the one reading now: a word of the answer, a word of visible thinking, or a tool row formed far enough to be spoken. `recallAside.token` is deleted and the aside reads the turn's own. A person's word can no longer let go of a request that has drawn anything at all, which is also what closes the withdrawal gap: the state where a cut takes a thought off somebody's screen is unreachable rather than handled. ONE DOOR FOR EVERY WORD. `continue` typed into a room was enqueued and never heard — drained when the request it interrupted ended, which on the owner's own step was thirteen minutes later. That is the other half of the 14:40:10 evidence and the report claimed it was already done. A direction goes through the same hearing door the pick does. The CAUSE is the caller's, and it is the one thing that genuinely differs: a model changes what the next REQUEST rides, so it is answered at the request boundary; words change what the next STEP carries, so a direction takes the conversation's own `errSteerCut` and returns to the boundary where queued lines are drained. THE ROOM IS TOLD. The cut sends `EventRetrying` with `Next` naming the model they chose — the one door that already means `this attempt is void` — so the wait a person spoke to end stops counting. And the waiting line no longer says `trying again` when the news is a move: the row it is composed from says `moving to <model>`, and somebody who picked a model should not be told their choice was a failure being recovered from. A rescue hop's status line agrees with its own row now for the same reason. THE LAW FOLLOWS THE VALUE. The one-door test matched three tokens, so a local named `generation` — which `completeWithRetryReasoning` already binds — walked past it. It enumerates every road that hands out a generation and flags anything reached by one, however it is named. And the door compared a pick against the SESSION's model rather than the one a rescued step is riding, which cost a whole cut request when somebody picked the fallback the step was already on. `Agent.riding` publishes what the ladder always knew. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The person's word is not a boundary cut, and the one door holds both Agent-Field#962 landed mid-review with `boundaryCut`: a cut whose REASON rides no transcript is owed rather than dropped, and `beginGeneration` spends it. The rebase composes cleanly because both changes are about the same door — Agent-Field#962's owed-or-dropped decision lives in `cutGenerationLocked`, which this lane had already made the single cancel site, and `beginGeneration` spends the owed cut THROUGH that door rather than reaching for the handle it is holding. Neither of this lane's causes is a boundary cut, and the test Agent-Field#962 states is what says so. `errPersonCut`'s reason is written to `Agent.spokenModel` before the cut is raised and taken from there at the request boundary; a direction is on the worker's queue before its cut. Both ride something the next request reads either way, exactly as a recall's block rides the transcript — so a word arriving between two requests needs no cut at all, and owing one would cancel a request that was about to be right. And this cause has a second reason of its own: an owed cut reports itself answered, and that answer is what the room says out loud. A person would read `switching now` over a pick that is in fact riding the next request. The one-door law was re-run against Agent-Field#962's new spend site and catches the shortcut Agent-Field#962's own doc warns about: `active.cancel(owed.cause)` inside `beginGeneration` fails it by name and line. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Three from the review: the shared reading is safe, withdrawn, and on a page (a) `recallAside.reached` replaced an atomic.Bool with a plain pointer written by the turn's goroutine and read by the sidecar's — a race whether or not anybody ever observed it. It is an `atomic.Pointer` now, and a nil load is simply a reading not handed over yet, which `reachedThePerson.did` already answers as "nothing has reached them" — the safe answer and the one that was true at that instant. Proved under `-race` over the recall, memory and person's-word fixtures. (b) `StreamReplaced` reset the four buffers and not the reading. What the dead machine drew is withdrawn on the event it sends, so the person has none of it in front of them — and a reading left standing would tell every door that may re-ask the request that they still do. (c) `let go of because you chose another model` is a string a person meets when they read a long step back, so models-and-cost.md has a section for it beside the other log-row questions: it is not a failure, here is why it is written down anyway, and it carries no door, so nothing reading the log to ask "did this turn end" counts their own act. A new heading rather than prose added to an existing one — the held-out score goes from `first 10/22` to `first 12/22` and holds top-4 at 18. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: a word said between two requests is not owed a cut The next request already carries the model the person named, so cutGeneration must answer false when nothing is running; otherwise the room says "switching now" for a request that is not starting. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…(review needed) (Agent-Field#992) * permissions: the frame names its way out wherever the pointer stands Agent-Field#946's frame and Agent-Field#985's grading landed within a day of each other and disagreed about one row. Agent-Field#946 was cut before the gate graded, so it drew `safe answer` on `deny all` only while the pointer was ON `deny all` — the same sentence then, because Agent-Field#933 opened every permission on the refusal. Agent-Field#985 made an ordinary call open on `allow all`, and the mark went missing from exactly the frames where the pointer stands on the act and the way out most needs naming. A panel of ONE never lost it: questionPanelOption marks any hands-only answer that loses nothing, whatever the pointer is doing. `deny all` is the answer that loses nothing by construction — the frame forms only where every member has one, and the row sends each question its own — so it now says so on every frame, which is one rule with the panel's rather than a second one. TestPermissionsFromOneStepAreOneFrame was the other half, and the red on dev: it read a costly set as opening on `deny all`, which was Agent-Field#933's rule and is no longer anyone's. It now asserts the pointer the grading puts there and, separately, that the refusal is named though the pointer is not on it. The manual's grouped-frame section, the gallery caption and the e2e needle's reason all still explained the deny-first pointer; each now says what is true and what expired with the grading. internal/e2e's live assertion is unchanged and was the corroboration: it waits for `safe answer` on four ordinary reads, so it would have gone red on the next live run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * permissions: one predicate decides the safe answer, on a panel and on a frame From the architecture review of Agent-Field#992. The first fix marked `deny all` unconditionally, which was a second spelling of a rule questionpanel.go already owned — and a wrong one: a frame whose member carries its asker's pick, or whose calls are plainly reversible, marked a row that its own tabs leave bare, so `2 one by one` contradicted the frame it was pressed from. questionMarksSafe is now the one predicate, questionSetMarksSafe folds it over a set exactly as questionGroupStart folds the pointer's rule, and the word is read only through questionSafeAside. TestTheSafeAnswerIsMarkedByOnePredicate fails any file that spells questionSafeWord for itself, so a third drawing of a question cannot invent a third rule about when a person is told where their way out is. The frame test pinned the mark with a frame-wide substring, which passed just as happily with the mark moved onto `allow all` — the one reading that tells a person their keystroke loses nothing when it grants four calls. It is a row assertion now, through questionRowSaying, and it checks `allow all` does NOT wear it. The `wary` case asserts the opposite of what it did, and says why. Nothing checked a FRAME's pointer against the gate's own grade — the live needle for that screen is the mark, which is now deliberately pointer-independent. TestTheFrameOpensWhereTheEngineGradedTheCalls does, with no model: the grave control is read from internal/session/testdata/consentask-rm-rf.json and must refuse to join a set, and the ordinary answers are session.AnswerOptions' own. The manual said `enter` on an untouched permission denies, in two places, which Agent-Field#953 made false. Both now split the MARK from the POINTER, and what `safe answer` means gets its own heading in the asker's words rather than a clause inside the grave case — it is drawn on every approval. The frame section lost the paragraph that split its answer list and gained a heading of its own, and the phone-width claim is scoped: under sixty columns there is no frame and no mark at all. The lifetime row's "THIS TEST FAILS THE DAY THE GRADING LANDS (Agent-Field#953)" is rewritten wherever it appears: the grading landed, nothing went red, and whether the row is owed is issue Agent-Field#995. DESIGN.md's pointer bullet carried the pre-grading rule and now carries the stakes rule. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ield#1001) The sentence told a person to run `aforge engine --stop` with no --workspace. That flag resolves to the HOME directory, never to the workspace being complained about, so copying the line exactly as written from inside a checkout stopped the healthy home engine and left the offending one running — and the line came back on the next launch, forever. Measured on the owner's laptop before the fix: a host on wire 14, started 2026-09-11 11:23 from a dirty build, still holding the aforge-v2 workspace twenty-two hours and eight rebuilds later. Every launch in that checkout read the refusal, and every remedy typed from it stopped the wrong host. `aforge engine --stop --workspace <the checkout>` retired it at once. The workspace comes from the host's OWN answer, remote.HostSelf.Workspace, rather than from what this process thinks it opened: the sentence is about the machine that will not let go, so the words a person types have to name what IT is holding. A host too old to fill the field keeps the bare command rather than being given an invented path. sessionHeldElsewhereSentence in chatv3.go already spells the flag for this exact reason, and its comment names this function as its voice. The voice was the one place not doing it. The version-mismatch branch is untouched. Refusing to splice a surface onto a host whose frames it cannot read is right, and the gentler busyEngineHostSentence road cannot honestly be offered across incompatible wires. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…nd two orphan packages (Agent-Field#991) * ignore macOS Finder litter The tracked Finder metadata was accidental repository noise. Remove it and teach the ignore file not to admit another copy. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * retire private planning dumps Move the lasting routing and harness research into the documentation tree, remove superseded root planning artifacts, and keep surviving references self-contained. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * prune superseded plan documents The deleted plans describe retired branches, surfaces, or research snapshots. Keep their live contracts in the current architecture and design records. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * keep only summarized design evidence Raw experiment cells and the generated home-design export duplicated retained reports and decisions. Remove the captures while preserving their conclusions. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * make retained paths portable Machine-specific paths leaked from benchmark defaults, captured reports, and source comments. Express the same locations through home-relative or neutral placeholders without changing harness behavior. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Remove orphan voice and gate packages The voice and gate packages had no importers anywhere in the tree. Remove them, their tests, and the structural-law entries their files had occupied; git grep proved both package import paths unused before deletion. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Remove unreachable Go functions Remove 68 functions reported unreachable from every main and test by deadcode -test ./..., together with the imports and private data they stranded. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * the captured frames and the benchmark defaults name nobody 169 of the retained terminal captures under docs/design/polish/frames carried a developer's home directory in visible text and inside OSC-8 hyperlink targets; the substitution is length-preserving, so every column and every escape payload is byte-identical. Four benchmark scripts defaulted to a private scratchpad that existed on one machine and no other — they default under $HOME now. A private host name, a provider's internal pod address and four person-specific comment examples go the same way. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * the transcription door no longer cites a package that is gone internal/voice held v1's microphone recorder and its own transcription client, and nothing imported it any more, so it went. Four comments and one design document still described it in the present tense — MULTIMODAL.md said its machinery "is real and waits on a surface wave", and transcribe.go cited internal/voice/transcriber.go as the live source of the wire shape it mirrors. The shape is unchanged and transcribe_test.go is now the only thing pinning it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * two documentation lines outlived what they pointed at JOURNEY.md's catalog used to be an index of scripts as well as a catalog of journeys; the harness that made it one drove the retired v1/v2 surfaces and went with them, so the page now says that internal/e2e covers selected v3 scenarios rather than one script per row. FIDELITY.md spoke of what "the .dc.html actually sets" after that export was removed; it is the record of what the design set. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * the change entry for the second public cleanup Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * the last personal paths and the last voice reference, now that their pull requests landed Thirteen pull requests merged into dev while this branch was being built, which freed six files the collision rule had put out of reach. internal/provider/ attribution.go still said internal/voice reaches the transcription endpoint on its own; internal/manual/chat/commands.md taught the slash rules with a real person's home in the example, and so did internal/tui3/detach.go and slashchip.go; docs/design/questions/DESIGN.md linked two ideation drafts that never existed in this tree; and two conversation-runtime records and one ab-routing ledger carried absolute paths from the machine that made them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * the change entry follows the files that came back into reach Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
… has closed (review needed) (Agent-Field#997) * tests: the reading beside a turn stops writing into a conversation that has closed `internal/session`'s load-dependent reds name a different test each full run (Agent-Field#959). One of them is now held still: five thousand runs of `TestAPickTakenByTheClockReadsAsProvisionalAndRunsWithNobodyParked` on the Spark under load failed thirteen times, every one of them as `TempDir RemoveAll cleanup: directory not empty` rather than on an assertion, and the file left behind in the directory each time was `told.json` — the delta stamp. The writer is `Agent.refreshElsewhere`, started from the turn loop as a bare `go` of its own. Nothing joins it and `Agent.Close` does not wait for it, so it stamps the conversation's folder after the session has closed — in a test, into a `t.TempDir()` that is being removed, which reds whichever test happens to own that directory. Two changes, one cause. The reading goes through `readBeside`, the one door for a reading beside the work (sidecar.go exists because four of these each had their own idea of cancellation; this was a fifth with none). And the stamp is written in the same locked step as the assignment, refused when the session has closed — the ask lane's own law about a clock that ran out after the door shut, said about a reading. That also makes the stamp true: it claims this session's model was told, and a stamp that advanced on a block no model ever read is a day of other windows' landings this conversation never mentions again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changelog: the reading beside a turn and the stamp it writes (Agent-Field#997) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * review: the stamp is owed behind the path, the reading obeys its context, and the law reads the tree Three blocking findings from the architecture review of Agent-Field#997. The stamp was written under `a.mu` — a stat, a marshal and a file write inside the lock a steer, a cut, a named interruption and every drain take before a request leaves. That is the shape Agent-Field#876 lifted out of the meta stamp, and the ≤50 ms law cannot see it because `paceAgent` never sets `Place.Dir`. It is owed under the lock and performed behind it now, through a `stampWriter` of its own that `Agent.SettleWrites` settles: the owe is registered while the session is still open, which puts it ahead of `closed` and inside the settle `Close` already performs. The closed check moves up to the reading's first acquisition, so a closed session does not walk the index at all. The `readBeside` ask discarded its context, which left the goroutine exactly the lifetime the deleted bare `go` had while three comments and the change entry claimed it was cancelled with the turn. The context is threaded and obeyed before the walk and again before the assignment, and `tellsElsewhere` is asked at the call site so a task node's turn enrols no no-op reading in the watch. The test pinned the early return rather than the shape. `Owe` starts its performer at once, so "the file is not there yet" is a race with that goroutine and cannot be a fixture: where the call SITS is the property, and taskdelta_law_test.go reads the tree for it, with both the shape it refuses and the shape it asks for planted. The runtime half now holds the reading on a channel through a real `Close` and settles before asserting the negative. Also: `NoteTold` only moves forward, because two readings written behind the path can land out of order; and the entry no longer claims the stamp is written where what it claims becomes true — delivery is at the drain's `landVolatileLocked` and `elsewhereTold` is never persisted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * tests: a fixture that owns an agent settles what its reading owed Moving the stamp behind the path moved the fixtures' obligation with it. Three hand-built agents in taskdelta_test.go call the reading directly and nothing ever closes them, so the write they owed was left to land whenever — which the proof run caught at once: 200 runs under `-race` failed as `TestAProjectWithNoOtherWindowGetsNoBlock … TempDir RemoveAll cleanup: directory not empty`, the same shape, one level down. They settle in their own cleanup now, which is the contract `Agent.Close` meets for a real session and which placemeta.go already states for every test that reads one of those files back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * review: the reading stays on the law, lands after its turn, and owes the later stamp Four findings from the confirm review. The ask was hoisted into a variable, which took `refreshElsewhere` out of the set the sidecar law watches — that set is read off the tree, and it reads only the function literal written into `readBeside`'s second argument. It is written out inline again, inside the condition rather than behind a nil. The assignment refused a reading whose turn had ended, which is not what the context is for: `elsewhereText` belongs to the conversation, not to the turn, and loop.go says in so many words that a read landing late rides the next step. Dropped, a disk slower than a short turn re-walks from the same unmoved `since` forever and delivers nothing. The context still stops the reading STARTING the walk; only `closed` stops the answer landing. The stamp's coalescing is max-wins on the instant rather than last-closure-wins. `Agent.Abandon` releases `a.mu` before it cancels, so an older reading can be owed after a newer one, and a [stampWriter] replaces its patch — the older closure would have been the survivor and would have written a stamp behind the block the model was handed. The instant is kept beside the writer under the lock and only moves forward; the patch writes what is kept. And the law accepted `NoteTold` inside ANY `Owe`, including the meta stamp's — which is off the path and also never happens, because the next meta patch replaces it. It requires the told stamp's own writer now, with that negative planted beside the other two. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * review: the closed check and the three writes it guards are one swap-shaped hold Agent-Field#999 lands `Agent.writeIfOpen`, the one door for "write nothing into a conversation that has closed", and this reading is one of its callers the moment it is on dev. So the region is shaped for that swap now: the lock, the check, the three lines it guards, the unlock, and nothing else between them — the prose moved above the hold and the comment names Agent-Field#999 as what replaces it. No behaviour changes: the check already sat immediately before the owe, with comments between. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rs turn bad (Agent-Field#1003) The lane row's default ran aforge's own chooser on every request, paying aforge's measurement budget to second-guess a router that balances well most of the time. Now auto sends the legacy preferences and lets the router route; a per-model gate counts refusals and unusable answers, and twice in a short while arms the chooser for a window. The belief ledger learns from every named lane's answers either way, so a takeover is never a cold guess. openrouter keeps its meaning as auto without the safety.
…fer (review needed) (Agent-Field#1012) * provider, cmd/aforge: the last loose locks hold their mutex from a defer The provider half of the lockdefer burn (Agent-Field#431): forty-seven sites across thirteen internal/provider files, plus the seven cmd/aforge stragglers, were the snapshot/test-and-set-then-release idiom with the Unlock on the success path. Each became a small method that holds the lock from a defer for its whole body and answers what the caller needs, with the slow or re-entrant tail left outside. No logic, ordering, or under-lock field access changed. That was the last entry on the known-red ledger, so the ledger burns to zero here: .github/known-red.txt and its ratchet test are deleted together, as the ruling in docs/rules/ci.md prescribes. The shared repositoryRoot helper moves to internal/ci/root.go so the remaining ci tests keep their door. TestEveryLockInTheGuardedTreeUnlocksFromADefer now passes on a clean tree, and the full internal/provider, cmd/aforge, internal/guard and internal/ci suites are green. Co-Authored-By: Claude <noreply@anthropic.com> * changelog: the lockdefer burn entry for Agent-Field#1012 * docs, ci: the words stop describing the known-red ratchet that is gone The burn deleted .github/known-red.txt and its internal/ci ratchet, but docs/rules/ci.md, the Makefile header, the ci.yml laws comment and a clause in internal/remote/ratchet_test.go still narrated the ratchet as live machinery — a constant that no longer compiles. Each now says the ledger burned to zero in Agent-Field#1012, that an absent ledger skips nothing, and that the one reading stays so a ledger cannot quietly return. Comment and prose only; no behavior. Co-Authored-By: Claude <noreply@anthropic.com> * provider: the routefirst takeover drain holds its mutex from a defer e61f57a (Agent-Field#1003) landed on dev after this branch was cut, with one snapshot-then-release site in routefirst.go's tellTakeover. It became takeParkedTakeovers, the same drain-in-one-locked-step shape as its siblings, so the Emits run outside the lock and the rebased tree keeps the guard scan at zero. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…, billed arms, cache pin, shaped gate, stale-build sweep (Agent-Field#1015) * checkpoint: the race's tightening never stands the first mark below half the price A raced both-yes pulled the first [taking stock] down to the very boundary the verdict landed on, and a measured planning turn was told at round three over one issue and two listings — noise the model waved past, which is what the round-twenty note then inherited. The first rung now never stands below checkpointFirstRungFloor, derived as checkpointPrice / checkpointRatio: triage may make the first look sooner, it may not make it empty. An unraced turn's ladder is byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * journal: billed arms leave their own call lines, and a turn that hopped seals one usage line per model The measured planning chat's journal summed to $0.789 of a $1.412 bill: hedge arms and cut retries were banked to the meter through reconciled() but wrote no call line, so exactly the expensive requests left no evidence. A billed receipt now writes one, marked arm: hedge or arm: reconciled — evidence like every call line, moving no total. And the turn's usage seal named the model latched at the seal, so the mid-session hop attributed all 31 requests (2.4M input) to the second model though the first served thirteen. addUsage now keeps the turn's share per answering model — the same name the bank row carries — and appendUsage seals one line per model when there were several, the turn's one wall time riding the first by name so a replay never reads it twice. Co-Authored-By: Kimi K3 <noreply@moonshot.ai> * changelog: 1007 title under the one-line bound Co-Authored-By: Kimi K3 <noreply@moonshot.ai> * turn fold: slices of a repeatedly read file point at the file, and the newest stays whole The measured planning chat read checkpoint.go in ten overlapping slices and carried all ten, verbatim, through twenty requests: the fold bounded generic tool-result accumulation but had no notion that slices of one file are re-readable where they came from. When the foldable region now holds several reads of one path, each older slice becomes a pointer in the stub family the prompt already teaches — the read recipe, offset and limit, that brings the slice back — no copy is filed, and the newest slice is kept whole. Selection counts a kept slice as buying nothing, so a pass still runs only when it can buy the whole headroom. The trigger, target, batch-completeness and frozen-horizon laws are untouched; bash and every other tool's results keep the filed pointer they always got. Freshness of a kept slice is the held-read seam's question, not this pass's: a pointer says the range was read and how to read it back, never that the file still says it. Co-Authored-By: Kimi K3 <noreply@moonshot.ai> * session: a read the conversation already holds answers with a pointer Held-range ledger (heldreads.go): a `read` fully covered by bytes the live transcript still carries, against an unchanged file stamp, is answered with a one-line pointer instead of a fresh fetch; a changed stamp retires the whole entry, a partial overlap fetches whole, and a stubbed or folded result drops out of coverage by itself. The read tool's description prices the round trip it costs, the system prompt teaches the pointer sentence beside the stub pointer, and the chat manual quotes the behavior. Co-Authored-By: Claude <noreply> * lanes: the cache pin joins the lane chooser's enforced set rather than being dropped by it * provider: the OpenRouter-takeover gate counts a refusal only when the router's own pick was refused A narrowed demand's refusal is evidence about our choice, not the router's default: for the gate to count it arming the takeover from within the takeover's own demands. shape reaches the door from the one classifier that holds the knobs (refusalobject.go's Client.refusalObject), and the refusal door asks it (routefirst.go's Client.noteRouterRefusal, velocity.go's two refuseLane branches). The answer sides stay shape-agnostic: an answer that arrived is a verdict about the machine that spoke it, whichever spine chose it. Measured in a live chat (2026-09-12): takeover armed, every narrowed demand 404'd, each 404 re-armed the gate — four 'Retry 1/2: relaxed the endpoint filter' lines at ~80k tokens a re-send before the first rung went bare. * tui3, session: a launch sweep names every live session on an older build rev The third binary-shadow incident in the repo's history ends with a visible warning instead of 'same old rev' on every screen. The sweep reads presence files (fail-open), freshness from presenceWindow (age, never pid — the file's own law), and the launch gate emits one advisory line through the same noteFacts door the landing keys use. Manual section added to starting-aforge.md. * checkpoint: a probe pins the first-rung floor against race-at-any-round * changelog: entries renumbered to the pull request they ship with * fmt: sweep and law-visit edits through gofmt * tests: pin the hop's split seal instead of the old one-line shape TestEveryResponseWritesItsOwnLineWithItsOwnShape names two distinct answering models in its fixture (the first response falls back to the latch, the second names vendor/served-model), so the per-model seal split correctly writes two usage lines there. The expectation now pins the split — one line per answering model, figures per model, the wall time on the first by name — exactly the hop case usagejournal_test.go covers. Co-Authored-By: Kimi K3 <noreply@moonshot.ai> * provider: the gate's shape test is a demand, not the ladder's membership The first cut classified shape through wirePreferences(...).membershipNarrowing() — the ladder's first-rung question, which counts require_parameters as membership. Every machine-unmodified ask read as narrowed, so an ordinary paced refusal (one of the router's own picks queueing) stopped arming the takeover: gate_e2e_test's TestTwoPacedAnswersHandTheRoadToTheChooser went red. Shape is now read from the knobs as a DEMAND — hedgeLane, or a lane choice carrying admitted names — with require_parameters and the ledger's own Ignore vetoes left outside the gate's question. * session: restore the offset/limit pin sentence and route held-reads through the one decode door lawregistry_test.go pins 'page the rest with offset/limit' in the read description; heldreads.go now decodes with decodeToolArguments like every other tool; the round-trip sentence is trimmed to keep the lean prefix under its budget. Co-Authored-By: Claude <noreply> * exec/bare: the edit merge sentence owns its whole rule, reclaiming the round-trip-priced read sentence's room The lean prefix was 62 bytes over on CI. The 'large unchanged regions' clause restates the merge sentence, so it goes; the held-range round trip sentence stays whole. Co-Authored-By: Claude <noreply> * changelog: 1015-stale-build-sweep surface fixed to the enum it checks --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Kimi K3 <noreply@moonshot.ai>
…-Field#1004) * e2e: a needle names a key, it never spells one TestQuestionsE2E has been 14 of 18 red since Agent-Field#933 took the brackets off every key on this surface. The suite went on waiting three minutes at a time for `[1] delete it` while the line drew `1 delete it`, and the untagged gate that exists so this cannot happen (Agent-Field#184) was green throughout, because it was looking at the half of each needle that had not moved: - nine needles in questions_e2e_test.go were inline literals, which the table's gate cannot see at all; and - eleven rows of the table spelled `[c] change` in `screen` while their `source` said only `change`, so the gate checked the word and never the key in front of it. So a row that is offered on a key now NAMES the key, and one function puts the two together: - tuiWord gains `key`, and [say] returns [tuiWord.spelling] — the word alone on a plain row, `keyedWord(key, word)` on a keyed one. - [keyedWord] is the one place this suite writes the gap between a key and its word. The nine pasted answers in the questions scenarios go through it, so `delete it` stays the scenario's word and the `1 ` in front of it stays the product's grammar. - nineteen rows are respelled onto it: the question grammar's own keys, the consent block's two, and the four landing answers, whose one-space column internal/tui3's own relanding and papercuts tests pin (`a resolve it n drop it s tell it`). And [TestNoNeedleSpellsAKeyTheSurfaceStoppedSpelling] is the law that keeps it: a go/ast walk of every screen-reading call in this package refusing a needle-position literal that brackets a key or pastes a numbered answer onto its word. It reads the table as data and the suite as source, and it leaves every other literal alone — a sentence the MODEL wrote is a coincidence, not a source of truth, which is what the suite's own header has always said. internal/manual/chat/questions.md said a key is drawn `[1] allow once`. It is drawn `1 allow once`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the e2e question needles entry (Agent-Field#1004) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * e2e: the chip is a tail, and a letter is the question's only once you aim The first paid run after the respelling went from 4 of 18 to 7, and the two families left in it are the same rot one layer down. THE CHIP LEADS WITH THE QUESTION'S OWN HEAD. `questionChipTail` waited for `question · alt+a`; the status line draws `? delete the build directory? · alt+a` (question.go's questionSegment) and spells the word `question` only where there is no head, or `3 questions` where there are several. Its `source` was `alt+a`, so the untagged gate was green on it exactly as it was on the brackets. The row is its own name now: the tail, ` · alt+a`. A LETTER IS THE QUESTION'S ONLY ONCE YOU HAVE AIMED AT IT. `o`, `c`, `x`, `?` are each the first letter of a word people type into the box, so the block does not take one from somebody who has not yet looked at the question (questionkeys.go's questionAimKey; the manual says it in a person's own words). Six scenarios pressed `o` to open a page, the `o` went into the message box, and each waited out its three minutes for a page nobody had opened — with `› o` on the screen it printed. So [aim] is the gesture, spelled once: `↓` then `↑`, because an aim may not be an answer — `enter` takes the pick and `esc` puts the question away — and the walk is therefore walked straight back, leaving the pointer where it was and the hand on the block. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * e2e: the page opens on the pointer, so the foot says what enter would send The room scenario waited for `nothing chosen yet` on a page that had just opened on `1 postgres`. Since Agent-Field#789 every answer has a pointer the arrows walk and enter takes, and the page opens where the block's pointer stood — questionroom.go's own enter path says so — so a page with answers on it always has one to send. `nothing chosen yet` belongs to the `something else…` row, which stands after the last option and carries no key. So the moment is read the way it now happens: the foot says `answering ` what the page opened on, and it may not also claim nothing is chosen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the whole of what moved, and the three defects under it (Agent-Field#1004) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…oes, and the prefix gate weighs the real belt (review needed) (Agent-Field#996) * roles: the compaction role is deleted, because no compaction has called a model since the summariser went RoleCompaction was a priced, described, settings-visible dial wired to nothing. [Agent.compact] takes `_ context.Context` and makes no model call at all — a pass is two mechanical rearrangements of text the session already has — so the row on the Providers tab offered a person a model for a call that never happens, and TierHigh's patience was derived from a summary nobody writes. The role, its tier assignment, its description and the settings and manual text that offered it all go. The high tier keeps every tenant it actually has — the auditor, the shaper, vision, the repair, the careful part of a division — each registered from the package that makes the call. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * session: every request says what it is for, and the door is the only thing that spells it NINE OF THE ELEVEN CALLERS OF THIS PACKAGE'S MODEL DOOR REACHED THE WIRE ANONYMOUSLY. The guardian, vision, the shaper, the spell-out, the subharness intake, the run planner, the harness designer, the ceiling's handoff draft and a saved program's own AI step all called completeWithModel with no provider.WithCallTag anywhere above them, so the model-call log could not say what any of them was: 2,309 of the 2,839 untagged finishes in the ten days to 2026-09-10 are this package's, and with them the answer to "what was this build spending that model on all night". The tag was a context value a caller could set or forget, and forgetting it is silent. It is an argument now — clientdoor.go's `callPurpose` — so a call with no purpose does not compile, and the door is the one thing in the package that calls provider.WithCallTag. The three callers that did stamp their own (the turn, the ask tool, the errand ladder) pass a purpose instead, which is one spelling of one fact where there were four. AND auxiliary.go's OWN CLAIM WAS THE FALSE ONE. It said callRole was "the one door all auxiliary provider calls pass through" while ten calls went round it. It is the one door every ERRAND passes through, which is a narrower and true claim, and the sentence says so and names what is legitimately not an errand — vision streams into the room in the person's own turn, the handoff draft is billed to the turn on the turn's own model, a program's step runs on no role's model at all. nohiddenwork_test.go is the law, on the laws gate: a blank purpose fails the build, a WithCallTag outside the door fails the build, and the walk fails if it ever stops finding the door. No behaviour changes. Every call goes to the same model with the same options; what is new is that its row in the log has a name on it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * tests: the prefix gate weighs the belt a configured machine actually carries THE GATE WAS POINTED AT A SHAPE NOBODY RUNS. fixedPrefixBudget's own doc comment has always said it bounds "the belt the shipping conversation door assembles". The fixture under it was v3ShapedAgent: a conversation with no memory store, no accounts hub, no standing items and no saved programs — eighteen tools, 39,073 bytes, eight kilobytes of headroom, green every day. A machine somebody has finished setting up carries twenty-three tools and weighs 53,025 bytes, which is 5,025 OVER the 48,000 cap the gate was enforcing. It has been over for as long as the shape existed and the gate could not see it, which is Agent-Field#576's shape exactly. The gate now weighs beltShapes[0] — "the shipping conversation, fully wired", the same definition prompt_belt_test.go uses, through one new helper so the two cannot drift apart again. AND THE FIGURE BECOMES A RATCHET. "The measurement plus a tenth" was right when the number came out of a diet that had just been paid for. This measurement is not the end of a diet; it is the first honest weighing of a prefix that had never been weighed, already past what the last diet aimed at, so a tenth on top would be five more kilobytes nobody chose. It is the measurement and nothing else, and anything that grows the shipped prefix now fails the build. WHAT IS OWED IS FILED, NOT FIXED. 48,000 stays as the stated target and the test prints the 5,025 shortfall on every green run. The bill is one tool: `stand` is 9,607 bytes, more than a quarter of the whole tool block and nearly twice the next heaviest. Trimming a schema is a change to what the model is told, not to a byte count, so it belongs to whoever owns the standing belt rather than here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the auxiliary inventory entry (Agent-Field#996) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * replay: the tag law reads the door, because the door is where a tag is stated now TestEveryTagTheBuildWritesResolvesToARoleSomebodyDeclared walks the tree for provider.WithCallTag. internal/session has exactly one of those now — the relay line inside the door — so the law was reading a variable it could not resolve and finding fourteen tags for a table of thirty-seven. It reads the door's own call sites instead, which is the same thing the build does: the purpose argument is what reaches calllog.Record.Tag. The `callPurpose(...)` conversion comes off before the argument is read, a role worn as a purpose resolves to internal/roles' vocabulary (over-approximated, because this law is safe answering with more tags than one site writes and holed answering with fewer), and the door's own constants are read from their declaration the way roleWords already reads internal/roles. AND IT IMMEDIATELY FOUND THE TWO CALLS THAT HAD JUST BEEN GIVEN NAMES. The ceiling's handoff draft and a saved program's AI step now write tags, and nothing priced them: both are lane.RoleAuxiliary and both have a row. The draft rung is the dearest side-call on the ceiling road and it has been invisible to every reading of calls.jsonl until now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * manual: the roles table stops listing a role the binary no longer registers The models-and-cost page's roles table is described on the page itself as 'built from what is registered in the running binary, so it is the truth about this build'. It listed `compaction`, which nothing registers any more, and the crew's careful line and its account of what aforge calls on your behalf both named the summary a compaction keeps — a call that has not existed since the summariser was deleted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix gate: the budget is the widest machine's, not the one it was written on The first spelling of the ratchet was 53,100 — the laptop that weighed it said 53,025 — and it failed on the runner that proved it, at 53,132. The prefix is not the same size everywhere: `grep` says a longer sentence about itself where ripgrep is absent, which is 134 bytes on every request of every turn. So the gate weighs what the WIDEST machine pays. bare.WidestGrepDescription is the one place that knows which of the two sentences that is, and widestBelt swaps it in wherever the gate runs, with a law that fails if the tool it names ever leaves the belt — otherwise the budget would quietly get easier. The residual is the shelf: load_capability lists the groups THIS BUILD has, 27 bytes more on a machine that can edit video. That is filed in the file's head rather than fixed here, because naming what a build COULD have is a change to what the model is told. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the prefix figure is the widest machine's Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * roles: a role that stops existing is dropped from the profiles that pin it Deleting RoleCompaction left the word in every config.json that had pinned it, and the panel re-serialises the whole `models.roles` string on any change — so the next time that person moved ANY OTHER pin the write came back `"compaction" is not a role`, and every role pin on the machine was unchangeable until somebody hand-edited config.json. The deletion had no reading for what it deleted. roles.Retired is that reading: a one-way list of the words this build used to answer to, with the line that says what happened to each. It is the only memory the build has of them, and without it a dead word is indistinguishable from a typo. ParseModelRoles drops those keys and says so once per process; writeModelRoles takes them out of the TEXT, which is what is actually stored, so a person who changes one pin stops re-saving a sentence about nothing. The test is the exact string a pre-deletion profile holds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prose: nothing says a compaction asks a model any more A compaction is two mechanical passes over the transcript; it has never asked a model. Six comments and two manual lines still offered it as the example of a billed auxiliary errand — the pocket the title comes out of, the thing the careful tier is for, a non-streamed call like a harness node — which is a sentence about a call that does not exist, and was the figure the careful tier's own patience was derived from until this PR re-derived it. The settings hint for `careful work` no longer promises it either: what that tier actually buys is the check on finished task work, the brief a task is shaped into, and reading an image. The transcript NOTE a compaction writes is still called a summary in agent.go, because that one is real. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * roles: a role's word lives in internal/roles, and a law says so `const spellOutRole roles.Role = "spellout"` lived in internal/session. It registered, resolved and tagged its call correctly — and reached the cost report as a word nobody had written down, because roleWords parses internal/roles and nothing else. roleOf prices an unrecognised tag as a background errand with nobody waiting, so the ONE auxiliary a person sits and watches was the one counted as if it did not matter. Nothing failed; a number was quietly wrong. The word moves to roles.RoleSpellOut beside its siblings, the Register call stays at the call site, and TestEveryRoleWordIsDeclaredWhereTheVocabularyIs fails the next one. And the replay walker stops enumerating receiver spellings. callName flattened one selector level, so three of the six rows in that switch — `p.agent.completeWithModel` and friends — rendered as "" and could never match: the ladder looked complete and was half dead. methodName asks the only question the law has, which is the method's own name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix gate: both arms weigh the shipped shape, at the widest machine THE LEAN ARM HAD THE SAME HOLE THE FULL ARM WAS REPAIRED FOR. leanShapedAgent built its own thin config — no memory store, no accounts hub, no standing items, no saved programs — so the arm that bounds the prefix for the person with the LEAST room weighed a belt without `stand` (9.6 KB on its own), `remember` or `search_conversations`, none of which leanCapabilityGroups shelves. It is the shipped shape on a small window now, which is what its own comment always claimed. And three ways the number could go back to depending on who ran it: beltShapes[0] read the fullest shape only until somebody put a row in front of it. beltShapeNamed asks for it by name. WidestGrepDescription returned the fallback sentence because that one is longer today; it now measures both and returns the longer, and widestBelt ASSIGNS rather than comparing — a swap that only fires when it makes the number bigger is a swap that stops firing silently. load_capability names the groups this BUILD has, and `edit_video` exists only where ffmpeg is on PATH — 27 bytes of prefix that depend on a program nobody installed on purpose. loadCapabilityDescription takes the members as a question now, so the gate can ask for the widest answer instead of this machine's. Both budget figures are re-measured in the next commit, on the Spark. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix: both caps are the measurement, and the three own-client roads say what they are THE CAPS. Full 53,141 and lean 44,989, both weighed on the Spark against the shipped shape at the widest machine, both with no headroom, both printing the shortfall against the target they owe on every green run. PERF.md moves in this commit, which is the rule for a cap. THE ROADS. memory_consolidate.go, standing_run.go and tools_doc.go each build a provider client the one door does not make — a longer timeout, static routing, a document config — and complete on it directly. That is a real difference, so the answer is not to force them through the door; it is to make them say the word the door says. clientdoor.go's withPurpose is that, and it is still the only file in internal/session that spells provider.WithCallTag. The two errands this build runs most often with nobody there reached the call log with NO TAG AT ALL, which made them indistinguishable from a turn that had lost its name. The standing check is `standing-check` and not `sentinel`, because cmd/aforge already writes that word for the resident's quorum errand and two calls under one tag is a reading of neither. The law now pairs the halves: a file that builds its own client owes a withPurpose, and it fails if it finds fewer than three such files — a structural law that matched nothing would pass for ever. And `compaction` comes out of the replay role table: no build can write it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the four findings the review turned up Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * law: the purpose is required on every own-client call, not once per file A file-level pairing is satisfied by one road naming itself while the road beside it stays anonymous, which is the exact shape of the failure this law exists for: the forgettable one is always the second one. Every completion in a file that builds its own provider client must now carry a withPurpose on the context it is handed — inline, or through a local the purpose was folded into. standing_run.go writes the purpose four wrappers deep and completes on `callCtx` several lines later, so the reader follows assignments to a fixed point rather than looking only at the argument. And the second pass counts the CALLS it judged, not the files: three files that build a client and nought completions in them would pass in silence. cmd/aforge-replay's two doc comments stop citing auxiliary.go's deleted WithCallTag line and point at clientdoor.go's callPurpose, which is where the tag is spelled now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * roles: the new law found two more of its own kind, and they are fixed TestEveryRoleWordIsDeclaredWhereTheVocabularyIs caught `const standingSentinelRole roles.Role = "sentinel"` in internal/session the first time it ran, which is the second instance of exactly the defect it was written for and the reason it is a law rather than a note. The word moves to roles.RoleSentinel; the Register call stays at the call site. And with `spellout` finally visible to roleWords, the tag law asked cmd/aforge-replay to say what it prices as — so the table gains the row, which is spellout.go's own lane.RoleAuxiliary and not a second reading of it. That row carries the seam it exposes: a person SITS AND WATCHES a spell-out, and an auxiliary is by definition a call nobody's seconds are being spent on. Either the lane role or the product is wrong there. The table's job is to agree with the build, so it does, and says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * roles: a dead pin is a dead pin, and three more numbers stop depending on the machine THE RETIRED LEDGER IS DELETED. It was a map of the words this build used to answer to, so a dropped pin could be told apart from a typo — and it could not earn its keep. Both are a pin no call will ever consult, both should stop being written back, and the only reader who can act on either is the person adding a word right now. Keeping it meant every future deletion owed it an entry, and the day somebody forgot, the old failure would come back exactly as it was. So the reading is symmetric: a pin for any word that is not a role is dropped, the writer refuses only a name being ADDED, and nothing dead is ever written back. The row DRAWS what is acted on (config.LivePinsAt) rather than the raw stored text — it used to draw `compaction: some/model` as a live pin while the list under it had no such line — and the panel says "no longer a role — that pin is ignored" to the person about to lose it. It is a sentence and not the log.Printf this had, which was the only one in internal/config and landed on stderr in every headless and --json door. AND THREE MORE MACHINE-DEPENDENT NUMBERS. The lean page interpolates the working directory, so that arm measured 45,034 on macOS against 44,989 on Linux and failed — a fixture artefact worth tens of bytes in the gate whose entire purpose is to be one number for everyone. The lean arm was also being handed the FULL shape's load_capability sentence, making its figure a hybrid of two belts that neither pays. And the replay table priced `vision` as an errand nobody waits on while image.go, its only writer, sets lane.RoleTalk with the reasoning beside it: a look at an image streams into the room during the person's own turn. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix: one weighing, one shipped shape, and a debt that is enforced THE DEBT WAS INVISIBLE. It was a t.Logf, and nothing in the Makefile passes -v — so the one line saying the shipped prefix is thousands of bytes over what it is supposed to be was printed where no human and no CI log would show it. The cap is the TARGET plus a dated waiver now, one per arm in one place, and a waiver only ever shrinks: known-red's discipline applied to bytes. Growing the prefix takes a diff with somebody's name on it. ONE WEIGHING. The two arms were forty lines each, written twice, and the copies had already drifted — only one printed its shortfall, and it was the arm with the smaller debt. reportPrefix is called twice. ONE SHIPPED SHAPE. v3ShapedAgent WAS the second opinion: its own thin config, eighteen tools, weighed by four gates including both budgets. It is shippedShapeAgent now. beltShapes' lean row built a third config again, so the belt law and the prefix gate were measuring different lean conversations under one name; both call buildShippedConversation. ONE VOCABULARY READER. purposeWords and roleWords were the same function with a different path; they are constWordsOfType, read once, with the empty-result panic inside it. The role law catches the CONVERSION spelling too — `roleRepair = roles.Role("repair")` was invisible to it — and now also reads every roles.Register argument, which is the spelling that cannot be worked around. roles.RoleRepair is declared with the others. And the manual stops teaching a summarizer rung, its `session: summarizer returned nothing` string, and a focus appended to its instructions. None of that exists: a pass stubs and folds, asks no model, and never folds your own words. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix: the lean page is weighed the same on every machine, to the byte The working directory was a fixture artefact worth tens of bytes; the Workstation line is runtime.GOOS/GOARCH and worth one, which a ratchet with no headroom fails on just as hard. Both are normalised at the one place that needs them to be, and the product still tells the model the truth about the machine it is on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix: the lean waiver shrinks on its first run, and `repair` gets a price The lean figure went 44,989 → 44,920 because the page's working directory stopped being a fixture artefact and the lean arm got its OWN shelf sentence instead of the full belt's. That is sixty-nine bytes off a number that had been measured on a hybrid, and the waiver comes down with it — which is the whole behaviour the ledger exists to have. And `repair` reaches the replay table. It only became visible there when the role stopped being conjured at its call site as roles.Role("repair"): a word spelled that way is invisible to every reader of the vocabulary, which was the defect, and the law that now catches it found this the moment it could see it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changes: the review's findings, all of them Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * prefix: the lean waiver shrinks again, to the byte the page now measures Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * roles: the registry is the tier table, and the vocabulary is a different question A REGRESSION I INTRODUCED, CAUGHT BY THE SUITE. Making the read drop any word the REGISTRY does not know threw away `imagegen:paint/model` — a real pin doing real work. A role gets into the registry by registering, which is how it gets a tier, and a role with no tier never does: a painter is chosen by a pin or not at all, since a chat model in tiers.high is not a statement about painting. So the registry was never the answer to "what are the roles". roles.Vocabulary is that answer and roles.Known is the reader's door to it. The list is hand-written, which is a thing that falls behind, so a law parses the file it lives in and fails when a declared role is missing from it or a listed one is not declared. The refusal lists the vocabulary too, so a person is shown `imagegen` as a name they may pin. And the retired-pin test seeds the row the way a profile written before the deletion holds it — straight into the file, because the writer is exactly what would refuse it today and that person never typed it today either. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * session: the two holding actions name the issue that deletes them The `standing-check` rename and [widestBelt] are both measurements around a problem rather than fixes for it, and both are deferred to a cross-package wave rather than grown here. Each now says so where a reader meets it, and names issue Agent-Field#1010 (spine: Agent-Field#928) as the place it is deleted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * config: whether a pin was already there is a question about the person's file writeModelRoles forgives a retired word it FINDS and refuses one being TYPED, and it asked parseModelRoles which of the two it was looking at. That reader drops every retired word by design, so the stored row it handed back could never contain the one word the check existed to find: a name that had sat in the file since before the deletion read as a name typed for the first time, and a machine with an old `compaction:` pin could not save a change to any other pin. The set is read off the stored TEXT now — storedRoleWords — because every reader above that line drops what it does not recognise, and the dropped word is exactly the word this question is about. The asymmetry gets its own test: the same word, forgiven when found and refused when typed. The old test only ever typed a word that was never a role, so the half that broke was the half nothing watched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * session: a held-reads pointer sentence pays 150 bytes on both prefix arms (Agent-Field#1015) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…gent-Field#1018) * tui3: the draft kill ring — whole-box clears keep the words, and the ↑ walk visits them dim in front of the sent history * tui3: /drafts, the page over the kill ring (enter restores, d lets one go) * changelog: the draft-page entry uses the PR's own number * tui3: /drafts takes its place under /compact and has a fate on home
…to OpenRouter unpinned, exactly the named provider pinned — is the row this build ships (Agent-Field#1019) `simple` is the default routing row: no pin sends no provider object and OpenRouter's own routing answers; a pin sends exactly {only:[X], allow_fallbacks:false}. The routing row reaches every client this process builds; a pin is refused by the wire, not by a saved memory, and the person is told in the conversation; the pin rides the calls a person is reading and every call of a command they typed; the call log names what each attempt carried; the picker predicts no machine where nothing chooses; a stall under simple without a pin is reported, never rescued. latency, price and off remain opt-in. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
… still queued (Agent-Field#1024) The hand-over press wakes a turn that drains the steering queue and, if it finishes, hands unsettled nodes back; two tests read the queue between those two events and saw it shrink. They now count what the model was told, queued plus drained, and hold the turn open so the press under test lands while the model is still deciding. No production change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
…tall (Agent-Field#1021) * docs: a README that sells the chat flow and tells the truth about install The README was an install page carrying four curl lines that 404 for anyone who is not signed in: the repository is private, `scripts/install.sh` is not on `main`, and the `agentfield.ai/get/aforge` proxy is an unmerged pull request on the website. It said nothing about the product. This one leads with what aforge is — a terminal session you talk to, that reads and edits files, runs commands, hands work to tasks you can walk away from, remembers, and takes slash commands — and shows a real captured screen of that loop on the default model. The install section puts the road that works today first (clone, `make build`, `bin/aforge`), then names both curl roads and says in one sentence each which is live and which is not. Long tails — installer flags, the slash-command table, the key table, the tool names — are folded. `internal/manual/chat/running-from-the-terminal.md` carried the same four dead curl commands, so the manual law makes it the same change. Its first section now says the same true thing; every `## ` heading is untouched, so the probe table still reaches it. Numbers appear only where a cited constant backs them, and the two places shipped text disagrees with itself (`--parallel` 8 versus 32, `--budget` 150,000 versus `--token-budget` 220,000) are left out rather than picked. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: README fixes from the refutation pass An independent lane re-ran every recipe in the claims ledger and drove the real binary in tmux. Three sentences did not survive, and one whole road was missing. The permission card was fiction. The ledger "checked" it with a grep that matched a comment at internal/tui3/consent.go:20 — whose own next paragraph says the block draws it now. What the surface actually draws is a bordered block whose header counts ten seconds (config.DefaultConsentTimeout), whose second choice is the bare word `always`, and which carries `c change`, `? ask back` and `safe answer`. Replaced with a verbatim capture at 100 columns, and `c` and `?` are now described in the words question.go uses. `aforge models` was listed as needing no key. It exits 1 with `aforge needs a model to work with.`; the repo's own manual page already said so at running-from-the-terminal.md:583. It now has its own sentence. The first-run quote was the branch nobody sees. firstrun.go:808 picks `setupConnectWord` wherever browser connect is available, so a fresh reader never meets `setupKeyWord`. Both roads are now named, folded, with the condition that chooses between them. And the gap: "run `aforge` inside a project" never said what that means. A new section gives the launch order from cmd/aforge/chatv3_layout.go:84 — `--workspace`, else the git root, else the directory, except in your home directory or under /tmp where aforge keeps a folder of its own and says so — names `/workspace` as the door, and says that on a machine with conversations on it bare `aforge` opens home rather than a chat. All of it was reproduced in tmux first. Smaller: `/spend`'s registered meaning carries its ` · alt+3` again, the nav row gains the Tools anchor, `ctrl+g` and the right-hand column are described as the code has them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: the change entry for the README rewrite (Agent-Field#1021) Five invalidations, because five things a session might remember about this repository stopped being true: the four dead curl lines as the install road, the same four in the manual page, the one-line permission card, `aforge models` as a keyless command, and `setupKeyWord` as the first-run copy. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: the account tools are named as conditional The tool-name table listed the five Gmail and calendar tools and the four Slack ones with no condition, which reads as "Gmail is on the belt". It is not: familyTools (internal/session/tools_connect.go:438) hands out the Google five only for a connected Google account and the Slack four only for Slack, and connectcaps.go:57 holds the same two sets as the inverse. The conditions paragraph under the table now says so and names the door a person uses, `/connect` (internal/tui3/commands.go:78). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…ire will ask for, a routing change lands now, the debug pin records bodies, enter unpins (Agent-Field#1025) The status chip, the settings lane row and the picker read the pin the transport will act on (provider.PinNow) instead of the profile row, so a retired pairing draws auto with its reason and never @x over a bare request. A routing change in the settings sheet re-installs the row and reaches the very next request because the profile door hands no static routing down. AFORGE_DEBUG=1 takes the in-process road like --debug and writes request bodies. In the lane fold, enter on the machine in force unpins it and typing filters that model's machines. Closes Agent-Field#1022. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
…hat drew it, and the opened step shows the prompt (Agent-Field#1026) The generate_image row draws the file it is about in primary ink and the image model that actually drew as a dim qualifier, read from the tail of the tool's own result line (", generated on <model>") so the row and the request cannot disagree; an unknown model adds nothing. Opening the step leads with the prompt, one dim line per other input, then "drawn with X" or "asked for best · drawn with X", then the picture. view_image rows gain their file the same way. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
…ands every engine down (Agent-Field#1000) Home's foot box is a block of one height — three rows, padded below the draft so the caret stays put — and the floor is spent only from frames that have the rows to spare, through one door the chat's foot and every place's frame ask. `aforge engine --stop-all` names each workspace it stands down. Gate re-run on Spark against dev 0738312 merge: laws, pr-ready (tui3 312 s, cmd/aforge, enginehost) all ok; driven captures at 120x40 and 80x24 match dev. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
…e behind a model is provider (Agent-Field#1027) Owner ruling 2026-09-14 (Agent-Field#1023 item 1): everywhere a person reads, the thing behind a model that answers a request is a provider — the settings row, the /model hints (→ providers), the fold sentences, the rescue and stall notices, the config hints, and the manual page titled Providers. Code identifiers, config keys (lane.talk), the @morph chip and the /status --json `lane` key (a script contract) keep their spelling. A law test fails any tui3 string literal that says lane. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv
…nt-Field#1033) * PERF.md: the prefix budget table says the caps the gate enforces The waivers were raised by 150 on each arm in the commit that made them, with the reason in the code comment, and this table was never opened — which is the one thing the performance law forbids: a cap that changes changes the doc in the same commit. The table now reads 53,291 and 45,066, over the targets by 5,291 and 13,566. Closes Agent-Field#1030. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv * docs: change entry for Agent-Field#1033 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…when you come back to the tab (Agent-Field#1036) * session: a card for a decision you already made is not asked again when you come back to the tab A turn's backlog is every event that turn has sent, kept so a surface arriving mid-turn reads the work from its first line. A CARD in it is the one event that is not a report of something that happened but a question about something that has not — and the replay handed it over verbatim, whatever had since been decided. So a person who approved a task, looked at another tab and came back was asked to approve it again, on every return, for as long as that turn ran; and because a question takes the keyboard where it is drawn, the conversation underneath it could not be scrolled while it stood. Both symptoms, one cause. The replay now consults the answer. [eventHub.attach] is handed what is still being asked — the banked words, read off a.mu at the moment of the attach, which is where a question goes on the book when it is raised and comes off it the moment it is answered or withdrawn — and leaves out a card whose question is no longer one. The backlog stays a faithful log of the turn; what is filtered is the REPLAY. [questionAsked] names the question a card put in front of somebody, in the lanes' own keys, for consent, a task proposal, a standing card, a harness offer and a connect ask alike. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv * session, tui3: the card comes back with your answer under it, not with the question again The first half of this change left the settled card out of a turn's replay altogether, and that traded one lie for another: the surface reads a propose_task call whose card never arrived as a call that was refused (task.go's [app.refuseFormingCard]), so coming back to the tab said `not started · the call was refused` over work that was running. So the engine states the outcome instead of the replay swallowing the question. [taskWait.decided] restates the proposal with the answer stamped on it the moment anybody settles it — a person, another window, or the countdown — beside the restatement [taskWait.withdraw] already made for the other ending, and at the one place both roads pass through. A card that states its own outcome is not asking anything, so the replay keeps it and leaves the open one out. The surface draws it as what it is: the assignment with the answer under it and no question raised. [taskVerdict] is the one reading of approved-and-redirect that the window whose key answered and the window replaying a decision both take. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv * docs: the change entry for Agent-Field#1036 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0182eyxXP8Xe7ADNKpYDe4wv --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…he same turn carries on (Agent-Field#1037) * approval: let account discovery reach its own question The shipped prompt blanket put approval questions in front of both account discovery and the connect card. Account listing now lifts as a read, while the connect tool lifts because its own card is the one consent question; named rules, deny, and the existing floors still win. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * session: carry account connections through the same turn Connect answers used to collapse refusal, silence, and typed instructions into one no, while the tool description told the model to wait for another turn. Answer provenance now survives to distinct sentences, one shared instruction says to continue on the next request of this turn, and the belt teaches the conditional discovery path. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * tui3: settle browser waits when their turn ends A browser row could keep waiting and animating after its turn had closed, and words typed beneath a browser question opened a key-check card. Turn settlement now closes those rows with the existing incomplete wording, and only typed-key questions can open the check card. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * session: hide browser sign-in exchange details Browser callback failures used to pass their raw exchange text, including a state nonce, into the transcript and tool result. The session boundary now keeps vendor refusals in plain words and replaces internal exchange failures with one honest, non-sensitive sentence. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * manual: tell the truth about account connections The manual said the browser stayed closed, concurrent credential writers could lose a change, and account bootstrap tools followed the ordinary approval path. It now describes the opened browser and retained address, locked store, single connect question, same-turn continuation, and the distinct ways a question can finish. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * session: let a connect answer beat the clock The five-minute branch could call an answer silence after its resolver had already claimed the question. The clock and resolver now share one atomic winner, and a claimed answer is returned even when its send is still in flight. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * connect: hide every failed browser exchange The session hid familiar OAuth failures, but unknown text passed through and the Connections tab still drew raw callback errors. Browser failures now cross one deny-by-default boundary; only a short vendor-shaped refusal is retained. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * session: prove account pickup on the shipped posture The same-turn acceptance ran under blanket allow, where its zero-consent claim could not fail. It now runs under the shipped prompt posture and proves the connect card is the only question before the newly armed tool runs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * manual: keep account answers inside the search window The privacy heading traded away the old asker's words, the SearchBoth guard was rewritten into a plain search, and the MCP inventory was split under false counts. Both vocabularies now retrieve, the rescue direction is loud again, and the original 28-row section is whole. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * session: the account cue pays for itself out of what was said twice The new account sentence and the same-turn wording pushed both prefix arms 79 bytes over their caps, and the sentence named `services` without the belt fact claiming that name. The fact now lists both tools it spells, says only what has to be true before the call, and `use_service` no longer repeats the ordering the fact already gives — leaving both prefixes below where they were on dev. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * changelog: the connect-on-demand entry for Agent-Field#1037 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…e keystroke (Agent-Field#1039) Home's ctrl+e writes the archive flag and then re-reads the world on the spot, so that the row moves under the hand rather than on the next sweep. The seam it re-read through answers from what is held and refreshes behind itself, and the write went straight past that cache to the engine — so the rebuild redrew the row exactly as it was, and the row went only when a later beat's fetch had returned and a later beat rebuilt. Two seconds of allowed staleness plus up to two three-second beats is the several seconds a person saw between pressing the key and watching the row go. hostWorld.archive is the seam now: the write over the wire, then the held copy corrected and the entry aged out so the next reading still asks the engine what it really thinks. That is hostStanding.save's correction, which already existed for the ambient side, applied to the one write home makes against the world. A refused write changes nothing here, and bringing a row back is the same correction in the other direction. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Agent-Field#1041) * module: the import path is github.com/Agent-Field/codeaf The repository is being renamed from aforge-v2 to codeaf; the module path moves first, on its own, so the mechanical import rewrite is one reviewable commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * build: the binary, the commands and the corpus tag are codeaf The commands move with the product name: cmd/aforge becomes cmd/codeaf, and the five neighbours beside it — census, changes, demo-home, release, replay — follow. `make build` writes bin/codeaf, the packed-manual build tag is codeaf_packed_manual, the release artifact is codeaf-release, the CI scratch root is /tmp/codeaf-ci, and .gitignore's stray-binary line is /codeaf. The manual page starting-aforge.md is starting-codeaf.md, and every reference to it moves with it. release.yml stops naming the repository: RELEASE_REPOSITORY is now ${{ github.repository }}, which is right before the GitHub rename, right after it, and right in a fork that publishes to itself. The wide textual rename of the product's own words is the next commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * rename: the product in the Go sources is codeaf The wide textual pass over every Go file: identifiers, strings, comments and test expectations spell codeaf, CODEAF_ and ~/.codeaf where they spelled the old name. It is the mechanical half of the rename and it is deliberately plain — no fallback reads the old environment variable, no adoption moves an old state root, no shim answers to the old command. Those arrive next, so that they are added to a tree with one name in it rather than a tree with two. Four things the machine could not do on its own, and a person did: - `AForge` inside an ordinary English word is not the product. A blind pass turned `AForgedTool` and `AForgettablePreference` into rubble; both are English again, spelled so the letters of the old name no longer occur. - The folder search ladder was documented and tested entirely in queries derived from the old name — its lead, its initials, its loose reading and the transposition the last rung exists for. `codeaf` shares four letters with the `~/code/` every one of those paths begins with, so several of those queries now reach a higher rung and would never have tested the rung they were written for. Every example is rederived from the new name and the ladder's own comment says what it now says. - The wordmark on the first screen had no letterform for `c` or `d`, and [wordmarkRows] SKIPS a letter it cannot draw — so the first screen of a fresh install would have spelled the name with two holes in it. - The guard that failed any first-screen sentence still carrying the retired name compared against a literal the same pass had renamed, so it asserted the opposite of its intent. That duty is the whole tree's now, and the name law is where it goes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * rename: the manual, the docs and the tooling say codeaf The same wide pass over everything a person reads or runs: the two manual corpora, the system prompt, the READMEs and design notes, the workflows, the installer, the bench harnesses and their self-tests. The pieces that are plumbing rather than prose, and had to move with it: - `.gitignore` ignores `.codeaf/` where it ignored the old repository-local directory. - CHANGELOG.md keeps every word it recorded and loses one: the HTML comment `codeaf-changes roll` inserts beneath is the tool's anchor, not a release note, and the tool had just been renamed out from under it. - `internal/exec/testdata/rtk` is a stub, and the only thing it shares with the test driving it is the name of the variable it logs to. Renaming one and not the other left the stub logging to /dev/null and the test reading an empty file. - The realissue bench rig names the arm it runs. `bench/conversation`'s own runner had already moved to `codeaf`, so a candidate still declaring the old arm was one the runner would refuse to start. `test/remote`, `internal/furrowbin` and the two `docs/design` capture scripts are renamed too. They sit outside the paths the wide pass was pointed at, and each of them names the binary, the state root or an environment variable that had already moved — a stale spelling there is a broken command, not a stale word. furrow is still furrow throughout. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * manual: the pinned-version install line gives VERSION to bash `VERSION=<tag>` written before `bash` in a pipeline sets the variable for `curl`, which does not read it, and not for the script on the other side of the pipe — so the documented way to pin a release installed whatever `latest` resolved to. README.md, docs/rules/promotion.md and release.yml all spell the piped form already; this page was the one that did not, which is why internal/release's TestPublishedPinExamplesGiveVersionToBash was red on dev. The example is now a runnable line rather than a sentence describing one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * manual: the page says what codeaf used to be called `## What it is called` carried a sentence contrasting the wordmark's spelling with the prose's, and the mechanical rename collapsed both halves onto one word — it read "it used to say codeaf in some of those places and codeaf in the others", which says nothing and is the kind of sentence a reader stops trusting the page over. The history moves to its own `## The old name` section, which is where it can name the retired spellings honestly, and which is the one place in this corpus the name law lets them be written. It answers the five questions somebody actually asks — what happened to aforge, is this the same thing, is this the CodeAF from the benchmarks, why is the folder .codeaf now — and it states the three things on a person's machine that keep working: the adopted state folder and the link left behind, the AFORGE_ variable still read when the CODEAF_ one is unset, and .aforge-v3/config.json still read inside a repository. The section is written long rather than dense on purpose. A short section whose heading carries every one of those words outranks its own neighbours under BM25: the first draft took the top result for "how do I start codeaf" away from `## Starting it`, which is the page talking over itself. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chat: three comments and a failure message that named two retired products Each of these was written when the surface spelled one product in the letterforms and another in the prose three rows under it, and each named both. The mechanical rename wrote the same word into both halves, so all three now said a thing happened and then described it happening to itself. They are rewritten to keep the anecdote — which is the ONE SOURCE OF TRUTH law's own worked example and worth keeping — without naming a product that no longer exists. The name law covers internal/tui3, so restoring the dead spellings is not available to them, and a `legacy-name` marker is for a compatibility seam rather than for prose. TestTheWordmarksRightEdgeIsNeverAHoleBetweenTwoStrokes failed with "the name would read `aforga`", which was the old name with its `e` drawn as an `a`. It derives the word from [product] now, so the message stays true through the next rename as well. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * namelaw: a live surface cannot quietly say the old name again A rename is finished when the tree stops being able to undo it by accident. A wide `sed` makes every literal say the new word once; nothing then stops the next wave writing the old one back into a manual page, a workflow or a first-run sentence, and nobody finds out until somebody runs the wide search again. So the law is a package of nothing but the law, found by scripts/laws.sh through its go/parser import and therefore on the pull-request gate the day it lands. It reads every Go source under cmd, internal and bench; go.mod, the Makefile, the ignore file and the size budget; the workflows, the issue and pull-request templates and the rulesets README; the scripts and the bench tooling; both manual corpora and the session prompts; and the documents an agent is pointed at. A failure names the file and the line. The exemptions are records rather than holes, and each says why beside itself. CHANGELOG.md, docs/changes, docs/design, the captured frames, bench-results, audit-notes and everything under a testdata directory say what was true on the day they were written. A line marked `legacy-name` is a compatibility seam — inline it exempts only itself, and on a line of its own it reaches forward to the first blank line, which is how a multi-line string or a two-line shell fallback is marked once. A Markdown section headed with the words "old name" is the one page that explains the history to a person who asks. The root Markdown set is an allow-list and not a glob, so a lane's untracked spec or notes at the root is not silently promoted into a product surface. Fixture tests prove every boundary on a temporary tree rather than on this one, so the repository-sized assertion going green means the surfaces were read rather than that the walk found nothing convenient. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: the agent-facing guides name the product, and the name it replaced CLAUDE.md and AGENTS.md are one file reached through a symlink, so they stay byte-identical by construction. They gain `## The name` — codeaf, lowercase, since 2026-09-14, and the law that enforces it — and `## The old name, and the three places it is still allowed`, which names the retired spellings outright. Naming them is the point: an agent whose memory predates today will spell them, and a section that refuses to say the word cannot tell that agent it is wrong. The section's own heading carries the words "old name", which is the law's exemption, so the guide is allowed to say what it has to say. Two sentences the wide pass left standing on one word: PERF.md's owner ruling had become a tautology about builds, and docs/CHAT-V3.md still described the rename as a refactor that had not happened yet while spelling the new name for both sides of it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * tui3: the folder-search comments reason from the new name Four comments still explained the ladder with queries derived from the old name (an initials example with a letter the new name does not have, and a slip example that no longer slipped). They reason from the rederived examples now. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs/design/polish: the three audits keep their record The wide rename made both sides of a recorded comparison the same word, so sentences that once said the wordmark spelled one name while the prose spelled another became false. A dated audit is a record; it keeps the words it saw. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * env: one door for the product's own variables, and the old spelling behind it Every CODEAF_ name the product reads now goes through internal/env, which answers the CODEAF_ spelling and falls through to the AFORGE_ one when the new name is unset or set empty — so a machine whose shell still exports the former names keeps working for one release. There are two doors on purpose. Get and Lookup are for a name the caller knows at compile time, and they PANIC on anything that does not start with CODEAF_, because a constant naming somebody else's variable is a programmer error. Value and LookupValue are for a name that is a value at runtime — a settings row's Env field, a knob table, a seat, an onboarding row — where the same table can hold OPENROUTER_API_KEY beside CODEAF_MODEL; an owned name there gets the same fallback and a foreign one is read plain. The remaining call sites move in the commits that follow, and the law that keeps them there lands with the last of them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * home: both names resolve the state root, and the first real start adopts the old folder CODEAF_HOME wins; AFORGE_HOME is honoured when it says nothing. With neither set the root is ~/.codeaf when that exists, ~/.aforge when only that exists — a legacy root the adoption below could not move — and ~/.codeaf otherwise. THE ADOPTION IS ONE-WAY, ONCE, AND NEVER FATAL. On a machine with no ~/.codeaf and a real ~/.aforge directory, the first start of the real binary renames the folder and leaves ~/.aforge behind as a symlink to it, so an old PATH line (~/.aforge/bin), an old unit file, a running daemon and anybody's own script keep resolving. A second start changes nothing. Any failure is one line and the process continues — the resolution above then reads the old root, which is why the fallback exists rather than being dead weight. It is called from main and from nowhere else, and the exported door returns immediately inside a test binary: a test that resolves the state root must never move the state of whoever ran it (internal/home/undertest.go says why). The machinery underneath is driven directly by its own tests. `codeaf help env` says once that the AFORGE_ spelling is still read for one release, and the demo home now strips both spellings from the child it launches — an inherited AFORGE_HOME would otherwise point a throwaway launch at the owner's own state root, which is the single thing that file exists to prevent. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * project: a repository's own files are read under either name and written under one The three places codeaf keeps something inside somebody else's repository move to the new name and keep reading the old one: project settings are <workspace>/.codeaf/config.json with .aforge-v3/config.json read when the new file is absent, a conversation's autonomy rules are <workspace>/.codeaf/ autonomy.json with .aforge/autonomy.json behind them, and a repository's subharness shelf is <repo>/.codeaf/subharnesses with <repo>/.aforge/ subharnesses behind it. READS FALL BACK; WRITES NEVER DO. Every writer names the new path and leaves the old file exactly where it is — nothing here rewrites a person's repository on its own, and somebody who renames the folder themselves simply stops using the fallback. The comment above ProjectConfigDir said this directory was deliberately not on the product's final name because the rename would happen once, at the end. This is that rename, so the paragraph now says what is true instead. The orientation digest skips .aforge and .aforge-v3 beside .codeaf, so a repository that still carries either is not read to the model as source, and .gitignore knows about the new directory as well as the task system's own. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * tasks: the work is committed as codeaf and recognised under either name A task commit is authored codeaf <codeaf@localhost>. Every reader that has to tell the task system's own work from the person's accepts the former identity too, because an existing repository carries commits made under it: a branch that has only ever moved under one of those two identities has not been moved by the person, and a landing must not be held back from it. THE SAME RULE ONE DIRECTORY OVER. The folders the task system leaves inside a repository are still written as .codeaf-v3 — live worktrees are registered under that path by git itself and moving it is not something a compatibility layer may do — but every reader of them now recognises .aforge-v3 as well: branch protection, the audit walk, the mirror copy, the dirt reading, the left-behind scan, and the clean and reset that must not sweep an old folder away. One list, in one place, rather than a name spelled into nine files. An empty commit range is also no longer read as the person having moved the branch. The early returns above it mean the range normally holds a commit, but a reading that comes back with nothing has observed nothing — and the reading- failure case beside it already answers that the same way. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * standing: one timer per machine, and a child hears both spellings Installing the timer now stops and removes an aforge-tick unit on the same machine before writing codeaf-tick, on systemd and on launchd alike. A machine that had the old one would otherwise tick twice — two processes doing the same standing pass against the same state root, five minutes apart forever. The units it writes carry the state root under BOTH names, and the reader that digs the root back out of a unit file on disk accepts either, so a unit written by the old build still resolves after an upgrade and a unit written by this one still works if something downgrades. The same for every variable the product hands to a program it starts: a skill's check.sh, a skills-bin shell, an rtk shell. They receive the CODEAF_ name and the AFORGE_ one with the same value, because a script somebody wrote last month reads the name it was written against and this program cannot edit it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * remote and install: the far command is codeaf, and the law holds the door shut A host that answers "command not found" is told the program is called codeaf now — it was aforge before 2026-09-14 — and must be installed there under that name. There is no retry under the old name: a machine that has the old binary has the old program, and starting it would be a conversation against something else. The recogniser reads either word out of the far shell's own wording, because the sentence a person needs is the same either way. The installer pulls Agent-Field/codeaf, installs into ~/.codeaf/bin, marks the PATH line `# codeaf installer`, and reads CODEAF_* variables with the AFORGE_* ones as fallbacks. Two transitional roads, each with a comment saying when to delete it: a release lookup that 404s under the new repository is retried under Agent-Field/aforge-v2, and a release with no codeaf-<os>-<arch> asset installs the aforge one — under the new name, since what is installed is this program. AND THE LAW ARRIVES WITH THE LAST CALL SITE IT GOVERNS. internal/env's law reads the tree with go/parser — so scripts/laws.sh runs it on every pull request — and fails any product read of an owned variable through os: a CODEAF_ or AFORGE_ literal, a constant anywhere in the repository that holds one, or either pulled out of os.Environ. The table-driven families that cannot be seen through statically are held by a count of their dynamic-door calls instead. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * resident: the skill-check test names the old spelling where the law can see it The marker inside the embedded shell script was a string to the name law, so the tree was red on a line that was a legitimate shim. The old spelling is a Go constant on its own marked line now, interpolated into the script. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * pair and relay: a name on disk or on the wire is not renamed with the product A device key, a relay machine name, a registration label, two protocol tokens, two HTTP headers and the pairing PAKE's two identities are bytes an EXISTING machine already wrote down or already speaks. The wide pass renamed all of them, which unpairs every paired device (`decodeSeed` rejects a key written by any earlier build, and `Load` answers "is not a device key any more — remove it … which un-pairs every device it was paired with"), changes the machine name a person types after `--at`, and leaves an old relay unable to see either header. They keep their former spelling permanently, each marked `legacy-name`: these are not a one-release seam, they are the wire. The device-key reader accepts both prefixes and keeps writing the old one, so a key written by this build is still readable by a machine that has not upgraded. Only labels a person reads say codeaf. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * install and release: the folder is adopted before it is made, and an old release still resolves Three things the install road got wrong, each of which meets a person on the day they upgrade. THE INSTALLER MADE THE NEW STATE ROOT BEFORE THE BINARY COULD ADOPT THE OLD ONE. `mkdir -p "$INSTALL_DIR"` creates `~/.codeaf/bin`, and adoption declines the moment `~/.codeaf` exists — so every existing person who upgraded through the documented road looked brand new, with their conversations, projects, memories and keys on disk and unreachable. Proved against the real binary. The verified download is now run once from the temporary directory first, while `~/.codeaf` is still absent, and only when the install directory is under the state root. A PINNED VERSION COULD NOT REACH THE FORMER REPOSITORY. `VERSION=<tag>` skips the API call that carries the repository fallback, so a tag published before the GitHub rename resolved against a repository that does not exist yet — which is exactly the window this release sits in. The asset download falls back to the former repository too, keeping the checksum in the same one it chose. THE FORMER PATH LINE WAS LEFT BEHIND AND DUPLICATED. A shell file carrying `# aforge installer` kept a PATH entry for `~/.aforge/bin` — through the adoption link, the OLD binary — and gained a second line beside it. The old marker is recognised and its line is replaced in place. Also: the Release workflow read `.github/known-red.txt` under `set -euo pipefail`, and that ledger burned to zero in Agent-Field#1012. Every non-dev release job died before its tests. The Makefile already guarded for it; the workflow does now too. That line is byte-identical on dev — it is not this wave's regression, but this wave's release runs through it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * standing and wake: a timer written under the old name is seen, repaired and removed Installing a timer already removed its former-name twin, but nothing ever reached Install on the machine that needed it. `Timer.read` looked only at the current unit path, so a machine carrying `aforge-tick.*` reported no timer at all: the standing page said nothing was installed while the old unit went on firing, startup had no drift to repair, and turning standing off left it running. Reading falls back to the former units and reports them as installed and stale, and Uninstall removes both generations on both platforms. `internal/watchdog` — the v1 resident's wake timer — had no former-name spelling anywhere in the file. Status, install and uninstall each knew one generation, so an upgraded machine kept an active `aforge-wake` unit whose ExecStart still resolves through the adoption link to the OLD binary, invisible, and installing the current one gave it a second timer against one state root. It now carries the same shape internal/standing has. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * home: an unusable current root falls back, and the page stops promising the link Adoption and resolution both treated ANY existing object at `~/.codeaf` as the state root. A regular file there declined the adoption and was then returned as the root, so a person with real state in `~/.aforge` got `.codeaf/graph.db is a file, and a folder was needed there` and no way to their own things. Both now require a directory: anything else logs one line and the former directory goes on serving. The manual said codeaf leaves a link at the old path AND that a failure means it carries on reading the old folder. Those cannot both be true of the same run — the link is best effort AFTER the move, so a move that succeeds and a link that fails leaves no old path at all. The page says it tries to leave the link, and that it is the MOVE failing that keeps the old folder in use. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * environment and caches: the one door is used everywhere, and a cache is not thrown away A key reference a person STORED was read with `os.Getenv`, so a stored `CODEAF_X` got none of the fallback the environment package exists to give — and the law could not see it, because the law only knows a read whose argument it can read at parse time. The reference goes through the dynamic door, and the law gains injected fixtures for every shape it claims to refuse plus a sentence saying a runtime-supplied name is beyond it and `env.Value` is the door for one. The extracted-document cache headers were renamed, and the reader compares them exactly — so every `.extracted.md` on an existing machine became a miss and the document was extracted again, which on the OCR and model engines is money per document. The former headers are accepted on read; the current ones are still what is written. Four surfaces said an `AFORGE_*` name is read when the `CODEAF_*` one is "unset". The code also falls back on an empty one. They say "unset or empty". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * namelaw and English: one marked line is one exemption, and "an codeaf" is not a word A line that was exactly `// legacy-name` exempted every following non-blank line — a hole wide enough to hide a paragraph, and a different law from the one CLAUDE.md states, which is that each line carries its own marker. Nothing in the tree relied on the run, so only same-line markers open the exemption now, and the fixtures that blessed the run refuse it instead. Two markers sat on lines with nothing retired on them and are gone. `aforge` takes "an" and `codeaf` takes "a". Twelve sentences the wide pass left mid-sentence now read, including the two a person meets — the terminal page's "An `codeaf do` errand" and the models page's — and `internal/furrowbin`'s promise that "every codeaf is an codeaf with furrow". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * tasks and media: the repository's own folder is .codeaf, and the former one is still read Stage 1's wide pass turned `<workspace>/.aforge-v3/` into `.codeaf-v3/` — a spelling that has never existed on any disk — while the settings layer had already put the repository's own file at `<workspace>/.codeaf/config.json`. Two folders for one product is the thing this wave exists to remove, and every reader written as the LEGACY rung was spelled `.codeaf-v3`, so it found nothing anywhere. One folder now. Every dropping — tasks, images, music, audio, video, jobs, stubs, attachments, the ground baseline, the release receipt, the left-behind record — writes under `<workspace>/.codeaf/<kind>`, and every reader of a kind accepts `.aforge-v3/<kind>` beside it, marked `legacy-name`. Reads prefer the current path and fall back only when it is absent. Nothing rewrites somebody's repository on its own. THE TASK WORKTREE WAS THE ONE THAT BIT. `tasksDirName` was the only spelling used to build a worktree path and the git-root lock, so a task registered under `<repo>/.aforge-v3/tasks/<session>/<id>` — every task on every machine that has run this program — was not found, not resumed and not cleaned, and an old binary and a new one took DIFFERENT locks on one repository. Both paths are tried, and a fixture registers a real `git worktree` under the former path and carries it through reload, resume and removal. Nine manual pages told a person to use `.codeaf-v3/config.json` for a repository's settings — a path the code has never read. They say `.codeaf`, and the tasks page names both spellings once where it says what is never committed. `.gitignore` drops the line that never named anything, and the orientation digest stops walking a directory it could not recognise. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * changes: the entry for the rename carries its pull request number Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * config: the receipt names the spelling of the variable that answered A person who set AFORGE_MODEL was told the model came from CODEAF_MODEL, a row they never wrote. The env door now says which spelling supplied a value, the seat records it when the environment rung answers, and the receipt says that word. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* codeaf-changes: a notes command renders one version's section to fit a GitHub release page GitHub refuses a release body over 125,000 characters, and a rolled-up section carries every fold of every entry — the v0.2.0 section renders at 1.7 MB. `codeaf-changes notes <tag>` prints the section whole when it fits, the headline layer with the folds removed when it does not, and a cut at a line boundary when even that is too long, always ending with the line that says the record is in CHANGELOG.md. A tag with no section is a non-zero exit and nothing on stdout. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * release: the stable notes go through codeaf-changes notes, not an awk copy of the section The publish job copied the whole `## <tag>` section of CHANGELOG.md into the release body; the first roll-up would have failed the stable publish at the last step, after six binaries were built. The workflow now asks codeaf-changes for notes that fit, the workflow test refuses the awk copy coming back, and the two rules say what the page carries when the section is bigger than a body may be. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs/changes: the entry for Agent-Field#1044 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* docs/changes: v0.2.0 rolled up into CHANGELOG.md The 613 loose entries in docs/changes/unreleased/ — every pull request since v0.1.0, the codeaf rename included — are now the `## v0.2.0` section of CHANGELOG.md, headline lines with the claims one fold away, and the loose files are gone. This lands on dev before the promotion, as docs/rules/promotion.md orders, so the stable release reads its notes from this section. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * exec: the removed-worker law reads CHANGELOG.md as the record it already reads docs/changes as The law skipped docs/changes because a changelog entry says what was removed, by name, and rewriting it would falsify the record. The first roll-up moved those entries into CHANGELOG.md, which the law did not skip, and went red on the laws. The rolled-up changelog is the same record. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs/changes: the entry for Agent-Field#1045 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…Agent-Field#1047) * release: the release-surface test survives an absent known-red ledger The ledger burned to zero and was deleted (Agent-Field#1012). Under set -euo pipefail the step's first line — an awk over the missing file inside an assignment — exited 2 before go test ran, on every channel but dev, which skips this job. The first staging build after the deletion published nothing that way. The file is read only when it is there, as scripts/laws.sh reads it, and a test runs the real prologue under the real shell options with the ledger absent, empty, comments-only and carrying a name. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs/changes: the entry for Agent-Field#1047 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…ue on release day (Agent-Field#1050) * Make the release-day install story true Describe each release channel and the conditions on both installer roads. Disclose the bounded background rtk fetch used by codeaf do, and state when GitHub can enforce the checked-in branch rules. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs/changes: the release-day truth entry for Agent-Field#1050 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…Field#1051) * Third-party notices, generated from the build and guarded by a law Nothing in this repository reproduced the licences of the code compiled into the binary. internal/pair/cpace is BSD-3-Clause and linked into every build, whose clause 2 asks for the notice in the materials that go out with a binary distribution; internal/connect/ampcatalog/providers.json is an embedded copy of the amp-labs catalog; and every module in the build carries the same shape of obligation. None of them had a notice anywhere. THIRD-PARTY-NOTICES.md is that notice, and cmd/codeaf-notices generates it from the build itself — the modules `go list -deps ./cmd/codeaf` names, plus the two components this tree carries its own copies of — so it cannot be written by hand and cannot quietly go stale. Like codeaf-changes it is a developer's binary and never a verb on codeaf, so the product pays nothing for it. The law beside it reads the same module set and fails when a compiled module has no section, when either copied component is missing, and when the committed CPace licence text is no longer reproduced word for word. It needs no network and decides in a third of a second. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * A release carries the third-party notices beside its binaries The release workflow published dist/codeaf-* and checksums.txt and nothing else, so the notice existed in the repository and reached nobody who installed the thing. A licence that asks for its text in the materials provided with a binary distribution is not satisfied by a file on a branch. The build job now copies THIRD-PARTY-NOTICES.md into dist/ before the checksums are written, so checksums.txt covers it and the publish step — which already uploads dist/* — attaches it to every release on every channel. The installer needs no change: it looks up only the row naming its own asset and ignores the rest. internal/release asserts both lines, because a copy that quietly stops happening is exactly the kind of omission nobody notices until somebody asks for the notice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * README and the promotion runbook name the notices Somebody reading the install section had no way to know a notice ships, and somebody following the release runbook had no way to know it needs regenerating when the dependencies move. One line each, where the reader already is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs/changes: the change entry for the third-party notices Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Agent-Field#1056) * The installer takes the newest channel build, not the first one listed `--rc`, `--dev` and `--staging` read `releases?per_page=100` and took the first tag that matched the channel. GitHub does not return that list in publish order: with `--dev` today it chose `dev-20260915-e2ae913b7d0c` (13:43Z) while `dev-20260915-56a22c20ec53` (14:56Z) and `dev-20260915-4b6ec83cfbfa` (15:21Z) both existed, and a person got a stale build with no sign anything was wrong. The whole list is read now and the candidate with the greatest `published_at` wins, falling back to `created_at` when a release has no publish time. The refusal named only one of its two causes. A private repository answers an anonymous call with a 404 and took the same path, so a person was told about a rate limit that was not the problem; the sentence names both now. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * The change entry for the installer's channel pick Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…r silently (Agent-Field#1830) * automations: the design, and the core — schedule, store, presence, clock The design (docs/design/automations/DESIGN.md) replaces standing items and the v1 scheduler with one mechanism: a schedule, an optional look, an action, run only while a codeaf window is open. audit-notes/standing-and-schedules.md is the evidence it answers. internal/automation is the object and its machinery, with nothing wired yet: - schedule: five-field cron read in the automation's own zone, stepping in absolute time so the wall clock never goes backwards (a 01:30 line runs once on the night the clocks fall back); intervals on an anchored grid, so late runs never drift the next one; lines that never match are refused. - store: SQLite (WAL) with the person's half as a document and the clock's state as guarded columns; a slot becomes a run in one transaction and can never be taken twice; a change counter every window reads from. - presence: one OS lock per open window, so "is any window open?" is answered by the kernel, not a heartbeat. - clock: one holder at a time, catch-up once and marked late, one run per automation at a time, two pieces of work at once, watches that speak on the change to yes, explicit outcomes read from reports and context causes, and a clean stop when the last window closes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the engine side — the automation tool, its card, and the runner - `automation` (propose, list, pause, resume, delete, run, history) is on a conversation's belt when a store is behind it, and never on a task's or a run's: nothing an automation does may arm another. Every answer ends with the time. - The card is one question kind (`automation`) built once in the session: 1 Save · 2 Save and run it now / check it now (not for reminders or worktree work) · 0 Don't save · words are a correction. It shows the schedule in words and exactly, the first run, and a watch's estimated daily cost when the price is known. Save and run it now hands the action back to do in this turn, so approvals reach the person and "always" is banked for later runs. - The runner looks (a command with the provider keys stripped, a bounded file listing that says what changed since the last decided look, or a tool through the person's own gate with its connected account put to use first), judges every look on the low-tier seat and bills it to the usage ledger against the automation, and runs work as a session built from the person's own config: their approval rules with nobody to ask, the first refusal for want of the person stopping the run as your call, a money cap, and an outcome that comes only from `automation_report`. - File watches keep a small memo between looks so a change made while codeaf was closed is still seen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory always: the store keeps rules as memories marked always - A memories column, always_on, declared for new stores and added to old ones by migrateMemoriesAlways inside one immediate transaction, with a partial index over active rules; the owner migration now checks its column inside its transaction too, so two opens of one old store at once cannot both alter the table. - memory_always events set and clear the flag; the add and supersede payloads carry it, a supersession keeps the retired row's rule, and the replay and the sync fold both apply it. - The write door promotes a remembered row when the same words are asked for always, and never demotes a rule. - AlwaysMemories reads the rules for named owners in one order (person, machine, project; oldest first); rules are no longer router candidates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the clock process, window presence, and no timers on the machine - `codeaf clock` (hidden machinery, like `engine`) is the one process that runs automations: it takes the lock or leaves, builds each run's configuration through the same assembly a conversation uses (extracted from openV3Launch as v3ConfigFor, which finds no conversation and starts nothing), runs keyless when there is no key so reminders still work, and retires when its binary is replaced and nothing is running. - Every window holds presence for as long as runSurface runs and starts a clock when none holds the lock, checking again every 30s. - Conversations get the automations door, one store handle per process. - Every start of this build takes the old launchd/systemd timers (tick and wake, both names) off the login, acting only on definition files it finds under HOME. `codeaf tick` stays as a hidden verb that does nothing, so a timer an older build installed ends quietly until it is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the window side — the card, the run lines, notifications and the store watcher Every window reads the automations store on a two-second beat: a finished run draws one dim line in the conversation that made it, the first window on the machine to claim a run raises the desktop notification, and the quit question gets its snapshot. Local windows hold presence themselves; the doors to another machine will hold it there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory always: rules ride every turn and task, /always, the memory place's a - Session: remember gains always; a rule settles through the one write path and lands as a preference; an ordinary line never sees, rewords or retires a rule; /always (RememberAlways) asks nothing; AlwaysMemories lists the rules in force; a conversation with no project of its own keeps its rules for the person and says so. - The model's own rule is a question: internal/approval's KeepsARule is a floor under every allow (and under no policy at all), no memo or guardian answers it, its card offers no standing yes, and with nobody to ask it is refused in words the model can act on. - Injection beside the standing orders: an <always> block in message[0] (no ages, stable order, 12 rules / 2,400 runes, kept on a failed read, lean profiles included), task briefs, plan-born run workers and codeaf do; rules skip the binding reads and the memory tidy. - Wire: Memory.RememberAlways, Memory.Always and Memory.SetAlways. - TUI: /always and its listing, an always fact on rule rows, a on the strip and the foot, and the card. - Manual: three sections on what-i-remember and the probes that ask how to make a rule; PERF.md records the rules block's bounds. - The fixed prefix is over its cap by 152 bytes on this branch alone; the waivers are not raised (the standing deletion pays it back). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: delete the v1 resident's scheduler The v1 resident kept a scheduler nothing could reach: no surface has made a charter since Agent-Field#469, and no production code installs its timer. It still ran through `codeaf wake`, advertised in --help as "run one full background pass by hand", and doctor read its timer. docs/design/automations/DESIGN.md replaces all of it; this removes it. Gone: - internal/resident: the watch engine and sentinel seam (watch.go), charter commands and the timer offer (charters.go), tenure, the practice loop, the retrospective's charter proposals and hygiene nudges, and every hook in the tick, the quiet gate and the splice (the charter draft on compile). - internal/store: charter.go, charter_spec.go, tenure.go, standing_watch.go, the practice loop's half of practice.go and the dead notebook reads, the charter command kinds, the proposal-appetite trait and the "proposals" reversal class, and the three charter question categories. - internal/head: the temporal compiler (standing.go), the charter half of question answering (charters.go, now answers.go), rule targets in change/stop/recall/open/status, the `standing` belt read, and the money rails for standing proposals. - internal/watchdog, and internal/registry (no importers at all). - cmd/codeaf: wake's pass, the sentinel client, the doctor rows `background timer` and `standing`, and the wiring in resident_build.go. - config: practice_budget_usd, practice_idle, brief_after and tenure_after, their rows, resolvers and env-table lines; the keys are retired, so a profile holding one is not told it is ignored. `codeaf wake` stays dispatched as a hidden verb that does nothing and exits 0, because a timer an older build installed keeps running it until the first start of the automations build removes it, and an unknown verb exits 1. Old stores still open and rebuild. Every v1 event stays in the journal and replays as an unknown kind; the `charters` table is no longer created but is never dropped, and nothing reads it beyond a tolerant lookup naming an older build's work in a self receipt. nodes.charter_id, Provenance.CharterID, agent_questions.origin_charter_id, the brief's charter item and the practice rounds' question replay all stay, because removing them is a migration that says nothing new. A charter question an older build left open lapses on the next pass, and a queued charter command is refused in a sentence rather than by its spelling. internal/store/legacy_scheduler_test.go pins both halves. The resident's own manual loses standing-goals.md and says what happened in daily-rhythm.md; the chat manual's `codeaf wake` section becomes one short section with `codeaf tick`, and the doctor section loses its timer row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: over --host and --at — the far machine's store on the wire, and its clock kept for an attached window A window over --host or --at sits in front of a conversation on another machine, whose automation tool saves into that machine's store and whose clock runs only while a window is open there. So such a window now reads and changes the far machine's automations, and the far clock counts it. - Protocol 21: thirteen Automations.* calls, one per tui3.AutomationsSeam function, answered from the engine machine's store; Welcome.Automations and Welcome.AutomationsZone say the engine has them and in which zone a rhythm is read; Hello.Window says the connection is a window. - The engine door supplies remote.EngineAutomations (the store, the zone, and keepAutomationsWindow as HoldWindow). A Window hello holds presence before it is welcomed and lets it go on every road out; an engine with no store advertises nothing and refuses every call. - hostOptions builds the seam from the client when the welcome says so, and the zero seam otherwise. Only the --host and --at boot dials say Window; the beside dials and the local engine road never do, which a structural law now holds. - Manual: a section on which machine runs them and when they stop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the v1 scheduler is gone docs/STANDING.md opens with a note saying what was removed, what an older store keeps, and that docs/design/automations/DESIGN.md replaces it; the rest of the page is left as history. docs/FEATURES.md loses the entries that described the removed machinery as working: the timer offer, charter proposals, the practice loop, probation and tenure, and `codeaf wake`. The entries that only mentioned it (the modality rail, the retrospective, the arrival brief, curiosity receipts, competence, doctor and the environment list) now say what the code does. docs/LIMITS.md drops the practice carve-out row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the demo home seeds automations, not standing orders cmd/codeaf-demo-home now makes seven automations across its three projects (two reminders, the morning sweep on a cron line, a dependency bump in a separate worktree, a command watch on CI, a once-watch on pricing.json, and a paused one) and replays the clock over a fortnight of open windows, so their runs carry every outcome, late catch-ups, and run folders that are really on disk. Three were said in seeded conversations, whose Words are turns those journals have, so their lines land when those conversations open. The spend ledger books each run's own cost under UsageLine.Automation in place of the standing check line, and the package no longer imports internal/standing. internal/automation gains Store.SetClock: the one door a fixture needs to write a history through Create, Take, Start and Finish at the moment it happened. Nothing in the product calls it. A demo launch, and the hand-open line it prints, set CODEAF_NO_AUTOMATIONS=1, so no window opened on the demo starts the clock: the seeded work would otherwise run for real on the person's own key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the place, the typed command and the quit warning; standing leaves tui3 /automations replaces the standing place in the same slot: the list with each automation's schedule and last run, its history, and → run, pause, stop, edit, delete and open. The exact typed forms add, edit, run, pause, resume and delete, and an add or edit ends on a card like the model's. Leaving the last window with a run in hand warns once. Home's next panel and since-you-left read automations; ask here keeps working, re-homed to its own errands folder, with the automation card in its pane. Every standing surface in tui3 is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the hints teach automations, and the standing words leave the place prose Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the standing engine leaves the session, the doors and the wire - internal/session: the stand tool, its card, inbox, world section, mark and runner are deleted; the belt fact and the page's paragraph now name `automation`, and the prefix waivers fall to the measurement - automation runs borrow the brain read-only, as standing firings did - the memory tidy rides the clock (automation.Tidy), gated on MachineIdle - the sweep's fourth rule reaps stale errands and keeps any an automation was saved from - an automation card answered from another window takes every key its own card drew (`2` was refused at the doorstep) - cmd/codeaf: the ticker, the background repair, the standing seam and the host's standing cache are gone; the clock carries the tidy - remote: Standing.* methods, ResolveStanding and the marked submit leave the wire; the held kind goes; the surface-door ledger drops to 18 - config: the background-checks row is retired with its key - run: worker briefs close on the person's rules alone Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: watch names the idea, and the standing purpose goes - `watch`'s description said lasting checks were `stand`'s, a tool that is gone; it now names an automation without naming a verb some belts lack - the unused standing-check call purpose leaves; the replay tool still reads old logs that carry it - the fixed prefix falls another 8 bytes and its waiver with it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the docs say what was built - the design doc gains the typed grammar, the → keys, the quit warning as shipped, the store's notification claim, the kept `ask here` errands, the read-only brain and the tidy on the clock; the watch cost estimate it promised was never built and goes - the guide, the README, FEATURES, LIMITS and the memory docs name automations and `/always` where they named standing orders; the README's standing screenshot goes with the page it showed - AMBIENT and STANDING-ORDERS are marked superseded Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the kind's answer row is said to be the superset it is Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the reading says why it is handed its palette Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * e2e: automations replace standing orders in the end-to-end suite Nothing in internal/e2e imports internal/standing or leans on a standing door any more, so the package builds once those are deleted. - The host guard proves the old-timer removal touches only the throwaway login: testdata/oldtimers runs RemoveOldTimers as a real program behind the guard, and the developer's tick and wake files, both names, are hashed around it. The guard also stands in for osascript and notify-send, and sets CODEAF_NO_AUTOMATIONS=1 on every launch whose scenario does not name it. - The shared world keeps no ambient store and no standing answers; say and drain take none, and decline an automation card if one ever comes. - The three standing lanes are deleted. TestAutomationsE2E replaces the three TestTUIE2E subtests that were about standing orders, with no key: ask here ending on an automation card (wide and narrow), and a typed reminder said by the clock into its conversation, as a notification and on the automations place, then the clock leaving on its own. - The words table drops the standing rows, respells the ones automations renamed, and catches up with home's activity heading, the seven-place bar and the Spending tab's per-chat label; testHomeShape, testAnswerFromHome and testOneSpendFigure read what is drawn now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the tui3 and session test builds compile again Three test files still named what the standing removal took away, so neither package's tests built at this commit and no manual gate in them could run: notice_test.go proved a retirement event that no longer exists, and the usage tests asked for a spend subject that is now SubjectAutomation. - notice_test.go: the gesture is /automations, which fires eventAutomationsOpened. - usage_ledger_test.go: an automation's run writes its line under the automation's id, and the rollup names the automation. - usage_spend_test.go: the automation row and its subject word. These are byte for byte the versions 61022e9 carries, so the two branches agree on them when they meet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the e2e timing notes stop promising a standing pass Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the chat manual says what replaced standing orders The chat corpus still taught standing orders — /standing, the stand card, keeping an eye, the OS timer and `codeaf tick` — after automations had replaced them. The chat answers from these pages alone, so it would have offered a page, a key and a timer that no longer exist. - automations.md is new: reminders, scheduled work and watches; the card and its answers; schedules and cron; /automations and its → verbs; history and what a run came to; where the news arrives; the clock that runs only while a window is open, missed runs marked late; cost limits; worktree or checkout; the typed /automations forms; ask here; rules as memories marked always; the automation and automation_report tools; where standing orders went; and what automations cannot do. - keeping-an-eye.md and standing-orders.md are deleted. Every other page that described standing — home, keys, commands, places, screen, asking-from-home, the remote pages, models-and-cost, questions, tasks, what-i-can-do, what-i-remember, hints-and-tips and the rest — now says what the automations code does, quoting its strings. - chat_test.go: the forty-nine probes that reached a deleted page are pointed at the page that answers them now, and fifty-six probes are added in the asker's words. The rerun and due-time tests follow. - truth_test.go no longer imports internal/standing: the standing facts leave, and automation.DefaultTime and automation.DefaultUSD are pinned where the pages quote them. - asked.go's wants follow the pages; lawregistry_test.go drops the two laws filed against keeping-an-eye; session's manual gate opens an automations store so `automation` is checked, and a second gate builds a run's belt so `automation_report` is too. - The e2e due-time subtest still reaches home, and waits for the sentence that says where an automation's next time is shown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: internal/standing is deleted Nothing imports it any more: the session, the doors, the wire, the config, the manual's truth table and the end-to-end suite have all moved to internal/automation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: home's tip leads with the command A home tip says a key or a command first, and the one that taught saying an automation did not, so home's row broke its own law. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a collection cannot gain a standing item The kind names nothing codeaf runs any more. A row an older build wrote can still be found and taken out; the schema keeps the kind so an older build on the same machine still opens the database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a conversation switched to is told what it missed The missed runs were gathered only on a window's first reading, so a conversation switched to in a window already open never heard them. Now any conversation that comes to the front is asked about once, and a run a window has drawn is not drawn twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the manual says when an errand that went nowhere is cleared Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: gofmt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the complexity ratchet holds the automations engine The ratchet walked the standing ticker and inbox, which are gone; it now walks the automations clock, store and runner. The run's Work held 25 decisions against a ceiling of 15, so it is split along its own phases: the run's configuration, the turn watched for the two reasons to stop, and what it came to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: comments stop describing standing orders as live Comments in cmd/ and internal/ (internal/standing and internal/e2e left alone) that still described the standing feature as current now say what the code does: the automation tool, /automations, `codeaf clock` and the rules marked always. Historical records are kept, with doc links to deleted symbols turned into plain text or pointed at the replacement, and every bracketed link a rewritten comment names resolves. Comments only: the token stream of every changed file is identical outside comments, apart from one stray blank line in effortscope.go's import block that gofmt removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a run of work stops at the daily spending limit Standing firings were held to the person's daily limit; an automation's work run is shaped like a task, which the turn's check passes over, so it spent past the limit. It now asks before anything is made for it and reads `your call` when the limit is reached. A watch's looks are not held to it: each costs a fraction of a cent, and a refused look is news. The design doc gets back the watch cost estimate, which is built. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the suites pass without standing orders - home settles its phone shape before it builds again; the band read that used to do it went with standing orders - `/automations` has its fates on home: the place bare, a conversation for `add` and `edit`, home's own line for the id verbs - `automation_report` is communication, and both automation tools have a folder-hold disposition; `usd` is a fractional argument - the dead standing fields, the backlog fold, the held kind, a separator and three band orders are removed - tests that still named standing words, `/standing` as a door or the standing ladder stamper now read the automations surface Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: ask an ask-here errand's approvals in its own pane A call inside home's `ask here` errand that the approval policy grades "ask" blocks inside the errand's session until that agent is answered. errandEvent had no case for EventConsentRequest, and nothing else holds the errand's agent, so the errand sat `working` on a question no screen drew, and a `1` pressed at it went into the follow-up box. - The pane now draws the approval under the call it is about, with the conversation's own question builder and renderer: `1 allow once` and `3 deny`. There is no `always` from the pane. - The answer goes straight to the errand's agent (ResolveConsent), not through the block's door, whose receipt lands above the window's own box and whose `c change` would be answered by the window's engine. - The row says `waiting on you` and sorts first; the live block gives way while the turn waits; the call's row keeps `allowed`/`denied`. - The block's settle guard applies to the approval's digits and clicks, so a digit typed into a follow-up cannot allow an unread command. - Approvals are dropped when the turn ends; several in one step are asked oldest first. Results pair to rows by call id. - errandWait is renamed waitErrand so the harness's waiter law sees it and a test can hold a gated stream open. - asking-from-home.md says all of this, and no longer sends approvals to `continue as a conversation`, which ends the waiting call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the word stands on the tab bar, between memory and spend A place that appeared only while somebody stood in it was a room nobody knew was there. Eight words need 84 columns, so a narrower frame folds spend and settings behind more. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: one strength, one write door, every line in front of every turn (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: banners through the terminal, closing pauses, and watches find the key What the owner's walkthrough of the first build found, fixed: - A banner is raised whether or not codeaf has the keyboard, so `r` on a reminder raises one too. In iTerm2 it is iTerm2's own (OSC 9), in Ghostty, kitty, WezTerm and foot the terminal's OSC 777, and clicking it brings the tab back. Elsewhere it is osascript with a sound, or notify-send with the logo. The first banner on a machine names the sending app once, linked to Notification settings. A codeaf-branded macOS banner needs a Developer ID: macOS 26 refuses an ad-hoc-signed applet silently. - A run's line is also said on the message line of home or the place in front. - Quitting never asks. A run closing codeaf cut off is told to nobody and runs again, once, when a window next opens. - A watch's check passes over a model whose service has no key, down to the conversation's own model, and names the model and service when none is reachable. The clock re-reads the saved key before every run, and follows the newest window's environment (a salted fingerprint, never a value), so a key exported in one shell and not another no longer decides it. - The typed form reads `at 6pm`, `at tomorrow 9am` and `at monday 9am` without quotes. - The clock no longer runs the memory tidy, which the memory rework rules out. - Home's since-you-left whisper no longer says watches run while codeaf is shut. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the demo's cut-off run is one the person stopped, and the row-zero law starts at 84 columns A run codeaf closing cut off now picks up again, which the demo's replay of the rhythm cannot express. Eight words on the bar need 84 columns, so that is where the bar is promised never to move. The since-you-left whisper says what happened rather than what landed, which a first look must not claim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: store, reflex and session tests for one strength (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: surface tests for one strength (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: wire, door and seeder tests for one strength (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the tidy, its clock types and the rule-consent floor are gone Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the manual, the settings row and the last stale seams match one strength - what-i-remember is rewritten for one strength, the Memory tab, noticing and undo; the other chat pages stop describing the router, the always flag, the tidy, the shelf key and "memory is off" - the settings row is "notice things to remember" and applies from the next turn - the model's forget is seeded allow beside remember: both say what they did and /forget takes it back - a far engine with no store says "memory is unavailable on this machine" - a live switch to the lean profile keeps the memory block - the speed and no-change tests read the noticing pass instead of the removed pre-turn recall and extractor Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the laws, the waivers and the docs follow one strength - lane.RoleRecall goes with the pre-turn recall: a role nobody calls is owed a deletion, and the provider tests that borrowed it use the tool role - the complexity ratchet watches the memory engine instead of the deleted contextual files; learnFromTurn, importMemoryFile and MemorySnapshot split under its ceiling - both prefix waivers fall to the measurement (52,519 and 44,915), in PERF.md too, and PERF.md's memory sections describe the one bounded block - tests that pinned the old shape (lean and tool-less pages dropped memory, an explained override became a memory, the settings row needed a restart) now pin the new one - the settings detail leads with what off does, and "remember across chats" still finds the row - docs/memory-architecture.md describes what memory is now; the contextual page is a pointer into history; the audit that started this is kept Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a test name stops spelling the old product name Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the change entry for Agent-Field#1830 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the change entry for Agent-Field#1831 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a run's whole result is read in its history, and its banner carries it The run under the cursor in an automation's history shows its full report in ordinary text, and the history opens on the newest run. A banner says what the run came to and up to 180 characters of its report, without repeating the title. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the Memories tab reads like Activity, and /forget is gone - the tab is "Memories"; typing "memory" still finds it, and eight tab words now need 86 columns - groups are rows of their own that open on → and fold on ←, never enter; lines hang on tree connectors with kept-by and age columns, and a pane reads the cursor row out on frames of 110 columns or more - the words being written on the add row or in a line's editor are drawn in that row, with the caret; before, they were typed into nothing visible - /forget and the undo stack behind it are removed: a person forgets and puts back on the tab, the model's forget stays, and every receipt made on the person's behalf says "see or forget it on the Memories tab" - wire Memory.ForgetQuery goes with the command, folded into Version 22 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the review's fixes - Deleting an automation stops its run in hand: the clock asks whether each run's automation still exists, since the delete takes the run rows (and any stop request) with it. - A rhythm of days that would overflow a duration is refused, not wrapped. - A files watch's walk checks its budget and its run's context on every entry, so a rarely matching glob over a whole home no longer walks it all. - The judge's client is kept per model and account, so a replaced key is used. - A window's presence file is locked and written before it is renamed into place, so a counter can no longer remove a window being opened. - `codeaf do` reads the rules before its deadline starts. - A typed id needs four characters, and the refusal says where the id comes from. A ~ folder crosses unexpanded and the store reads it as its own machine's home, so a line typed over --host names the far machine's folder. - Each automation keeps its last hundred runs; forgotten and deleted runs' folders go, except a folder holding a worktree, whose changes are the person's to review. - A watch's banner says its own line, not what its look saw. - The old timers' files are removed before their jobs are unloaded, by label. - Stale docs and comments; the audit note is dropped from the change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the catalogue test reads the Memories tab row Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the bound is the store's, held inside every write Review fixes for Agent-Field#1830. - the 4,800-rune bound, the line cost and the quoting move to the store (memory_room.go); every door that makes a line active — write, replace, reword, move, put back — is measured inside its write transaction against every block the owner reaches, so a line kept everywhere cannot overflow another project, and two writers with room for one admit one - duplicates are the target owner's only; a move or a replacement onto words already kept lets the copy go instead of keeping two, and a forgotten line cannot be moved - a store an earlier build filled past the bound lets its always rules, then project, machine and person lines ride (FitMemories), and the conversation says once how many don't fit - the model's remember and forget act only on a turn the person typed - a noticed line is said on the standing lane when the turn's stream has closed; an ask-here errand is not noticed - memories_fts stays this release for older engines still running - the settings row reads one spelling; the tab's foot over an empty filter says esc; the project lookup's wire error is no longer "no project" - stale comments, names and docs; the audit notes and the contextual doc go Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the guide's tool table names automation, not the removed stand Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: tell a person who had memory off, once per machine, that their lines ride The owner's ruling on R8: on the first start after the upgrade, a person whose memory row was off is told once that their N kept lines now ride every conversation they hold in, with the Memories tab to forget them. The marker is created exclusively beside the store on that first start whatever the setting says, so it is said once per machine and never to someone who turns noticing off later. No line changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a woken turn does not arm the model's verbs; the person's line does A turn a task's landing or a job's ending opens is empty and marked a wake, and it armed remember/forget because it carried no authored mark. The verbs now arm only on a non-empty line the person typed, on their line drained into a turn mid-way, and on the follow-up turn started to answer a line they typed in the last seconds of the turn before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a line noticed while its conversation is out of sight waits for the person The keeper holds a conversation's standing lane while another is on screen, and it drained memory's notices to nowhere. Memory's notices now say they are in no record (Event.Unrecorded); the keeper keeps them, files them with the conversation's parked receipts, and coming back draws them there. A turn's own lines wait for the turn to end, since coming back mid-turn replays them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a full refusal says whose block it would overflow; an already-kept correction is said The store's refusal now carries the owner it would overflow, and every door says it from the conversation's own view: here, for <project>, or in another project. Over --host the name in the text is compared instead. Noticing a correction that was already kept lets the old line go and now says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: test the bound on replacement, the unbounded import and a held second writer A seam inside the room check holds the first writer in its transaction; the second must not read the room until the first commits, and then finds none. The test fails with deferred transactions. Replacement is measured, and the legacy import is kept whole past the bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: words already kept are not put back twice; an unknown project counts nothing Putting back a line, or rewording one, onto words its owner already keeps active is refused with store.ErrMemoryKept, and the tab says "already kept". When the engine cannot say which project this is, the tab takes nothing from the failed answer and its head row draws no don't-fit count. Tests cover the tab's refusal words, the no-match hint and the no-project note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: a stub keeps the changelog's contextual-memory link; its terminal recipe goes CHANGELOG.md links docs/contextual-memory.md, so a one-line page says it is retired and where its contents are. The terminal acceptance recipe and its recorder tested the removed evidence layer, and are deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the manual, the change entry and the design say what round two changed Full receipts say whose block; words already kept are refused on put-back and rewording; an already-kept correction is said; a line noticed out of sight waits for the person; a woken turn arms the verbs only once the person types; an unknown project counts nothing that doesn't fit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the turn that answers the person carries it on its own message A stale flag could outlive a failed, declined, vision or abandoned turn and arm the next task's landing. The drain now reports whether it heard the person: mid-turn that arms the rest of the turn, and at the turn's end the follow-up wake's opening carries answersPerson. No agent state is left. A real-loop test fails a turn after a steer and checks the next wake is not armed; the keeper's turn notices, the hand-off on the way forward and the unrecorded mark are each pinned by a test that fails without them. The manual says an answer to a question on an idle conversation does not arm the verbs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the change entry records the re-measured prefix waivers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… is refused (Agent-Field#1837) * automations: a finished reminder moved later wakes again; a late save is refused Moving a FINISHED one-time reminder later with `e` on /automations could leave the row finished. Two things combined: - CommandLine wrote a one-time `at` to the minute, so an `in 2m` reminder (seconds precision) came back earlier in the box, and "the next minute" could be seconds away. - Store.Update saved a new one-time moment that had already passed while the card was up as the next run; the clock took it at once and the reminder was finished again a beat after the save. Fixes: - The edit line keeps a moment's seconds (and fraction); parseMoment reads them. - Store.Update refuses a changed one-time moment that is not after now. - An edit is refused for a past moment only when it moves the moment, so a finished reminder can be renamed. - automation.NextAfterChange is the one rule both doors' cards use for the next run, so the typed edit no longer promises a run to a paused automation or a fresh slot to an unchanged rhythm. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * changelog: a finished reminder moved later wakes again (Agent-Field#1837) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: review fixes — paused receipt, DST round trip, manual - A typed edit of a paused automation says "still paused — resume starts it again" instead of a next slot it does not run at. - The edit line writes a moment in a fall-back's repeated hour with its offset, so it reads back as the same instant. - A moment that passed in the current minute is refused to the second. - The Store.Update comment names errPassed, and that a zone-only change to a one-time schedule is refused too. - DESIGN.md narrowed: only a change is refused at save time; an add answered late still runs once. - Manual: a section on a change refused at save time and renaming a finished reminder, the refusal list, and three retrieval probes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…gent-Field#1836) * tui3: make the switch and plan test fakes safe for the off-loop readers The -race failures in the held-send tests and the run-stop card test were in the test seams, not the surface. The kept conversation's watcher calls Attach from its own goroutine, and the door line asks PlanTasks, PlanTaskPage and the plan verbs off the loop; the real agents take their locks for all of these. The fakes did not: - switchAgent: Attach and its stop guard running/backlog/stops with a mutex; tests that flip running while a watcher is live use setRunning. - planFake: PlanTasks answers a copy as the store does; setStatus writes a new slice instead of over the one planAppWith handed the surface; pages are guarded, and the program-room test writes them through setPage. Fixes the four held-send races, TestStopOnTheRunsOwnPageRaisesTheCardAndTheCardStopsTheRun, and three more of the same class found on dev: TestAProgramRoomReadsTheLandingTheStoreEndedAhead, TestTheCancelKeyOnAPlanRowEndsItThroughTheStore, TestPOnAPlanRowPausesThenResumes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: change entry for the held-send race fakes (Agent-Field#1836) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: keep the Agent-Field#1836 change entry title under 100 characters Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * tui3: route the plan fakes' test writes through their lock; atomic rail counters Review follow-ups on Agent-Field#1836: - railPlanCounter's rows/pages counts are atomic; they are bumped by the surface's off-loop reads. - planFake gains editRows (in place, keeping planAppWith's aliasing) and setPlan; every direct test write to fake.plan and fake.pages goes through them or setPage. - switchAgent.mu's comment says exactly what it covers. - The change entry's invalidates line is cut to the rules' length and drops surface for this test-only change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…s what it says again (Agent-Field#969) (Agent-Field#1796) * census: the call row carries the demanded set, so served != lane means what it says again (Agent-Field#969) Since the chooser demands the whole admitted set (provider.only with fallbacks off), the router may serve any member of it, so Record.Lane (the ranked head) stopped being the only machine the request would accept. The census read served != lane as the router going somewhere we did not choose, which after the set-demand is often the router choosing a different member of the set we did choose. Add Record.Lanes []string, filled from laneChoice.Only when the demand is still being sent, carrying the whole set when it has two or more members (a one-machine demand is left to Lane alone). The census counts asked != served only when served fell OUTSIDE the admitted set. callrows.Row embeds calllog.Record, so the census reads the new field the day it lands. * docs: change entry for Agent-Field#1796 (demanded set on the call row) * address review: record the demand that actually travelled, not the original choice ZeroPoint95's review on Agent-Field#1796 caught that demandedLanes read the original laneChoice.Only, so a rescue (sends only:[B]) and a narrowed retry (drops a refused machine) recorded the whole original set and misattributed Lane. Capture provider.only as wirePreferences composed it, at encode time, onto the trace; carry it onto the openAttempt so a finish row written after a later attempt re-encoded still describes its own. demandedLanes now reads that composed set, and recordedLane names the single machine a narrowed attempt really demanded rather than the ranked head it recovered from. Adds the two wire-versus-log regression tests the review asked for: a rescue arm records only its one machine, and a narrowed retry does not keep the set it no longer demands and attributes to the machine it does. * address review 2: preserve the demanded set through the hopped close, fix docs ZeroPoint95's second review caught that closeOpenAttempt clears trace.open before recording, so a finish row built on the fallback close read the latest encode's demand rather than the closed attempt's. Carry the attempt's snapshot through recordFacts.demandedOnly and read it off the ended row in bodyDemandedOnly, keyed on ended (set only on that row) so an attempt closed carrying no demand is not handed a later one. Also remove the stale duplicated demandedLanes doc that still described reading laneChoice.Only, and correct the Record.Lanes doc: Lane is a member of the set but not necessarily its first element, since a three-to-two retry can keep the original ranked head as Lane while Lanes names the surviving pair. Adds TestAHoppedAttemptKeepsItsOwnDemandedSetThroughTheClose, which fails without the carry and passes with it. * docs: clarify call demand snapshot comments --------- Co-authored-by: ZeroPoint95 <329227198+ZeroPoint95@users.noreply.github.com>
* docs: describe the built-in coding, security and review specialists * docs: record the specialist README corrections * docs: refine specialist caveat and unwrap touched prose
Member
|
Hey, thanks for the PR. Could you sign the CLA when you get a chance so we can review it? |
Author
|
please Review the PR and let me know sir these is My first PR if I did anything mistake help i can learn |
…nt-Field#1546) (Agent-Field#1842) * session: the daily spend ceiling binds task and errand turns too (Agent-Field#1546) railBlockLocked skipped the daily budget check for InTask runners and the home Errand, and the crew guard that also enforces it is absent under --one-model and for an InTask agent with no crew. So a chat /task past the day's limit, and a task under --one-model, kept spending with no refusal while headless codeaf do and standing firings honoured the limit. Remove the InTask/Errand carve-out so the daily ceiling is checked on every turn-starting path. It is a ceiling read of the shared ledger, never a tally, so a path already held to the crew's own day cap is refused in two places, never charged twice. * docs: change entry for Agent-Field#1842 (daily ceiling on every path) * address review: carry the selected daily budget and spend preauthorization into workers ZeroPoint95's review on Agent-Field#1842 caught that the daily check read the default profile for workers (which carry no ProfileDir), so a worker refused under a higher selected limit and spent past a lower one, and that it re-applied the limit --yes-spend deliberately lifts. - Resolve the daily ceiling once at the root (where ProfileDir is set) and carry it as Config.DailyBudgetUSD; dailyCeilingUSD reads live from the profile for a root and the carried figure for a worker, never a profile at an empty path. - Carry Config.SpendPreauthorized (--yes-spend / CODEAF_PREAUTHORIZE_SPEND=1) into workers; it lifts the daily check and nothing else, matching the crew guard. - Thread both through all three worker constructors: the task-child (task_run.go), the adaptive-run worker (orchestrate.go) and the plan-run bash worker (run.CrewFactory, which gains a preauthorized parameter). Adds regressions: a worker held to its carried selected budget (higher allows, lower refuses) not the default, and preauthorization lifting the daily ceiling while a conversation limit stays in force. * fix: preserve daily budget authority in roots and task checks --------- Co-authored-by: ZeroPoint95 <329227198+ZeroPoint95@users.noreply.github.com>
…ld#1877) * docs: record DeepSWE harness versions and release context * docs: add DeepSWE version evidence change entry (Agent-Field#1877) * docs: use public senior-dev lineage and simplify version records
Collaborator
|
Thanks for putting this together. We can only review and merge contributions once the CLA is signed, and it's still pending a few days after the bot's prompt, so I'm closing this for now. If you sign it (link in the CLA comment above) and comment here, we'll reopen it and give it a proper review. |
…#1870) * fix: refresh Codex catalog client version * docs: record Codex catalog version fix for Agent-Field#1870 * test: cover version-gated Codex discovery through both catalog doors Pin the backend fixture independently of the shared client version so reverting the advertised version hides newer models in both direct and translated listings. Preserve visibility filtering and cached reasoning metadata. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Abir Abbas <abirabbas1998@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: build valid SQLite file URIs on Windows * docs: record Windows SQLite URI fix for Agent-Field#1868 * test: preserve POSIX SQLite URIs and cover Windows path forms Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Abir Abbas <abirabbas1998@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…1845) * fix(session): require explicit work orders for auto tasks * docs(changelog): add entry for PR 1845 * test(session): tolerate prompt line wrapping * fix(session): distinguish polite work requests from questions * test(session): cover routing authorization and stopped-result scope Separate feasibility questions from explanation requests in the shared route contract and the searchable chat manual. Pin examples with their complete classification clauses, and prove stopped-result suppression does not block fresh requests or normal remediation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(manual): make stopped-result routing reachable through search Give the stopped-result rule its own section so the manual context includes both the restart guard and the fresh-human-request exception. Pin the actual retrieved answer, since merely finding the long tasks page hid the rule beyond the section limit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(session): judge human steering during stopped-result wakes Read current-turn person provenance and judge the newly consumed instruction, including a verbatim repeat of the stopped request. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(session): scope stopped-result routing to each delivered task Keep attempt snapshots and effective obligations distinct even when sibling tasks inherit the same request. Skip result-only cancelled work before classification, and show both readers only the independent eligible work with explicit cancellation boundaries. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(session): restore task cancellation from its saved ending Derive the stopped runtime flag from the persisted stopped ending. Keep restored cancelled results out of routing while ordinary failed results retain repair eligibility. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(session): limit stopped-result guard to unambiguous result-only wakes Keep dev's routing inputs, floors and rulings whenever a human speaks, results are mixed, or provenance is incomplete. Skip both classifiers only when every delivered result is stopped for the current request in a result-only wake. Remove scoped eligible-work questions, attempt tags and snapshot deduplication. Retain frozen stop provenance and restored cancellation for the stop-only case. Preserve untagged news through batching without changing existing owed asks. Compare production wake, Submit, retry, cancel and recovery probes against dev, and narrow the manual and change entry to the conservative guarantee. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(session): drain steering before reading routes in stopped-wake tests Both fresh-human stopped-wake tests submitted a steer from the answer hook but let the turn race the boundary drain, so CI could count one route reading instead of two. Drain inside the hook, as the mixed-result steering test already does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Abir Abbas <abirabbas1998@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Author
|
Hi, I've signed the CLA as requested. Could you please reopen the PR and review my contribution? Thanks sir! |
…gent-Field#1884) * docs(agents): say CI is real, Spark is private and no key is normal Agents in cloud sessions kept reporting that the repository has no CI and no Spark. CI is GitHub Actions and runs on every pull request; gh fails there only because its token does not authenticate, so the guide now points at the GitHub MCP tools. Spark is the owner's private machine and was never a step anyone else owed. Add a when-to-run table so cloud sessions lean on touched packages instead of repeating it locally, and drop the PR template's line about the deleted known-red ledger. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtiPtzDsHa753NHJBpKYpn * docs(changelog): add entry for PR 1884 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtiPtzDsHa753NHJBpKYpn --------- Co-authored-by: Claude <noreply@anthropic.com>
…pers (Agent-Field#1881) * tui3: /helpers makes this conversation a new team's manager and asks it for helpers A person deep in a piece of work can now turn it into a team effort with the conversation that knows the work in charge. `/helpers` (or `+ Make team` beside Tasks in the right-hand column of a chat in no team) makes a new top-level team with the conversation in front as its manager in one store edit, narrows the strip to it, and once the store has taken the edit sends the conversation one turn: propose two or three helpers, ask, start nobody until the person agrees. The person answers in words. Yes is team_start under the usual approval posture; no is the new team_dissolve, which forgets a team that has never held anyone but its manager (no member, former member, subteam or Traffic). It is on the belt only while that is true, for every team however it was made, and the store checks again under its lock. Every rule a team made on the Teams page meets is met here: a fresh name, the next colour, one conversation managing one team and its subteams, and the store's refusal taking the window back. The manual's team manager page has the command, when it is not offered, and cancelling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * tui3: /helpers lives in the Teams dropdown, and says what it asks The column button beside Tasks is gone. The Teams dropdown's last row, under a rule, is now always `+ New from this session`: it puts `/helpers` and a default ask in the message box, in place of what was there (kept on the drafts ring), and sends nothing until the person presses enter. Because the row is always there, the `Teams ▾` chip shows with no teams yet; only over --host to an engine without teams is it absent. The dropdown no longer prints an up/down, enter, esc footer. Nothing hidden is sent any more. /helpers sends exactly the words after it, and a bare /helpers sends the default ask and shows it in full in the transcript. The ask is in the person's words and names no tool; the model knows it manages the team from the role note every manager gets. A helper the manager starts opens as a tab on that team's strip: when the manager is in front, the strip is set to the team's overlay, without moving focus or the draft. The cursor no longer lands on the new row when no team is shown, and the long-list window follows the cursor's line, now that a rule sits between the teams and the last row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * tui3: + New from this session only with no team selected With a team's overlay on the strip, the Teams dropdown no longer offers `+ New from this session`, and /helpers refuses with `/helpers works with no team selected · clear <team> with × first, or use + Add subteam on Teams for a team inside it`. The team /helpers makes is always top-level, and making it from inside another team's overlay read as nesting. Nesting keeps its own doors: + Add subteam on Teams, and a manager's sub-team start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * tui3: a 💡 tip for /helpers `/helpers makes this conversation the manager of a new team` joins the tips, after /task's. It is armed only where /helpers would act: after the first exchange, with no team selected, in a conversation that manages none, never on home. It retires the first time /helpers is typed or the Teams dropdown's `+ New from this session` is chosen. The table is twenty-five tips now, and the hints page says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * session: a conversation that has gone on may suggest /helpers, once After the person's fourth message, an interactive conversation in no team is told once, in a note of its own, that it may end a reply with one sentence suggesting a team when the work is long and has parts a few helpers could take on at once: "Want to bring in some helpers? Type /helpers and I'll suggest who." Only the person can make the team; the note says so, and says never for small work, never instead of the work, and never again once suggested or declined. It is a note and not a paragraph of prompts/system.md because the page is the fixed prefix every request pays for, held under a budget that only shrinks, and the suggestion only fits a conversation that has gone on. Tasks' workers, automation runs, home's ask here and conversations already in a team are never told. The team manager page says why the chat suggested it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * session: a member a manager started wakes with its brief again On an ordinary launch every team edit goes through the engine's teams door, which stamps a new member's join time. A member started by team_start always joins after the start that made it was written, and the join bound in the Traffic delivery dropped that start: nothing was addressed to the member, the start watch never woke it, and helpers sat idle while the manager reported them running. The unit test missed it because it added the member with no join time. A member's own start, addressed to its handle within the start grace, is now exempt from the bound; every other line from before the join is still withheld, which the new test also holds. The default /helpers ask no longer says "Don't start anyone until I agree", which the memory that notices rules kept as a standing project rule. It now says what happens next in this exchange: "I'll answer yes, ask for changes, or cancel." Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: change entry for /helpers (Agent-Field#1881) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * tui3: + New from this session makes the team at once; /helpers asks it Choosing the Teams dropdown's row used to fill the message box and nothing else, and the change below was easy to miss. The row now makes the team the moment it is chosen: this conversation becomes its manager, the strip narrows to it and the column turns to its Traffic on the same frame, and the box is given `/helpers` and the ask for the next step. /helpers now asks the team the conversation in front manages for helpers, and makes no team. In a conversation that manages none it changes nothing and says to use + New from this session. A /helpers sent before the store has the row's team is held until it does, so the manager's first step already knows it is one. A refused save empties the box again. The default ask is one sentence: "Suggest two or three helpers for this work, and I'll say yes, change them, or cancel." The tip, the one-time suggestion note, the command rows, the manual and the change entry say where the team is made now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * tui3: the team + New from this session makes is named after the conversation The click still makes the team at once, under its folder's name, so the strip changes on the frame. Beside the line, the naming role is asked once (five seconds at most, on the cheap naming model) for one or two words naming the work, from the conversation's title or opening words, and the team takes the answer. The rename is a teams-store edit applied only while the team still has the name it was made with and no other team has the new one, so a name the person chose here or in another window is never replaced, and a team that is gone stays gone. A failure, a timeout or an answer that is not a name leaves the folder's name. The receipt says the final name once; a name that arrives after it is said on its own line. session's NameTeamWords asks the short question and cuts to the limit; NameTeam is the group's three. Teams.Name carries an optional words field; an engine without it answers the group's question and the surface cuts the answer to two words. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(teams): bind startup briefs to memberships and retire used-team dissolve --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Hotfix of Agent-Field#1887 onto v0.8.0, carrying only that change to main. Connected services ask for streamed token counts with stream_options.include_usage (the default router road keeps its existing usage request), an explicit 400/422 refusal of the option retries once and is remembered per endpoint, and missing text counts gain separately labelled estimates that never enter billing. Each physical answer keeps its own hashed receipt so a later provider receipt replaces its estimate in analytics. The relay that accepts the new usage statuses shipped as website-open-infra Agent-Field#82. The settings page keeps v0.8.0's resident practice paragraph; the rest of the change is byte-identical to Agent-Field#1887's head 9445d02 except where dev-only commits had moved the surrounding lines. Co-Authored-By: Abir Abbas <abirabbas1998@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The v0.8.1 hotfix carries Agent-Field#1887 alone on top of v0.8.0, so its section holds that change and the v0.8.0 reconciliation entry (Agent-Field#1825) that was still loose on main. Both entries leave the unreleased folder here, and the merge back into staging and dev removes them there too, so the next roll-up on dev cannot list them a second time. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: improve model usage accounting across providers * docs: keep account-specific references out of usage documentation * docs: record model usage accounting changes for Agent-Field#1887 * fix: include structured text responses in model usage estimates * fix(provider): preserve usage roads and unique attempt receipts Streamed requests had gained stream_options on the default router road, changing its established wire bytes. Only connected services now ask for that option, following the actual endpoint after a billing-road change. The router retains its existing usage.include request. The usage option had also admitted unrelated streamed 400s to learn(), and a connected endpoint refusing it with 422 failed a call dev answered. Keep the old repair eligibility independent of the usage option and retry only an explicit unsupported-option refusal on 400 or 422. Remember that refusal for the endpoint without changing unrelated errors. Cover router and connected wire shapes, fallback and refusal memoization, dev error/request-count parity, raw-stream single settlement, and the separation between token estimates and billing. Update the manual and usage disclosures with the precise roads and refusal statuses. Ollama 0.9.0 reuses generation ids from a small random range. The former receipt key collapsed separate answers and reused event ids with different counts. Include the physical attempt in that key, and carry it through late recovery so estimates still pair with their measured receipt. Cover repeated provider ids and raw-stream recovery without duplicate rows or bills. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(telemetry): preserve receipt presence and emit safe token shapes Previously a caller's status could disagree with emitted components, unsafe integers could reach the relay, and late receipts could turn absent counts into measured zeroes. Derive status from safe emitted components, omit invalid counts and unsafe sums, and require a receipt identity for estimates. Keep late token presence through a session-bound recorder. Cost-only recovery emits no token update; one-sided recovery stays partial. Extend the shared fixture and test its outputs against the relay's validation rules. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(provider): reconcile receipt identity and compose usage repairs Previously whitespace generation ids split recovery from observation, repeated tool names inflated estimates, opaque replay counted as input text, and a metadata-only cut invented observed zero output. Canonicalize the generation inside the physical-attempt receipt helper and count only honest observations. Compose independent repairs once each without widening unrelated refusal handling. Associate usage-option refusal wording with that option. Preserve late token presence and recovered prices. Keep unmetered direct-service answers off receipt lookup because recovery retains the original bearer. Prove native cache aliases match canonical billing counts and token pricing; no estimate is banked or priced. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: describe measured aliases and usage receipt limits Previously the disclosure omitted the total-only exception and overstated measurement and recovery behavior. Describe component-preserving recovery, canonical receipt identities, safe numeric limits, opaque input, empty output, and bounded composed repairs. Record the deliberate native-alias measured-count change and unchanged no-lookup behavior for unmetered direct-service overflow. Estimates remain separate from billing, response usage and spend. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Abir Abbas <abirabbas1998@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
main receives Agent-Field#1887 alone as v0.8.1; merging that hotfix here keeps every later staging-to-main promotion a fast-forward and lets the release guard find the rc commit on staging. Where staging already matched dev, the merged files are byte-identical to Agent-Field#1887's head. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Agent-Field#1887 reached dev as 663dfbf and main as the v0.8.1 hotfix. This merge brings that hotfix's history and changelog roll-up here, so dev keeps containing staging and main. Code is unchanged; the v0.8.1 section lands in CHANGELOG.md, and the Agent-Field#1825 and Agent-Field#1887 entries it rolled up leave the unreleased folder so the next roll-up does not list them again. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Author
|
Dear santoshkumar sir please check these pR let me know any thing wrong which i made Thank You Sir |
santoshkumarradha
force-pushed
the
dev
branch
from
October 24, 2026 21:53
a2f0486 to
d68bcf8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Supported Platforms
Testing
Notes
Motivation
Provide a convenient Homebrew installation option for CodeAF and establish automated validation to improve packaging reliability.