docs(plans): plan offloading the harness to another device - #2364
Merged
jonathanKingston merged 5 commits intoSep 9, 2026
Conversation
jonathanKingston
force-pushed
the
claude/harness-cross-device-offload-o6ejvb
branch
from
September 5, 2026 00:29
00d6b2a to
313acdc
Compare
Contributor
jonathanKingston
force-pushed
the
claude/harness-cross-device-offload-o6ejvb
branch
from
September 5, 2026 02:35
313acdc to
0fe4f22
Compare
jonathanKingston
temporarily deployed
to
github-pages
September 5, 2026 02:37 — with
GitHub Actions
Inactive
Collaborator
Author
|
Audit result: the documentation diff is internally consistent, I would not open another implementation issue yet. The Proposed plan is the decision artifact; if Decisions 7/8 are accepted and work is scheduled, create one implementation tracker then (or convert/link an existing roadmap issue) rather than duplicating the unresolved design discussion now. Keep draft until that decision review is complete. |
jonathanKingston
force-pushed
the
claude/harness-cross-device-offload-o6ejvb
branch
from
September 6, 2026 09:19
0fe4f22 to
97d2f70
Compare
jonathanKingston
force-pushed
the
claude/harness-cross-device-offload-o6ejvb
branch
from
September 6, 2026 10:57
97d2f70 to
766a2e5
Compare
jonathanKingston
marked this pull request as ready for review
September 9, 2026 04:01
Records what the package extraction made possible and what still blocks a run continuing after the desktop disconnects. The runtime is already portable and unused: 17 of 476 non-test files in src/main import electron at runtime and none are on the agent, tool, hook, sandbox or thread-store path; headless-agent-host.ts runs the whole product loop with no renderer; verify-agent-path-import.mts enforces that with electron poisoned; and the Tauri sidecar already runs the main process as plain Node. The only non-test caller of runHeadlessAgent is a benchmark script. The plan's argument is that offloading is an ownership problem rather than a transport one. SSH already carries the tool layer, but the thread store's mutual exclusion is an in-process mutex, not a file lock, so a fenced per-thread writer lease has to come before any worker process. It sets out nine binding decisions and phases O0-O6 with exit gates, and names where it departs from the existing "provider keys never leave the desktop" line. Also corrects two plan statuses that no longer match main: - The headless automation contract module, its published JSON Schema and gen:headless-schema are on main; the doc still said they were only on a feature branch. - Deferred approvals D1 has landed (the defer outcome and its durable append-only queue); the index still listed D0 only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011i4xR3bwms6hEJDdd449qo
main gained library-splits.md, the plan that owns the extraction this one builds on, so state the relationship instead of re-deriving it: - name library-splits.md as the parent, and say this plan is the product capability its client/server split unlocks rather than a second opinion on how the packages are cut - O0 now consumes step 9 (#2312, the versioned API protocol and ShellHost) instead of proposing its own worker entry mechanism; if #2312 lands first, O0 is a packaging step - reconcile the Electron measurement with the count library-splits.md uses: 30 of 476 non-test src/main files name electron, 13 for types only, so 17 import it at runtime Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011i4xR3bwms6hEJDdd449qo
main gained client-server-split.md, which promotes #2312 out of library-splits.md step 9 into its own Active plan with step 1 landed. Follow it: - O0 now consumes that plan rather than the library-splits step. Its step 4 produces copse-core, "a daemon with three front doors: Electron IPC, WebSocket, and the ACP agent server" — that daemon is this plan's worker, so O0 is its first remote consumer, adding only what a remote deployment needs that a local daemon does not: a sandbox-state handshake and the O1 lease - name both split plans as parents, and say this plan settles neither how the packages are cut nor how the protocol is versioned - re-measure against the rebased tree: the denominator moved to 479 non-test src/main files, while 30 named / 13 type-only / 17 runtime still hold Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011i4xR3bwms6hEJDdd449qo
main grew a non-test file in src/main, so the denominator is 480, not 479; 30 named / 13 type-only / 17 runtime are unchanged. Also tighten the "only non-test caller" line: verify-agent-path-import.mts imports runHeadlessAgent without calling it, purely to prove the graph loads under a poisoned electron, so autonomy-regression-agent.mts remains the only caller that actually drives a run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011i4xR3bwms6hEJDdd449qo
thread-in-container.md and src/main/services/container-runtime/ are on main now, and they falsify this plan's central qualification. It said "the runtime is portable and unused"; container-runtime/worker-entry.ts calls runHeadlessAgent inside a guest container, so main-process code drives the portable runtime off the desktop today. Reconciled rather than restated: - status is Proposed (partly overtaken): O0, O3 and O4 are delivered for a disposable local container, and the plan says so at each phase instead of describing them as unbuilt - O4 was delivered more strictly than proposed here — --network none plus a per-origin unix-socket broker is execution-runtime-security R3's broker-only egress, met for that runtime - O1/O2 are the half nothing has built, and are the same work as that plan's T2, which names the same lease mechanism; say so rather than duplicating it - the execution table gains a container column, including that the guest does not need the window but cannot be attached to - where the two disagree, the shipped prototype wins Also re-measure after 197 commits of main: 517 non-test src/main files, with 30 naming electron, 13 for types only, 17 at runtime. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011i4xR3bwms6hEJDdd449qo
jonathanKingston
force-pushed
the
claude/harness-cross-device-offload-o6ejvb
branch
from
September 9, 2026 04:06
766a2e5 to
b6cb073
Compare
jonathanKingston
deleted the
claude/harness-cross-device-offload-o6ejvb
branch
September 9, 2026 22:47
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
docs/plans/cross-device-harness-offload.md, a plan for running the harness on a second machine while the desktop stays in charge and the laptop is free to closethread-in-container.md, which landed the loop-in-guest half while this was openmain, and register the new plan in the indexWhat changed since this was opened
mainmoved 197 commits and merged the container work, which falsified this plan's central qualification. It said "the runtime is portable and unused";src/main/services/container-runtime/worker-entry.tsnow callsrunHeadlessAgentinside a guest container, so main-process code drives the portable runtime off the desktop today. The plan says that instead of the original claim.The honest position is that this plan is partly overtaken:
git pushdeferred--network noneplus a per-origin unix-socket broker isexecution-runtime-security.mdR3's broker-only egress, met for that runtimethread-in-container.mdparks it as T2So the remaining value here is the ownership half. O1/O2 and T2 name the same mechanism (the per-thread writer lease from
acp-session-continuity.md), and should be one piece of work rather than two. Where the two plans disagree, the shipped prototype wins — stated in the document.Why the plan still earns its place
The argument it makes is that offloading is an ownership problem, not a transport one: the thread store's mutual exclusion is an in-process mutex rather than a file lock, so two processes over one workspace have no mutual exclusion at all. A fenced lease therefore comes before any second worker. That is unaddressed on
main, and it is the exit gatethread-in-container.mdsets for T2 ("close the desktop mid-run, reopen, and observe one converged thread").It also records the measurement (30 of 517 non-test
src/mainfiles nameelectron, 13 for types only, so 17 at runtime; none on the agent, tool, hook, sandbox or thread-store path), the execution table including the container column, and nine binding decisions. Two of those now have a shipped prototype agreeing with them: Decision 7 (containment must be proven before unattended) matches the attestation, and Decision 8 (one leased credential in the worker) matches the narrowing ofunattended-runs.mdDecision 3.Boundary with the other plans
library-splits.mddid the extraction that makes the question worth asking.client-server-split.md(#2312) owns the mechanism; step 4'scopse-coredaemon is this plan's worker.thread-in-container.mdowns the runtime, the contained-effect gate, the egress broker and the credential narrowing. It is the senior sibling and landed first.Status corrections
Both verified against the tree, not inferred:
main". The contract module, its published JSON Schema,gen:headless-schema, and the bench consumer are all onmain. Restated as Phase 0 landed.deferral-mode.tsanddeferred-approval-store.tsare onmain. Index aligned to the doc.The index's "Last audited" date is deliberately unchanged: this corrects three rows, it is not a full audit.
Validation
Documentation only; no source, schema, or fixture changes.
main(a288035), no conflictsoxfmt --checkpasses across all 77 files indocs/plans/thread-in-container.mdreferencesci-fullwas green end to end, including all 8 e2e shards andscreenshot-artifacts; CI re-runs on this headReview note
The
ci-fulllabel is still applied. Now that this is out of draft it is only needed to defeat the oracle's docs-only thinning, which zeroes the e2e shards — remove it if you would rather this PR stop running the heavy tier on every push.🤖 Generated with Claude Code
https://claude.ai/code/session_011i4xR3bwms6hEJDdd449qo