Skip to content

The stub carries the fragment CLI, and its agents ask each other - #778

Merged
futurepaul merged 14 commits into
masterfrom
claude/stub-asks
Oct 31, 2026
Merged

futurepaul merged 14 commits into
masterfrom
claude/stub-asks

Conversation

@futurepaul

@futurepaul futurepaul commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Step 3's groundwork (Paul and the coordinator chose option A, 2026-10-30): the stub image carries the fragment CLI, and its scripted agents ask each other the way Hermes' fragment_ask does, so the local lanes test an ask end to end on the real CLI path. It stacks after #763, and the threads PR stacks on it.

What

  • images/stub/Dockerfile builds the CLI from exactly the CLI's inputs, as our Hermes image's cli stage does, but dependencies first and unoptimized (below). A change to the cell, the shell, the e2e or the docs leaves it cached. xtask's guard the_cli_stage_copies_what_the_cli_builds_from now reads both Dockerfiles, each in its own form.
  • The stub's build context is now the repo root, as Hermes' already was, cut down by the root .dockerignore. That changes it in cell/wrangler.jsonc, ci.yml's stub prebuild, images.yml and docker.rs. images/.dockerignore goes, since nothing builds from images/ any more.
  • The script runtime gains ask <agent> <words>: it runs fragment --json ask --return-to <this chat> --id ask-<turn> -- <agent> <words> as the agent acting for its owner (FRAGMENT_AS_AGENT, FRAGMENT_FOR, plus the guest's own FRAGMENT_API). It replies asked <name> or ask refused: <why>.
  • The computers lane: the lead asks its second agent. The question lands in their pair chat with return_to set to this chat, it's answered there, and the answer comes back as the lead's own turn.

Cost (measured)

  • Image: 20.6 MB → 43.8 MB (as docker image ls says). The CLI is built unoptimized (a 17 MB binary): the stub's agents only make a few calls with it, and it builds in a third of the time.
  • The stub's CLI stage builds its dependencies as a layer of their own, from the manifests and the lock alone (our crates as empty sources). A change to our own crates (cli/, crates/core, crates/proto, …) rebuilds only them, and CI's BuildKit cache (scope e2e-stub, mode=max, saved on master's pushes) keeps the dependency layer until a dependency changes. Hermes' stage is untouched, so its image doesn't change.
  • CI, shard 1's stub prebuild, which runs before the Rust build:
stub prebuild how
before (no CLI), bridge rebuilt 1 m 47 s #762's run
first version (optimized CLI, one layer), all cold 4 m 30 s this PR's first run
now, all cold (bridge, CLI deps, our crates) 3 m 16 s this run: deps 104 s and our crates 36 s, beside the bridge's 182 s
now, only our crates changed (deps cached) ~36 s of CLI, hidden behind the bridge when it rebuilds too our-crates layer on CI
nothing the CLI builds from changed cache hit, seconds
  • So for the common PR that touches crates/core or crates/proto, the extra cost goes from about 2 m 45 s to about 36 s, and to nothing when the bridge rebuilds anyway. "All cold" happens only until master's next push saves the dependency layer, and again when Cargo.lock changes.
  • Local (32 cores): the stage cold takes 21 s (deps 10.7 s, ours 10.0 s); after a change to core, 14 s.

Tests: computers lane: 238 passed, 0 failed locally. xtask's guard covers both stages.

Complexity ledger: one Dockerfile stage (the CLI's inputs, guarded; dependencies first); one script rule (~35 lines); the context moved in four places and one .dockerignore removed; the guard reads both images' stages. No platform change.

🤖 Generated with Claude Code

@alexlwn123 alexlwn123 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.

Pass for this stack layer at 4194934e61d2df8dda17d6443f76226f3a692cfd, against #763 at 14f27912e3fb5685b28c220e32245eb5412e5f76.

The stub now exercises agent-to-agent asks through the real CLI. The build-context changes cover the build callers, and the invocation preserves agent/owner identity, a deterministic post ID, and the originating chat for the answer. The new lane checks the question, target reply, and returned turn. I found no blocking regression; the reused CLI stage and extended dependency guard are proportionate to the change.

Validation: the focused xtask Dockerfile dependency guard passes locally; Linux CI's images check passed. Local image workspace tests could not compile on macOS because unchanged SimpleX code uses Linux-only libc::prctl/PR_SET_PDEATHSIG. Docker and end-to-end tests were not run locally; those CI jobs and the main check remain pending. The referenced external engineering-style file was unavailable.

@alexlwn123 alexlwn123 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.

Pass for this stack layer at e2e0c7ddf06efa5b1c0135e7d764252380a15601, against #763 at 14f27912e3fb5685b28c220e32245eb5412e5f76.

The previous head passed with no blockers. This rereview covers the new dependency-first stub CLI build and its updated guard. The dependency layer preserves the manifests and lock; the final step refreshes the real sources and template build script before rebuilding. I found no blocking regression. The extra build step is proportionate to the caching goal.

Validation: the focused xtask Dockerfile guard passed. The actual linux/amd64 CLI stage built successfully, and its binary passed offline smoke checks for --version, new --list (all six embedded templates), and ask --help. CI's check and images check are green. Full Docker and e2e suites were not run locally and their CI jobs remain pending. The external engineering-style file was unavailable.

Non-blocking: the PR description and docs/computers.md still describe identical Hermes/stub CLI stages and the old CLI size; update those claims to reflect this head's unoptimized dependency-first stub stage.

@alexlwn123 alexlwn123 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.

Pass for this stack layer at 1b14f3cc0c5bbfc46d4eeb0c88b4e8a9a158935d, against #763 at 14f27912e3fb5685b28c220e32245eb5412e5f76.

The previous head passed with no blockers. This head changes only docs/computers.md, resolving the prior non-blocking note: it now describes the dependency-first, unoptimized stub CLI build and updated binary size. The PR description has also been corrected. The wording matches images/stub/Dockerfile; no implementation or additional complexity was introduced, and I found no blocking regression.

Validation: reviewed the exact head delta and Dockerfile; git diff --check passed. Runtime tests were not repeated for this documentation-only update. Current-head CI remains pending. The external engineering-style file is unavailable.

futurepaul and others added 7 commits October 30, 2026 20:49
Several agents, one UI for any number (Paul, 2026-10-30): each chat's
row is two lines, its agent first (its face, a group's stacked; its name;
its role's tag; what it is doing there, else when), then the chat's own
name. "New chat with [agent]" names the open chat's agent, else the main
one; with more than one agent its chip lists them all, the pick for that
chat alone. The launcher's start row follows the same rule, with a pick
beside it. The launcher's button is a search and its key, beside the
brand. The main agent's pill and its menu go: what it is doing is on
its chats' rows, its profile and screen in a chat's ⋯, its name and
picture in Settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Chat rows now say what their agent is doing, so a row whose agent
finished its work while the list changed is rightly drawn again; every
row that still says what it said stays the same element.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stub image builds the fragment CLI by our Hermes image's own stage
(cached by the same ids; xtask's guard reads both), its context now the
repo's root as Hermes' is. Its script runtime's `ask <agent> <words>`
runs `fragment ask --return-to <this chat>` as the agent acting for its
owner, as Hermes' fragment_ask does, so the local lanes test an ask end
to end on the real CLI path: the computers lane's lead asks its second
agent, the question in their pair chat, its answer back as the lead's
own turn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Settings' Agents adds an agent with a name and a role, made as the
first run makes its agent (one shared `makeAgent`): its own chat opens
at once with the making's steps, and it says hello first. Its job names
no role; its role is its fragment.json's meta.role, which its runtime
tells it. Each agent's row has a Role field, written and put live as its
name is. Add is offered while the computer runs fewer than 16 agents.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stub's CLI stage builds its dependencies first, from the manifests
and the lock alone (our crates empty sources), so a change to the CLI,
core or proto rebuilds only our crates; its target is the layers' own, so
CI's BuildKit cache keeps the dependencies' build. Unoptimized (the
stub's agents make a few calls with it): a third of the build time, a
binary of 17 MB. xtask's guard reads its dependency-first form.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add kept its name and role in memory alone, and made its chat before its
agent, so a reload in between left a chat nothing tied to them (#763
review). Add now makes its agent first, its title, job, tier and role
written, then its chat: once its chat exists, all Add was asked for is on
the platform. A page's start (resumeFirstRun, once no first run is owed)
finds one of their chats, <label>-chat, with no message yet, whose agent
<label> is not in it, and makes it on from there; in it but quiet, its
hello is posted again (the same record). Cut before its chat, Add again
with that name makes on the agent it made.

cargo xtask check runs the repo's *.test.mjs on the pinned Node's own
runner; cell/shell-tests/onboarding.test.mjs cuts each step, reloads, and
checks one agent with its role in one chat (all seven reload cases failed
before this change).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@alexlwn123 alexlwn123 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.

Pass for this stack layer at bc94bb0afbeb581d8dcb1379513b7814e68e7fbd, against #763 at 89f91cd6fd51ab743f756541deda29e2e0480ceb.

The previous head passed with no blockers. Git range-diff confirms all three commits retain identical patches after the rebase. I checked the updated base's interaction with the stub build contexts, CLI inputs, scripted ask path and computers lane; I found no blocking regression. The dependency-first CLI stage remains proportionate to the caching goal, with no additional machinery in this revision.

Validation: the focused xtask test the_cli_stage_copies_what_the_cli_builds_from and git diff --check passed on this head. Current-head CI is queued/running. Docker and full e2e suites were not repeated locally for this rebase. The external engineering-style file is unavailable.

futurepaul and others added 2 commits October 30, 2026 20:52
Two chats of one label (a create whose answer was lost made the second):
the agent in the one is made, and the quiet other is no Add to finish.
The quiet-chat test now holds a page's writes to the hello's replay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@alexlwn123 alexlwn123 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.

Pass for this stack layer at 6feb34f2b43f494475164bf3f4827dd3eef6b63b, against #763 at 278e52289a19613bdefda253f8d531500f5c3194.

The previous head passed with no blockers. This merge brings in only the base’s onboarding recovery fix and tests; the layer’s diff against its updated base is byte-for-byte identical to the previously approved diff. I checked the merge delta and its interaction with the stub CLI build and scripted ask lane, and found no blocking regression. No additional implementation machinery or complexity is introduced by this revision.

Validation: the focused xtask test the_cli_stage_copies_what_the_cli_builds_from and git diff --check passed on this head. Current-head CI is pending. Docker and full e2e suites were not repeated locally for this base merge. The external engineering-style file is unavailable.

futurepaul and others added 3 commits October 30, 2026 21:24
Settings' Agents adds an agent with a name and a role, made as the
first run makes its agent (one shared `makeAgent`): its own chat opens
at once with the making's steps, and it says hello first. Its job names
no role; its role is its fragment.json's meta.role, which its runtime
tells it. Each agent's row has a Role field, written and put live as its
name is. Add is offered while the computer runs fewer than 16 agents.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add kept its name and role in memory alone, and made its chat before its
agent, so a reload in between left a chat nothing tied to them (#763
review). Add now makes its agent first, its title, job, tier and role
written, then its chat: once its chat exists, all Add was asked for is on
the platform. A page's start (resumeFirstRun, once no first run is owed)
finds one of their chats, <label>-chat, with no message yet, whose agent
<label> is not in it, and makes it on from there; in it but quiet, its
hello is posted again (the same record). Cut before its chat, Add again
with that name makes on the agent it made.

cargo xtask check runs the repo's *.test.mjs on the pinned Node's own
runner; cell/shell-tests/onboarding.test.mjs cuts each step, reloads, and
checks one agent with its role in one chat (all seven reload cases failed
before this change).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two chats of one label (a create whose answer was lost made the second):
the agent in the one is made, and the quiet other is no Add to finish.
The quiet-chat test now holds a page's writes to the hello's replay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stub's build context moves to the repo's root in the e2e-build action,
where master moved ci.yml's e2e build steps.

@alexlwn123 alexlwn123 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.

Pass for this stack layer at b201eff549c575e6bd883a00bb518cbe50be1210, against #763 at 751f46a731e65fedc8a62fc353133944d5b125ef.

The previous head passed with no blockers. Comparing the old and new layer diffs confirms that the only substantive adjustment is moving the stub's root build context and its explanation from ci.yml into the shared e2e-build action. I checked both action callers and the remaining image build paths; the CLI, scripted ask and lane changes are preserved. I found no blocking regression or additional complexity in this merge.

Validation: the focused xtask test the_cli_stage_copies_what_the_cli_builds_from and git diff --check passed on this head. CI's images check is green; the main check, Docker lane and e2e shards remain pending. Docker and full e2e suites were not repeated locally for this base merge. The external engineering-style file is unavailable.

@alexlwn123 alexlwn123 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.

Pass for this stack layer at edb1daf8bb72e684fdb836abf8a2a4e61871eebb, against #763 at 84190bfad27634a028e02f59e32a2828572f9db1.

The previous head passed with no blockers. Comparing the old and new layer diffs confirms identical patches apart from blob IDs after this base merge. I checked the updated build/test context and its interaction with the stub CLI and scripted ask path; I found no blocking regression. This revision introduces no additional implementation machinery or complexity in the layer.

Validation: the focused xtask test the_cli_stage_copies_what_the_cli_builds_from and git diff --check passed on this head. CI’s images check is green; the main check, Docker lane and e2e shards remain pending. Docker and full e2e suites were not repeated locally for this base merge. The external engineering-style file is unavailable.

Base automatically changed from claude/settings-add-agent to master October 31, 2026 05:29
@futurepaul
futurepaul added this pull request to the merge queue Oct 31, 2026
Merged via the queue into master with commit e4c85c6 Oct 31, 2026
16 checks passed
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.

2 participants