Skip to content

Wormhole: continue a chat on another computer (pair, sync, take back) - #1888

Draft
AbirAbbas wants to merge 75 commits into
devfrom
abir/wormhole
Draft

AbirAbbas wants to merge 75 commits into
devfrom
abir/wormhole

Conversation

@AbirAbbas

@AbirAbbas AbirAbbas commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

What this is

Project Wormhole: continue a chat on another computer. You pair a second computer with a link (or the existing six-digit code). Its home screen then lists the chats running on your other computers, and "continue here" moves a chat over with its workspace files, git history, saved tool output and task records. One computer holds a chat at a time. Sync goes through the hosted relay at codeaf.agentfield.ai/fabric or your own codeaf relay, and everything is sealed end to end: the relay sees only ciphertext.

This lands the work Sankalp built (first opened as draft #1738) and Ara ported to zeropoint95/wormhole, merged onto current dev. It then fixes what an audit, a code review and hand testing found.

Decisions taken (Abir, 2026-10-21)

  • Rollout: cells (the moving-chat substrate) default on for dev, staging and source builds, off for rc and stable. CODEAF_CELLS=1/0 overrides on every channel.
  • Windows: moving chats is absent, because furrow needs Unix. The commands say so and point to WSL. dev's existing remote access (serve, chat --at, --host, six-digit machine pairing) works there as before.
  • Engine: furrow's source goes back to its own repository (furrow 0.2.0: the workspace codeaf's engine grew into furrow#10, v0.2.0). engine/ is not vendored here. codeaf checks the embedded engine's verbs once per process, and if they are missing, cells are absent with one sentence.
  • Git history travels sealed. Working-tree secret files (.env, key-bearing sources) never enter the store; they move only through the encrypted vault. Committed history moves as the repository is.
  • Size budget raised by the measured cost (PERF.md section added).
  • Hosted relay: deployed by the owner from relay/hosted/DEPLOY.md (staging first). This PR deploys nothing.

What changed beyond the port

  • Kept dev's CI workflows; the branch had deleted them. Kept dev's automations and memory rework, and restored unrelated drift the imported snapshot carried.
  • Moving a chat never loses work. A stale reopen enters continuation instead of overwriting newer history; take-back keeps sealed-but-unuploaded turns and transcript-only replies as a kept branch; forced takes are conditional on the holder and fence shown, in both relays; a displaced window becomes view-only and says so.
  • A home that never paired sends nothing to any relay, and opening the add-device card doesn't change that. CODEAF_SYNC_URL=off stops all traffic, including from clients opened before it was read and from an engine host started with another setting.
  • The first launch after pairing draws before syncing. The approver's device record is written at once. A self-hosted relay serves its own pairing page instead of linking to the hosted one. Terminal link approval uses a.
  • The resident keeps its executor seat. With cells off, shell text containing .cell is not refused and no extra memory file is written.
  • Hosted relay: operator brakes for daily new identities and total stored bytes; mailbox generation fencing in the self-hosted relay too; hermetic Worker tests; a staging-first DEPLOY.md.
  • One change entry replaces seven entries that reused other PRs' numbers. The manual matches the code, and atlas icons go through the glyph vocabulary.
  • A moved chat works where it landed. The model gets a note naming the old and new folders, and file tools map paths from the old folder into the new one, never writing into the old folder.
  • Linux sandbox: the probe now runs the real helper, so on hosts that restrict user namespaces (Ubuntu 23.10+, GitHub runners), work falls back the way policy says. Ordinary work runs unconfined with one notice, and work that must have the network denied is refused.
  • Tests that only need cells to be available say so instead of depending on whichever engine the build staged. The pairing journey fails when any step fails, answers the name prompt, and stops the engines it started.

Validation contract

The contract has 22 items (pairing, devices, revoke, seeing a chat, continue, take back, one winner, quiet homes, secrets, off switches, Windows, shipped engine, CI, size, manual, laws, one entry, no regressions, Worker conformance, bounded cost, deploy runbook, rollout). Each new test names the item it proves.

How it was checked

  • Linux build, vet, GOOS=windows and GOOS=darwin builds; make test-quick, laws, all three manual gates; make size under the new budget.

  • Full suites for every new package and every non-heavy package touched; internal/tui3 and internal/session by focused -run.

  • Relay conformance, real HTTP, local servers: codeaf relay 146 pass / 4 skip; the Cloudflare Worker under wrangler dev 148 pass / 2 skip, twice, zero retries. Worker unit tests 224/224.

  • Hand test of the real binary in two terminals, two homes, a local relay and a live model:

    • A quiet home sent zero requests while opening and closing the add-device card.
    • Link pairing worked with matching check numbers.
    • The other computer listed the chat as running elsewhere, and "continue here" moved it.
    • The transcript and workspace arrived byte-identical, and git history came along.
    • .env arrived only through the vault, and the relay store holds neither the key nor its variable name.
    • Revoke made the relay refuse the removed device.

    The flow defects the first pass found are fixed: a blank first launch, the move not opening, the displaced window still writing, and the moved chat writing to the old folder. A second and third hand pass confirmed it. B's edit lands in B's copy, A's window becomes view-only and offers the move question, and typing over the arrival card reaches the box.

  • TestPairJourney (-tags e2e, real binary, tmux, live model, Go relay): all 13 steps pass on both the online and offline continuation paths, about 1m on a 2m budget.

Test it yourself (two computers)

  1. On both computers, build this branch with the engine: make build FURROW_SOURCE=<furrow checkout of Agent-Field/furrow#10>, or FURROW_ARTIFACT=<a furrow 0.2.0 binary> until v0.2.0 is tagged.
  2. Optional: run your own relay (codeaf relay --listen :8787 --store <dir>) and set CODEAF_SYNC_URL=http://<host>:8787 on both. Unset, the hosted relay is used.
  3. On the new computer, run codeaf pair. On the other, paste the link into home (alt+d) or run codeaf pair approve <token>, compare the four digits, and press a.
  4. Work in a chat on computer A, then on computer B open home (space space) and press alt+m, or pick the row and choose 1 continue here.
  5. Check:
    • B says "Moved from A in Ns".
    • Files, git history and .env are there.
    • A says it only shows the chat now.
    • Asking B what it did gets the right answer, and its edits land in B's copy.
  6. Take the chat back on A the same way. Then /devices, r on B: B is told it was removed.

Before this leaves draft

🤖 Generated with Claude Code

ZeroPoint95 and others added 30 commits October 3, 2026 23:39
Add the pairing, relay, cell engine, executor, handoff and sync machinery,
with the corresponding commands, manual pages and verification.
An OpenTUI (bun) app that maps the PR 1738 two-machine work: machines,
codeaf Go pieces, hosted and self-hosted relay, and the furrow engine,
with draggable boxes, a detail pane per node, and step-through flows for
pairing, continuing a chat, and furrow seal/fork/materialize. Diagram
content lives in src/data.ts; tests check every file path it names.

Run: cd tools/atlas && bun install && bun start. Test: bun test.
Upstream codeaf tracks no binaries; builds come from make build or
GitHub Releases. PR 1738 added this 84.5 MB linux/arm64 ELF by mistake.
`codeaf atlas` opens the two-computer architecture map — pairing, devices,
cells, sync and the furrow engine — as draggable boxes and arrows, built on
the Bubble Tea v2 the other surfaces already use (charm.land/bubbletea/v2),
with no new module dependency. The view is a cell canvas: mouse cell-motion
dragging with the package's own rectangle hit-testing, tab+enter and click for
the detail panes, 1/2/3 or f for the flows, left/right to step, p to play, ?
for the legend, q or ctrl+c to quit through the alternate screen.

The diagram is one typed data file, internal/atlas/data.go, and the view
renders only from it. data_test.go fails the build when a files[].Path no
longer exists or an edge names a node that is not there, so the map cannot
drift from the code silently. The tests drive the model directly: drag moves
a box and re-routes its arrows, tab+enter opens the pane, stepping a flow
highlights its step, play toggles, the legend shows, q quits, and the frame
fits 80x24.

Before the port, every claim in the TypeScript twin's data was checked
against the source. The corrections are mirrored into
tools/atlas/src/data.ts so both versions agree: the four-digit check is the
first two bytes of sha256(pubkey) mod 10000 (uint16_be), the link is approved
from the chat card or `codeaf pair approve` and not a home card, CODEAF_CELLS=0
is the cells off switch, the takeover is run by syncsetup's Continuer.Take
through internal/handoff (not the other way round), the engine repository type
is FurrowRepository, and `furrow fork COMMAND` refuses --json. The hosted
relay's "no recovery key" line, which no code supported, became the documented
"no request log and no account table"; machine A gained the drive-side file
its "publishes each turn" claim rests on; and the furrow-cli summary no longer
overstates --json. `bun test` and `bun run typecheck` still pass.

The command is on the help page inside the existing line cap (the two `codeaf
why` synopsis pairs folded into one), the chat manual gained an atlas page
section, and the change carries an entry in docs/changes/unreleased/.

submitted a change that the project's own build or tests do not pass. senior-dev's model said: The atlas architecture map is now a `codeaf atlas` subcommand (internal/atlas on Bubble Tea v2, one typed data file, nine deterministic Go tests), every claim in the TypeScript twin's data was verified against the source and the corrections mirrored into both files, and the binary builds, draws in a pty and quits cleanly — with the changelog and manual entries the repo's gates demand. senior-dev observed: 1 of the project's 2 build and test commands failed. submitted candidate failed verification (1 failing entrypoint); shipping it anyway as the run's own answer: 95242 bytes across 12 file(s), tree 00bda30096e0
Combine the pairing, executor, memory, relay and atlas changes with the
upstream interfaces, keeping both sets of changes.
/atlas opens the same architecture map `codeaf atlas` draws — the same
internal/atlas model and data, not a copy — as a fullscreen sheet over the
conversation. esc or q closes it and hands the chat back whole, draft
included; the map's own playing flows run on the chat's loop through one
beat message. It is registered in the command table beside /pair and
/devices, documented on the running-from-the-terminal manual page, and
TestAtlasOpensTheMapAndReturnsToTheChat drives it through the real router.

Three merges of upstream dev's chat work needed the same commit:

- chordregistry_test.go still listed standMarkKey, the ctrl+enter marking
  chord dev unbound on purpose (queueing took the chord; the marked door is
  /standing). The row goes with the chord.
- The takeover sentence rode a synchronous open; dev's opens from home now
  land off the loop (homeOpenLater), so the sentence and the setup card
  were being said into the conversation the person was LEAVING. The
  takeover's closing work now rides the open ([app.homeTakenSaid]) and is
  spent at its landing.
- The two-computer pages joining the manual corpus shifted retrieval for
  five of the reachability probes. The asker's own words are now headings
  on the pages that answer them, which is the manual law's own fix.
After a pairing, neither computer had a device record: a device wrote its
own record only at its next chat start (syncsetup.Sync.putDevice), so
codeaf devices said 'nothing is paired yet' on the computer that had just
printed 'Paired.', and after a link pairing only the joiner was on the
directory. Now the same upsert every chat start makes runs when a pairing
finishes: on the side that showed the code, the side that typed it, the
side that approved the link and the side that joined by link
(cmd/codeaf/pair.go, pairlink.go). A device may only ever write its own
record, so the fix builds no record for anyone else: PutOwnDevice is the
one record-building path, exposed minimally from syncsetup and reused.

The pairing itself succeeding is the contract, so a record that did not
land is one line on the terminal (pair.RecordUnsaidLine) and the exit
stays 0 — the next chat start writes it anyway. The upsert is a seam on
pairDoor like the mailbox and joining seams, so one test process can run
two doors against two homes: TestDevicesAfterACodePairingShowsBothComputers
and TestDevicesAfterALinkPairingShowTheApprover drive the real doors
through the in-process relay and assert each side's devices list shows
the other.
Keep the build output outside the tracked source tree.
The command table's every row must have a fate on home (homefate_test.go),
and /atlas joined the table without one. It rides with the commands that
need a conversation first: the map is raised over a conversation's frame,
so home opens one and runs the command against it, the way /manual and
/files do.
…ts first map

internal/atlas grows a Map type (Name, Title, one-line Description, Nodes,
Edges, Flows) and Maps, the ordered registry every entry point reads, with
ByName for lookups. The diagram content moves from the Atlas global into
Pairing, a named map, in internal/atlas/pairing.go — a maps subpackage would
have imported atlas for the types while the registry imported the maps back,
so the data stays in-package. The model, view and frame take a *Map; atlas.Run
opens the first registered map and RunMap opens any named one. The tests hold
every registered map to the tree (files, edges, flows) and keep the names
unique.
…d tab completion

Bare codeaf atlas and bare /atlas now raise a picker over the registry —
one row per map, its description, enter opens the row the cursor is on,
esc/q hands the terminal or the conversation straight back. A name opens
that map in both surfaces; an unknown name refuses with the registry's
own sentence — no map "nope" — naming what is available, non-zero from
the CLI and said in the transcript from the chat. /atlas tab-completes
map names through the same argument-list seam /export and /attach
complete paths through, and codeaf help says atlas [map].
Boxes and the help, detail and flow panels now blank what is under them,
so arrows run under boxes instead of through them and panels are no longer
see-through. Arrow labels are placed after the boxes, at the nearest free
spot on their own arrow, and skipped when none is free. Text is measured in
runes, not bytes, so a line with '—' or '•' no longer runs over the border.
The pairing map is titled Pairing with a short description, so the
pickers read 'pairing  two computers, one chat'.
Both pickers (codeaf atlas and /atlas) now draw rows with one shared
atlas.PickRow: the map name in bold (accent on the cursor row), padded to
the longest name, then its one-line description in the muted tail colour,
the codeaf list shape of a name and a dim tail. The pairing map's full
one-line description is back, without the PR reference.
pidA and holderState read /proc/<pid>/task/<pid>/children and
/proc/<pid>/exe, so on macOS durability-hosted.sh failed with "no process
under pane runs the binary under test". The lookup now lives in two small
helpers, childPids and exeOf: they keep the /proc path on Linux, and where
/proc is absent use pgrep -P for children and ps -o comm= (the full exec
path on macOS) for the executable. Both sides of the comparison are
resolved with filepath.EvalSymlinks.
…urrent furrow

"could not continue this chat here" now carries the take's first error line,
so a failing move can be diagnosed from the screen. The Linux move failures
behind it came from a Mac cross-build embedding the pinned furrow release
(v0.1.0), which predates cells; docs/testing-anywhere.md now says how to hand
a source-built Linux furrow to the build instead.
…findable as soon as its first call is durable

The hosted durability e2e failed its tightest mode: kill the holder 500ms
after a lone call completes, and the other machine could not take the chat —
'handoff: read chat <id>: directory: not found'. The chat's directory record
is created by its first publish, and on a Mac the relay's Disk store made
each of a frame's pointer files durable with its own full disk flush
(flush_other.go: 'one fsync each'). The first publish of a chat carries the
whole workspace closure — a git repository's internals alone are dozens of
objects — so that first publish was 600-700ms behind the call it carried, and
a machine dying inside that window left a completed call no other machine
could find.

Timing against a real relay on this Mac: seal 67ms, export 16ms, one
PutFrame (66KB, 83 objects) 607ms, directory create 2ms. The whole delay was
the relay's per-pointer fsyncs.

Darwin has no syncfs, but it has the same pair of primitives: F_BARRIERFSYNC
writes a file's data to the device, ordered after the writes before it, and
one F_FULLFSYNC flushes the disk's write cache, which commits everything the
barriers wrote. flushFiles on darwin now does one barrier per file and one
final full sync for the batch — the same group commit flush_linux.go already
gives Linux, where syncfs was introduced for exactly this: thousands of
per-fsync journal commits were what made a large frame outlast every client
deadline. A batch of one file keeps its plain full sync, which is the common
case and is fully durable on its own.

Trade-off: the batch's durability rests on the barrier fsyncs writing every
file's data before the final flush, which is what the flags promise; nothing
waits per object any more. The client is untouched: a seal still never waits
on the network, the publish still fires the moment a turn is noted, and the
record is created immediately after the upload it points at, so a chat's
directory record exists no later than the moment its first completed call is
durable on the relay — now about 100ms after the call instead of 700ms.

The first publish's head is observed on the relay ~100ms after the call
finished (was ~700ms); all three kill modes of the hosted durability e2e
(500ms, 2s, 5s) pass.
…r that is not here

A chat taken over from a machine whose project folder is not on this one
was labelled "proj-a (copy here)", which reads as a copy of proj-a being
on this machine — and there is no such folder here. The marker now says
where the project is: "proj-a (copy from another machine)", one const
(session.MovedCopyWord) that the conversation footer (host.go's movedWord),
the home projects panel (world.go's readProject + projectWord) and the
footer under home's cursor (homedraft.go's targetProject, reading the
world scan's gone map and never the disk) all share, so the surfaces
cannot drift into disagreeing about the same chat. A chat back in its own
folder is named by it plainly: the marking follows the recorded folder
being absent, not the chat's history.
It lacked its opening --- fence and used kind: fix where entries say fixed,
so make changelog-check refused it.
Shorter title (under 100 characters) and surface remote, one of the
allowed surfaces; make changelog-check passes.
…a confirmation

The pairing panel took every press and acted on none, so a drag over the
code it shows never selected anything. A press on the panel still answers
nothing (its own law), but it may now arm a sweep (pairdrag.go): a drag
selects and copies the panel's rows — the code, its lines, and the link
card's rows — over the same clipboard road with the same copied · N chars
word, and c while the code is shown copies the code alone; the hint line
names the key.

Replacing a computer's own chats was a flag of the terminal command and
never a keystroke in a chat. It is both now: /pair <code> --replace asks
first, states what is lost, and joins only on an explicit yes; a no or esc
leaves everything untouched, and a home with nothing of its own is joined
without the question. The plain refusal names the in-chat way; the
terminal's --replace behaviour is unchanged.
The approving side prints "<name> (<OS>) wants to pair", with the OS of the
computer that asked. The test pinned "linux", so it passed on Linux CI and
failed on every Mac.
This repository runs no GitHub Actions: builds and releases happen locally
and upstream syncs are merged by hand. .github/.gitignore keeps stray
workflow files out of accidental commits; a sync merge can still reintroduce
tracked workflows, which is deliberate.

build-cross keeps the six-platform list inline; it previously read the
release workflow, which no longer exists. Its windows/amd64 build fails on
main for a pre-existing reason (internal/cellstore uses Unix-only syscalls);
the workflow built Windows on a Windows runner instead.
Brings Sankalp's two-computer work, as ported by Ara, onto current dev:
pairing by link or code, the device list, cells, encrypted sync through a
hosted or self-hosted relay, "continue here", and codeaf atlas.

Kept from dev: every CI workflow (the branch had deleted them), the
automations that replaced standing orders, and the #1830 memory rework.
The standing-order files stay deleted; the one seam they carried, giving
a run's tools the execution seat, now lives in the automation runner.

Restored to dev: changes the imported snapshot carried that were not this
feature (fallback-pin filtering, harness-question publication, skill
import budgets, performance budgets, cancellation polling, a wording
sweep and its new law). Kept from the branch only what the feature needs:
the memory event ledger a moved chat replays, the config writers vault
restore uses, and the execution-context plumbing the executor law demands.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…only with a capable engine

Moving chats needs furrow, which runs on Unix, so on Windows the identity
pairing, device naming, rotation and every move door are absent and the
explicit commands say to use WSL. dev's own remote access (serve, chat
--at, --host, the six-digit machine pairing) keeps working there.

Cells now default on for dev, staging and source builds and off for rc
and stable; CODEAF_CELLS=1 or 0 overrides. Where cells are off the doors
say how to turn them on instead of half-running.

An engine without the verbs cells call (export, published, want, import,
rebind, materialize, serve, changed-path sealing) makes cells absent
with one sentence. It is probed once per process from the engine's help,
never from its version string, since a source build also says 0.1.0.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AbirAbbas and others added 30 commits October 21, 2026 19:20
R10/F5, F4 / C5. Include the actual session-layout reader,
active-window directory tracking, pre-submission ownership read,
moved-banner landing and fresh attachment.

Its hunks in internal/syncsetup/drive.go internal/tui3/homepanel_continue.go  ride in the earlier commit that first touched those files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
F1 / C4. The initial local seal remains local until the drive is
ready; tools wait for ownership, and catch-up cannot miss the seal
at the startup boundary.

Its hunks in internal/syncsetup/drive.go internal/cellsync/batch.go  ride in the earlier commit that first touched those files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
F3 / C1. Both doors use BeforeApprove without editing the other
lane's pairlink.go.  The existing enrollment fixture now gives the
device the same persisted name it publishes.

Its hunks in cmd/codeaf/wormhole_contract_test.go  ride in the earlier commit that first touched those files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
F6 / C5. Keep borrowed projects in place, mark new arrivals as copies
even if the origin exists, and rebase only derived metadata when
filing a copy.

Its hunks in internal/syncsetup/take.go cmd/codeaf/synctake.go internal/tui3/home.go  ride in the earlier commit that first touched those files.

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

Its hunks in cmd/codeaf/wormhole_contract_test.go  ride in the earlier commit that first touched those files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
C1/C3/C4/C5. Keep these manual and change-entry hunks with their
corresponding feature commits above if the driver wants each commit
to carry its account.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Item 1 / R5 / C18. Preserve the distinct cancellation lifetimes. The
child regression disables the package fallback before reaching the
real resident shell tools.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Item 2 / R4 / C10. Stage only the existing-engine sync-setting section
in the shared terminal page. Include both the generic fingerprint and
the stricter sync comparison; provider changes retain their former
busy-host behavior.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Item 3 / R11 / C18. Host execution avoids both the filter and the
extra state-directory stat; cell workspaces retain protection.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Item 4 / R12 / C18. Install and bind the portable ledger only for
enabled cell sessions; legacy memory stays in the existing store.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Item 5 / R13 / C1. In pairlink.go stage the approval-key/comment
hunks only; leave the LinkRelay routing hunk for item 6. Stage only
key-choice prose in the shared manual pages. Code pairing retains
yes/no.

Its hunks in internal/manual/chat/running-from-the-terminal.md  ride in the earlier commit that first touched those files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Item 6 / F2 / C1/C10. Stage the resolved-URL invitation and
LinkRelay routing hunks in pairlink.go, the exact local-relay URL
matchers/imports in pairlink_test.go, and the self-hosted-page/manual
refusal hunks. The real relay resolver covers CODEAF_SYNC_URL without a
display flag. The chat intercepts custom links and refuses a different
configured service locally.

Its hunks in cmd/codeaf/pairlink.go internal/manual/chat/add-or-remove-a-computer.md internal/manual/chat/running-from-the-terminal.md cmd/codeaf/pairlink_test.go  ride in the earlier commit that first touched those files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Item 7 / R7 / C14. Stage only the Wormhole size-ratchet section
of PERF.md, with the exact measured increase and unchanged byte
headroom. Integrate this budget with the feature whose measured cost
it pays.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Item 8 / R9 / C19/C22. Stage only the local Worker proof bounds
section of PERF.md. Keep canonical assertions and production Worker
code unchanged. A private Wrangler copy retries only the original
connection-lost transport exception, preserves signed request bytes,
reports each retry, and fails closed on an unknown runtime; a bounded
Go transport controls request load. Keep authorization at normal
mailbox lifetimes and run the unchanged expiry assertion on its own
short-lived fixture; require that expiry passes rather than skips. The
thousand-socket case uses an isolated local runtime with the same
limits, preventing bulk proxy teardown from stalling other cases.

Its hunks in PERF.md  ride in the earlier commit that first touched those files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Item 9 / R15/R16 / C18. The numeric strings keep their current
displayed values; only their source changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
codeaf pair refused before reading its flags, so on a build with cells
off, or where the embedded engine cannot run, even codeaf pair --help
exited 1 with the refusal. pair is on the help page, so help is now
answered and only the pairing itself is refused.

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

The journey wrote each step's verdict and then reported PASS whatever
they said, so a journey with failed and blocked steps read as green. Any
failed or blocked step now fails the test. It also waited for a link on
codeaf.agentfield.ai, but a self-hosted relay now prints its own pairing
page, and the journey runs against a Go relay.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
codeaf pair on a computer that was never named asks for a name first,
filled in with the host name. The journey never answered, so step 2 waited
out its deadline at the prompt. It now presses Enter when asked.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The continuing page said 'relay' in a heading and in the git-history
sentence; the device pages name it the sync service. A self-hosted pairing
test used an all-A key, which the colour law read as #AAAAAA.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The device sheet opens on this device's own row, where r is rightly not
offered, and the journey waited for it there. It now waits for the sheet,
moves to the other computer and expects r remove on that row.

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

Ubuntu 23.10 and later let a user namespace be created but give the process no capabilities in it, so the jail's re-exec of the helper with ambient CAP_SYS_ADMIN was denied (fork/exec /proc/self/exe: permission denied) while the probe, which only ran true, said namespaces worked. Every jailed call failed, ordinary work included. The probe now runs the real helper in a no-op mode with the same attributes. Without the jail, work that must have the network denied is refused with the existing sentence and other work runs unconfined, said once per session.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
cell.Available asks the staged engine, so package tests passed or failed with whichever furrow the build happened to stage (CI staged the pinned v0.1.0, which lacks the exchange verbs). Tests that only need cells available now declare it with celltest.Available; tests that run the engine require a real one with celltest.RequireEngine. FirstRun no longer dereferences an absent sync.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A moved chat's model kept the old computer's absolute paths from its history and wrote there. The next request now carries a note naming the device it came from, the old folder and the new one, and the file tools map an absolute path under the old folder to the same place in the new one, never writing into the old folder even when it exists here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A message typed while the arrival card was up was swallowed by the card. Printable input now reaches the box; enter on an empty box still answers the card.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Approving from a home that never ran codeaf said to run codeaf pair, which joins rather than approves. It now says this device has no identity yet and to start codeaf here once.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The real binary keeps its engine after the window closes, so every
journey run left a daemon per workspace behind (28 after five runs). The
journey now ends every engine whose workspace lies under its homes or
workspaces, moved copies included.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The probe step makes its own home and workspace, so its engine survived
the cleanup that covered the journey's two homes. Every engine under the
test's temporary root is now ended.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
TestNoToolDecodesItsOwnArgumentsWithEncodingJSON holds every tool to
decodeToolArguments. The moved-copy mapper decoded with json.Unmarshal;
it now uses the same door, and still passes arguments that are not one
object on untouched for the tool's own refusal.

Co-Authored-By: Claude Opus 5.5 (1M context) <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.

2 participants