Skip to content

santos/dev2 lands on dev: the worker harness as default, runs as work, skills from other harnesses, the chat as manager - #1410

Merged
AbirAbbas merged 879 commits into
devfrom
santos/dev2
Sep 25, 2026
Merged

AbirAbbas merged 879 commits into
devfrom
santos/dev2

Conversation

@santoshkumarradha

@santoshkumarradha santoshkumarradha commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Brings santos/dev2 onto dev. dev is already merged in with a real merge commit, so this is a fast-forward: dev has nothing that dev2 lacks.

Status: ready for review. #1396 and the worker step-boundary fix are integrated. The current head 008363c98e6cff47cab919364d609d91a0037581 passed the light gate, touched-package tests, final required check, and CLA check on 2026-09-24.

What this brings

1. The worker harness, now the default. A task runs on a bash belt: one loop under both /task and codeaf do, with a checking seat for the belt check. CODEAF_TASK_BELT=node (or legacy, or off) is the way back to the older node belt. See #1109 waves 1, 2, 6 and 7, and #1335, #1340, #1355, #1207.

2. Runs as first-class work.

  • A run's life is the conversation's.
  • It works in its own copy, and the copy is written down so it can be found again.
  • Dollar and time limits end it by one road, and the ending names the limit that caused it.
  • A run's dollars reach the conversation's total.
  • Work that nothing is driving reads as interrupted, not failed, and is kept, readable with the earlier runs. Nothing carries an interrupted run on today; a new task starts a run of its own.
  • A stopped task reads stopped everywhere.

About 50 entries, from #1204 through #1305.

3. Skills from other tools. A skill shelf, use_skill, per-message automatic choice, a working /skill picker, and visible skill-use reporting. #1396 adds enabled Claude Code plugin skills, Codex bundled skills and linked skill folders. Skills work with memory on or off, and attachment/list operations cross the hosted session connection. The stable model catalog is bounded at 12 KiB of descriptions plus 2 KiB of names; keyword-based carry remains. #1409 adds OpenCode and Goose folders separately.

4. The chat as manager over the plan store. The chat role. The chat sees the plan when the person speaks, and notes are a channel into a running worker. See #1205, #1354, #1356 and #1357.

5. Task page, rail and step rows. The page and rail door. Step rows are cut from the commands as they ran, step numbers continue across a wake, and a call that did not run has no row. See #1231, #1257, #1260 and #1261.

