Skip to content

Deliver a remote loop's shed prompt on a channel that can fail - #392

Open
scgopi wants to merge 1 commit into
mainfrom
fix/remote-prompt-delivery
Open

scgopi wants to merge 1 commit into
mainfrom
fix/remote-prompt-delivery

Conversation

@scgopi

@scgopi scgopi commented Sep 20, 2026

Copy link
Copy Markdown
Owner

The bug

A loop on a Codespace booted with its entire brief being a pointer, and the file was not there:

Your complete instructions are in the file at ~/.graphcode/memory/codespace---…/PROMPT.md — read that file first
Read PROMPT.md — Path does not exist

Cause

When a goal overruns the ~1 KB line zmx types into a session, the launch sheds it to PROMPT.md and types a short pointer (#57). For a remote project the file rode remoteDeliveryScript's manifest — one python3 -c carrying the 45 KB CLI shim, the briefing and the wake digest, ~105 KB of base64 in a single argv string (Linux caps one at 128 KiB), ending in || true.

That neutering is correct for everything else in the manifest: a session without its briefing is still a session, and delivery must never block a launch. It is wrong for the prompt, which is the instructions. And #345 made it common — shedding now moves the prompt to a file before it drops the briefing, so far more remote loops launch pointered. Any failure in that one best-effort command produced a live, running agent with nothing to do.

Fix

The prompt gets its own delivery: a small installer carrying one file, un-neutered, &&-chained into the fresh launch inside the create branch.

  • A failed delivery takes the launch with it — the node stays honestly not-running and the next liveness sweep retries, the posture startRemote already takes on a failed dial.
  • It logs prompt-undelivered to the remote dial log, so the failure is diagnosable instead of surfacing only as an agent saying its instructions do not exist.
  • It no longer shares the shim's payload size, and runs only when a launch is actually about to happen.
  • The resume branch is untouched: a resumed conversation needs no prompt.
  • Loops whose prompt fits the typed line pay nothing — no second installer, no extra gate.

Not addressed here: the wake digest still rides the best-effort manifest. A missing memory degrades (the loop wakes without what past passes learned); a missing prompt does not.

Verification

Worktree gate, private DerivedData, literal exit codes:

Step Result
xcodebuild -scheme graphcode build exit=0
xcodebuild -scheme graphcode test exit=0, ** TEST SUCCEEDED **, Test run with 1900 tests in 199 suites passed
xcodebuild -scheme graphcode-cli build exit=0
xcodebuild -scheme graphcoded build exit=0
swiftlint lint 0 errors
swift format lint --recursive --strict exit=0

TDD evidence

RED: xcodebuild test -only-testing:graphcodeTests/RemoteSessionLaunchTests with main's ZmxSessionLauncher.swift and RemoteGraphAccess.swift in place -> exit=65, theBestEffortManifestNeverCarriesThePrompt failed on "files.keys.contains PROMPT.md"

GREEN: xcodebuild -scheme graphcode -destination platform=macOS test -> exit=0, ** TEST SUCCEEDED **, Test run with 1900 tests in 199 suites passed

REGRESSION: full suite plus graphcode-cli and graphcoded builds, swiftlint and swift format lint -> exit=0 on every step, 0 lint errors, the 1897 pre-existing tests all still pass

The other three new tests need API this branch adds, so they cannot run against main at all.

A remote loop whose goal overran the typed command line launched with a
pointer at ~/.graphcode/.../PROMPT.md, while the file itself rode the
same `|| true` installer as the 45 KB CLI shim, the briefing and the wake
digest — ~105 KB of base64 in one argv string. That neutering is right
for everything else in the manifest: a session without its briefing is
still a session. It is wrong for the prompt, which *is* the session's
instructions, and since #345 moved the prompt to a file before dropping
the briefing, far more remote loops take that path. Any failure in that
one command started an agent whose entire brief was a path that wasn't
there, reported as "Read PROMPT.md — Path does not exist".

The prompt now travels alone, in its own small installer, un-neutered and
`&&`-chained into the fresh launch. A delivery that fails takes the run
with it and logs `prompt-undelivered` to the remote dial log, so the node
stays honestly not-running and the next liveness sweep retries, instead
of burning a pass on an agent that cannot read its own goal.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: scgopi <scgopireddy@gmail.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.

1 participant