6. Pickers. One fuzzy matcher for every picker, match highlighting, and the caret parks where you type (#1321).

7. Benchmarks and docs. The footprint benchmark and its method, resume cost (#1126, #1317), and ADHD-shaped answers (#1209).

8. Hardening.

Behaviour that changes on merge

  • Tasks run on the bash belt by default. Before, CODEAF_TASK_BELT=bash opted in. Now node, legacy or off opts out.
  • task.parallel = 0 means no limit on both doors.

Review

Every feature group above had a feature-level review against its change entry. The findings are being fixed in their own PRs into dev2, each with tests shown failing first and a full make check on the merged head.

Already in:

Also integrated:

Deferred skills decisions and limits

Per-scope skill enable/disable remains a product decision against automatic selection by meaning. #1409 remains separate. Claude Code's disable-model-invocation and user-invocable frontmatter are not yet honoured. Remote picker discovery still reads local disk, and task workers with memory off do not inherit the temporary shelf. These are not included as completed features in this PR.

Evidence

Latest verification (2026-09-24)

  • Skills from Claude Code plugins and Codex, with memory off, chosen by what they are for #1396 merged into this branch at 6f1f39f5 after its successful PR gate, clean integration and independent review.

  • 008363c9 fixes the original failing note-delivery test's cause: a worker could issue further actions while its asynchronous reader was still recording the preceding step. Task workers now wait for recording, limits and note delivery before another action; cancellation releases that wait.

  • Full internal/run passed. Note cases passed 10 repetitions; note/cap cases passed 20 repetitions under the race detector; the stricter cap assertion passed 30 repetitions. Deterministic tests cover acknowledgement, cancellation and ordinary asynchronous events. A temporary slow-recorder experiment reproduced the old failure and passed five times with the fix; no artificial delay remains.

  • Combined-tree focused run/session tests passed five repetitions, and make build passed. The published source tree matches the locally tested tree (5d7e675fc5a9c7898a8186762e2cc2238d67010c).

  • The earlier session failure named in Skills from Claude Code plugins and Codex, with memory off, chosen by what they are for #1396 passed 20 repetitions; the full telemetry package passed.

  • Local integration build, vet and manual checks passed. The local pr-ready run could not complete because the execution environment refuses a Unix socket in TestARecordingLaunchKeepsItsCallsInThisProcess. GitHub CI remains the final gate for the combined PR.

  • Final GitHub gate: GREEN on 008363c9: light gate, touched packages and required check all succeeded. Run 36053569186. PR marked ready for review after confirming the tested head is still current.

Review fixes (2026-09-24)

Pushed to this branch after review, as fast-forwards only, with no force-push.

dev merged in:

Four blockers fixed:

  • 3cc26ea04: a skill or Claude Code settings file that is not an ordinary file (a pipe, a device, or a link to one) is absent. A committed SKILL.md -> /dev/tty no longer hangs the chat.
  • 2d5cf1fb1: the default run road asks the machine (task.max_load, task.min_free_mb) before every worker it starts, and the rail says waiting · machine busy.
  • 01acafb17: codeaf do keeps its run record in a private folder under the state root, never in the person's repository.
  • ee5f424e5: a task that finishes on its capped step ends done and gets its review.
  • With them: 503150586 (manual pins), 2aaf5919e (change entry), f5cf5c86f (a test reads its refusal through a wrapped path).

Owner rulings written into the manual (ab036aaca). No behaviour changed.

  • A commit a task lands on the worker harness carries the bare Assisted-by: CodeAF. Only the older node belt's landing names the model.
  • A /task started after the conversation's dollar limit is spent still gets one paid call before the limit ends it.
  • Signing is on by default and has no off. A profile or shell that still turns the retired attribution row off is told so once, and only the model's name can be turned off.
  • A message carrying a picture carries no skills, the attached ones included.

codeaf do on a busy machine (41a57e164). It used to wait in silence until --timeout. Now:

  • The first held start prints waiting · machine busy · <the limit that held it> on stderr, once.
  • The first start after the hold prints starting · the machine has room again.
  • A timeout with nothing started still leaves 124 / stop: "deadline", and --json carries the held line in blocked_on.

Should-fixes filed as #1444–#1465. Also filed from this review: #1490 (read / read_document block on a pipe; pre-existing on dev), #1491 and #1492 (load-only test reds), and #1493 (a ruling on the Model Pool judge at low credit).

CI on 41a57e164: green. The light gate, touched packages (the whole dev2 delta) and check all passed on both the push run 36084156976 and the pull_request run 36084160527.

santoshkumarradha and others added 30 commits September 18, 2026 17:40
…en questions

The stamp and the rows covered every task the conversation's filter admitted,
and the held questions were read from a store kind nothing writes, so they were
always empty. The family is the root and what reaches it through its parents;
the questions are the session's open questions whose subject works one of those
tasks, by their heads.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ker seat)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ker seat)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…urns late (#1210)

The root's worker marks its task done in the store before it returns. When the supervisor's pass saw the store done in that gap, Start ended the run with the right outcome and an empty result. Start now reads the stored root result when the worker's return is missing. A new test holds the return back past one pass, so the gap is every run of the test.
…y, and the landing's deadline fits a real call

Deciding whether to refresh ran after every message and opened the plan store
twice each time; it now reads the rows the task sheet already carries and the
store read moves into the command. The landing waited half a second for a call
that takes two to four, so the refresh could only ever succeed in a test; it
waits six. The rail no longer draws the whole plan when its reading holds no
rows (a fallback added for a fixture), and the landing fixture sets the belt
itself instead of inheriting it from the shell that ran it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he loop and at the landing

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nced answer

The page the model read was six lines; it now says who is asking, when to open a
task, what an answer is, and what to do when the record does not hold it or the
person is steering. The rows, notes and task bodies are bounded, the page is
said once, and the answer is found by its braces.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The owner, 2026-09-18: a prompt is written so it is true in any setup. Two
example lines spelled a Go file and one a Go glob; they name a path and a name
pattern instead.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
AbirAbbas and others added 2 commits September 24, 2026 18:58
dev moved by one commit (f101ad2, #1440) while the first merge of the
day was being pushed; this brings it in.

Conflicted files and how each was settled:

- cmd/codeaf/chatv3_process.go: v3Process keeps dev2's catalog ownership
  (catalogs, closed, lifetime, ownCatalog, keepCatalog, takeCatalogs) and
  gains #1440's creditWatcher inside the struct. The process builds the
  skill shelf, then installs the credit watcher; neither needs the other.
  closeAll cancels processCtx and then joins the watcher.
- internal/manual/chat_test.go: dev2's six skills probes and #1440's five
  credits probes, side by side.

Broken by the merge without a textual conflict:

- internal/manual/chat/models-and-cost.md said a task on the shipped crew
  always runs on the paid worker model. While a known OpenRouter balance is
  low, an unwritten worker row now uses the free worker model; a row
  somebody chose keeps its model.

Checked with no change: the free crew covers all five tiers, and every
dev2 role (check, repair, belt worker, chat manager) reads one of them; a
402 is kept out of dev2's router retry, and the affordable-cap resend
happens once; one low-credit warning path per frame beside dev2's chips,
tip and keys rows; both launch roads wire ReadCredits once.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…and waited for

#1440's balance reads at launch, on a key change and on a switch to a paid
model run as Bubble Tea commands, and Bubble Tea does not wait for a
command it started. On santos/dev2 the process's closeAll cancels and joins
everything it owns (#1259, #1274), so a read could still be writing
credits.json after the process that owns the profile had closed.

tui3.Run now wraps ReadCredits in an owner that cancels every read in
flight and waits for it before Run returns, and refuses a read that starts
after close. Both local launch roads go through it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@santoshkumarradha

Copy link
Copy Markdown
Member Author

@AbirAbbas thanks for the dev merge (99ec179ab). To keep this reviewable, this PR is now frozen:

AbirAbbas and others added 9 commits September 24, 2026 20:02
…eview

The step cap was checked before the store's own ending was read, so a worker
whose last allowed command was its own `plandb done` (or `plandb wait`) came
home with "stopped at its step cap" while the store said done. The supervisor
then read that as a failure, tried to fail a finished task, and never seated
the review round the leaf was owed.

The worker now reads the store's ending first when the cap trips, and reads it
once more after the turn drains before it names the cap, because the command's
store write can land after its end event. Work still open at the cap stops
there exactly as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…file is absent

A cloned repository can commit a link, and codeaf followed every one it met
while reading skills. A `SKILL.md` linked to `/dev/tty` made `codeaf chat` read
the person's own keystrokes as a skill at launch, a blank screen until ctrl+d;
a `.claude/settings.json` linked the same way did it to anyone with a Claude
Code plugin registry; a pipe blocked in open; a link to `/dev/zero` was read
until memory ran out, because the plugin and settings JSON had no size cap.

Every reader of those files now goes through one opener in internal/skills:
it refuses anything that is not a regular file both before the open and on
the opened descriptor, opens without blocking on unix, and reads through a cap
(a SKILL.md's 64 KiB head; plugin and settings JSON whole or not at all above
1 MiB). A refused SKILL.md is skipped with `SKILL.md is not a regular file`.
The resident's digest and copy, the folder row's own read and the plugin
registry, manifest, catalog and settings readers all use it.

The /skill picker no longer scans the disk on the update loop. The scan runs
beside the ordered door line, the list opens at once on the shelf and the last
scan, and the folders arrive when it answers; enter on a folder row reads only
that folder's own SKILL.md, so the attach keeps its place in the line.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`task.max_load` (1.5 per core) and `task.min_free_mb` (1536 MiB) are on out of
the box and the manual promises them on every road, but the run engine never
asked: its only bound was `task.parallel`, 0 by default, so every ready worker
of a `/task` or a `codeaf do` started at once however busy the machine was.

The supervisor now consults an admission gate before every start — the root's
first seat, ready leaves, parked tasks and woken parents — built on the same
governor and the same process-wide lane account the node road uses, so run and
node workers are reserved for together. A lane is taken once the worker exists
and handed back on every road a worker returns by. Both doors wire it: the chat
from the conversation's own rows and account (the graph's when the door handed
none), `codeaf do` from the profile.

A refused start is shown for what it is. Each pass reports the set of tasks the
gate refused, and only those: the run's rail row reads `waiting · machine busy`
while the set is not empty, a held part or an unstarted root reads `queued ·
machine busy` on the plan page, and the word goes as soon as nothing is held —
a held part the person cancels included. The do-door test fixture turns both
rows off, because a scripted run is not a measurement of the box running it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… repository

On the default road `codeaf do` opened its plan store at `<dir>/.codeaf/`
and never removed it: `plandb.db`, the worker's plandb shim and every task's
transcript of commands and their output sat untracked in the person's
repository, one `git add -A` away from being published. The older road never
did this; it keeps a private home under the state root's `runs/`.

The run road now does the same. Each invocation opens its store in its own
0700 folder under `runs/` (or `CODEAF_HOME/runs/`), and everything the run
writes — shim, transcripts, trajectories — lives beside that store. The older
road's rule decides what survives: a done run removes the folder unless
`--keep` or debug mode asked for it, anything else keeps it, and a kept folder
is the last line on the error stream as `record kept at <folder>`.

The directory is checked before the record is opened: a `--dir` that names a
file is refused with exit 1 and opens nothing, and a missing one is created,
as the store's own directory creation used to create it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The pages now quote the run road's 300-millisecond re-ask and the node road's
5 seconds, and the 64 KiB and 1 MiB caps a skill scan reads through. Each is
read out of the constant that owns it, unit included, so changing one without
the page goes red.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
One entry for the four fixes, and 1411's line about an interrupted `codeaf do`
store being set aside beside the next one, which is no longer how a `do` run
keeps its record.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On CI the temporary folder is long enough that the refusal wraps, and the
surface broke it at the hyphen in `codeaf-ci`, so the flattened screen read
`codeaf- ci` and the sentence was not found. The screen and the sentence are
now compared with every space and line break taken out of both; what is
asserted is still the one refusal line naming the folder.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e really do

The owner's rulings on #1410 (2026-09-24), written where a person looks:

- A commit a task lands on the default worker harness carries the bare
  `Assisted-by: CodeAF` line: a run's record names no model. Only the older
  node belt's landing names the model the task ran on. permissions.md said
  every task landing named its model, and the 1412 entry promised it.
- A /task started after the conversation's dollar limit is spent is not
  refused before it starts; its first worker makes one paid call and the
  limit then ends the run.
- Signing is on by default and has no off. A person whose profile or shell
  still turns the retired attribution row off is told once, in the words
  quoted on the page, and only the model's name can still be turned off.
- A message that carries a picture carries no skills, the attached ones
  included; the attachment stays on for the next text message.

Probes for each ruling are in the chat manual's question table. No behaviour
changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The default run road now asks the machine before every worker, and on a busy
machine `codeaf do` waited in silence until --timeout, then left 124
`deadline` with nothing started and nothing saying why.

The first start the gate refuses now prints one line on stderr in the
rail's own words, with the settings row that held it:

  waiting · machine busy · available memory under task.min_free_mb 1536 MiB

The first start after it prints `starting · the machine has room again`.
Neither repeats while the gate is re-asked each pass. A --timeout that
arrives with nothing started keeps `stop: "deadline"` and exit 124, and
`--json` carries the held line in `blocked_on`, followed by
` · nothing started before --timeout`; stderr does not call it a question.

The governor records which ceiling its last refusal met, and
`session.RunAdmission.HeldBy` answers it; `session.MachineBusy` is the one
spelling of the word. The terminal page, tasks.md, HEADLESS.md (including the
124 row the run road leaves the wall on) and the review-fixes entry say so.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@AbirAbbas

Copy link
Copy Markdown
Collaborator

I updated the description. Two lines claimed more than the branch does:

  • Model name in commits. It said the model name in commits could be switched on and off everywhere. A task landed on the worker harness (the default belt) always carries the bare Assisted-by: CodeAF.
  • Interrupted runs. It said interrupted work "can be carried on". Nothing wires that today: an interrupted run is kept and readable, and a new task starts its own run.

I also added a Review fixes (2026-09-24) section listing what landed on santos/dev2 since review:

CI is green on 41a57e164. The rest of Santosh's text is unchanged.

@santoshkumarradha

Copy link
Copy Markdown
Member Author

@AbirAbbas this is ready for your review. dev is fully merged in (including #1440), there are no conflicts, and CI is green. GitHub is only waiting on your approval.

Next in line once this lands: #1485 (one task page). It's green on a full make check and CI, and gets retargeted to dev as its own small PR.

@AbirAbbas AbirAbbas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified end to end on 41a57e1: the four review blockers are fixed in the real binary on both launch roads, #1410's main flows, Ara's Home/tips/Sessions wave and #1440 all pass by hand, and the tagged TUI suite shows no subtest that passes on dev and fails here. CI green. Merging.

@AbirAbbas
AbirAbbas merged commit 5256d70 into dev Sep 25, 2026
7 checks passed
@AbirAbbas
AbirAbbas deleted the santos/dev2 branch September 25, 2026 02:20
ZeroPoint95 added a commit that referenced this pull request Sep 25, 2026
… into senior-dev

Resolved against dev's run road: the start lock and join-or-wait now carry the
program road (a program never joins a run, and nothing joins a program's run),
dev's set-aside ends an abandoned program run in its own words first, a closed
conversation leaves an ordinary run interrupted while a program's run is ended
and its folder finished on its branch, commits carry dev's gitSignature, the
task page takes dev's trail-and-facts head with the program's pinned line in
the facts row, and the prefix waivers sit on the merged measurement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants