feat(bin): add trusted carbon peer relay to the primary firstmate - #8
Closed
morris2spears wants to merge 5 commits into
Closed
feat(bin): add trusted carbon peer relay to the primary firstmate#8morris2spears wants to merge 5 commits into
morris2spears wants to merge 5 commits into
Conversation
Owner
Author
|
closed. claude on carbon will raise issues on repos that firsmate on mirage will tackle. no further action needed. |
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.
Intent
The captain wants trusted inbound relay from the concrete carbon Claude Code orchestrator session to the live primary Firstmate on mirage, using the existing SSH fleet-key trust boundary and the established durable external-channel pattern. A carbon-side client must capture its exact originating tmux pane, stable window and session identity, hostname, and timestamp; SSH the raw request into the primary home; durably record private request metadata, message, and pending/resolved delivery state; surface ids only through an authenticated check wake and durable wake queue; let a new agent-only fmpeer-respond skill act with the same authority as direct captain input; and return a concise response over ssh carbon to that exact pane via one literal tmux send-keys followed by a separate Enter, resolving only on confirmed delivery and refusing blind retries after uncertainty. Keep this pass carbon-focused without a general peer registry or new pairing-token authentication, do not alter X or Telegram mode behavior, document activation and mechanics proportionately, add real mocked regression coverage for receive, wake integration, and reply command shape, and leave actual carbon deployment and Telegram completion notification to Firstmate after the green PR.
What Changed
bin/fm-peer-relay-tell.sh) that captures the originating tmux pane, window/session identity, hostname and timestamp and SSHes the raw request into the primary home, wherebin/fm-peer-relay-receive.shdurably records private request metadata, message and pending/resolved state (bounded ingest read and message cap) and wakes the watcher.bin/fm-peer-relay-poll.shto surface ids only via authenticatedpeer-relay-requestcheck wakes (plus apeer-relay-errorwake for stranded offers) with bounded re-offer and retention pruning,bin/fm-peer-relay-reply.shto inspect a request and send a reply back over ssh carbon to that exact pane as one literaltmux send-keysfollowed by a separate Enter - resolving only on confirmed delivery and refusing retries after uncertainty - and shared helpers inbin/fm-peer-relay-lib.sh, wired into bootstrap, session start and supervision.fmpeer-respondskill,docs/peer-relay.mdplus activation/tunable notes in AGENTS.md and the architecture, configuration, scripts and turnend-guard docs, and 13 mocked regression cases intests/fm-peer-relay.test.shcovering receive, poll, wake integration, reply command shape and delivery uncertainty. X and Telegram mode behavior is untouched.Note: the one failing case in
tests/fm-session-start.test.sh(lock concurrency) reproduces on the base commit and is pre-existing, not a regression from this branch.Risk Assessment
✅ Low: This round changes only AGENTS.md, the fmpeer-respond skill, and two docs to route the already-implemented peer-relay-error wake and document the retention tunable, matching the established X/Telegram routing pattern with no executable code touched and every earlier accepted fix verified in source.
Testing
Ran the new peer-relay regression suite (all 13 cases green) plus the touched adjacent suites, then proved the intent end-to-end outside of unit tests: a real tmux pane acting as the carbon orchestrator sent a captain message through the client, the mirage receiver stored a private 0600 durable record, the authenticated watcher surfaced only the request id into the durable wake queue with no body leakage, and the reply came back over the ssh-carbon leg as one literal send-keys plus a separate Enter into that exact pane, flipping the record from pending to resolved and refusing a second blind send. Evidence is a CLI/terminal transcript and a tmux pane capture rather than a screenshot because the changed surface is shell tooling and a terminal pane, with no rendered UI.
Evidence: End-to-end carbon peer relay transcript (client send → durable record → wake queue → reply into exact pane → resolved → retry refused)
Evidence: Carbon tmux pane capture showing the delivered reply
└─$ PATH=... fm-peer-relay-tell.sh 'firstmate: what is the status of the carbon relay?' ... client-exit=0 └─$ Captain, the carbon relay is live: your message arrived on mirage as request peer-1785607622-gQMPl4 and this reply came back to pane %0.Evidence: Mirage-side durable state after delivery
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 5 issues found → auto-fixed (2) ✅
bin/fm-peer-relay-poll.sh:48- The peer poll silently skips a request whose offer marker is not a valid private artifact (line 48-50) and also swallows publish failures (lines 44 and 54) with a barecontinue. The established sibling channel, bin/fm-tg-poll.sh:127, treats exactly this state as tampering and surfaces it once viaclaim-error. Here the request staysstate=pendingforever, never re-offers, and no diagnostic reaches the captain - contradicting the fmpeer-respond claim that the bounded offer window prevents a stranded message. Reachable path: any leftover/tamperedstate/peer-relay/offered/<id>with the wrong mode, or a transient failure inside fmx_private_artifact_publish_stdin during the re-offer, permanently silences that captain request. Recommend mirroring the tg poll's error-surfacing so a stuck relay is visible rather than silent.bin/fm-peer-relay-receive.sh:125-cat > "$STAGE/message"writes the entire SSH stream to disk before the 1..65536-byte cap is checked at line 132, so a malformed or buggy client call (e.g. piping a large file into --stdin bypassed, or a direct receive invocation) can write unbounded data into the primary home's state directory before rejection. Bounding the read (e.g.head -c 65537) enforces the documented cap at ingest.bin/fm-peer-relay-poll.sh:26- Nothing ever prunesstate/peer-relay/requests/<id>/. Resolved and delivery-uncertain records keep the raw message and reply bodies indefinitely, and every poll cycle re-walks and re-stats all of them (4+ stat calls each via fmpeer_request_dir_valid). Telegram mode prunes its stale offer markers; the peer relay has no equivalent retention step, so cost and stored private text grow without bound.bin/fm-peer-relay-receive.sh:160- Removing the sharedstate/.last-checkmarker makes every registered check due on the next watcher tick, not only the peer poll, so each inbound peer message also triggers an early merged-PR/declined-PR gh sweep. It is bounded to one extra sweep per message and is documented in the surrounding comment; noting the wider blast radius of the wake mechanism only.bin/fm-peer-relay-reply.sh:90- The default remote client is the absolute, user-specific path/Users/morris/.local/bin/fm-peer-relay-tell.sh, while docs/peer-relay.md describes the install location as~/.local/bin/.... It is overridable via FMPEER_REMOTE_CLIENT and asserted verbatim in tests, so this is a deliberate pin rather than a defect, but it silently breaks if the carbon account home ever differs.🔧 Fix: surface stranded peer offers, bound relay retention and ingest
3 issues (1 warning, 2 infos) still open:
AGENTS.md:501- The fix adds a new check-wake payloadpeer-relay-error <message>(bin/fm-peer-relay-poll.sh:40) but no instruction surface routes it. AGENTS.md:501 and .agents/skills/fmpeer-respond/SKILL.md:5,15 still name onlypeer-relay-request <id> ..., while both siblings explicitly route their error variant (AGENTS.md:499x-mode-error ...-> fmx-respond, AGENTS.md:500tg-mode-error ...-> fmtg-respond). Concrete path: a tampered or wrong-modestate/peer-relay/offered/<id>makes the poll emitpeer-relay-error cannot record peer relay offeronce, then emit_error_once deduplicates it forever; with no skill trigger and no handling step in fmpeer-respond's Failure and recovery section, that single wake can be read past and the captain's request stays pending and unsurfaced - the exact stranding the fix was accepted to eliminate. docs/peer-relay.md:54 also still asserts the pollemits only peer-relay-request <id> [<id>...], contradicting the new line 57.docs/configuration.md:475-FMPEER_RETENTION_SECSis described in docs/peer-relay.md:61 but is absent from the environment tunables list in docs/configuration.md, where its siblingFMPEER_REOFFER_SECS=1800was added at line 475. An operator scanning that list sees the re-offer knob but not the retention knob.bin/fm-peer-relay-poll.sh:19- fmpeer_retention_prune runs only from the poll, which exits at line 19 when the relay is not enabled, and bootstrap's opt-out path removes only the check/trust artifacts. Removing config/peer-relay-carbon therefore freezes state/peer-relay/ - including raw captain request and reply text - with no remaining pruner. This matches the existing Telegram opt-out convention (bin/fm-bootstrap.sh tg_mode_setup leaves state/tg-offered behind), so noting the tradeoff rather than a defect.🔧 Fix: route peer-relay-error wakes and document retention knob
✅ Re-checked - no issues remain.
tests/fm-session-start.test.sh:681- tests/fm-session-start.test.sh case "concurrent session-lock acquisition admits exactly one live harness" fails on this machine (0 winners out of 40 concurrent fm-lock.sh acquirers). Reproduced identically on the base commit e645d1e with a clean archive checkout, so it is a pre-existing environment/flakiness issue in the macOS lock concurrency test, not a regression from this change. Every other case in that file passes../bin/fm-test-run.sh tests/fm-peer-relay.test.sh- all 13 peer-relay cases pass (receive, poll, wake integration, reply command shape, uncertainty/no-retry)./bin/fm-test-run.sh tests/fm-bootstrap.test.sh tests/fm-session-start.test.sh tests/fm-supervision-instructions.test.sh tests/fm-documentation-audiences.test.sh tests/fm-x-mode.test.sh tests/fm-tg-mode.test.sh tests/fm-test-run.test.sh- 6/7 pass; session-start lock-concurrency case failsBase-commit control run:git archive e645d1einto a temp dir, then./bin/fm-test-run.sh tests/fm-session-start.test.sh- same failure, confirming it is pre-existingManual end-to-end relay on a private tmux server (tmux -L fmpeer-demo): sentbin/fm-peer-relay-tell.sh 'firstmate: what is the status of the carbon relay?'from inside real pane %0 with stubbedhostname/sshbridging to a mirage-side FM_HOMEbin/fm-peer-relay-reply.sh inspect <id>on mirage showing origin_host/pane_id/session_name/window_id/client_epoch/received_epoch and state=pendingbin/fm-watch.sh(bounded) on the mirage home - emittedpeer-relay-request <id>only, with the same ids-only line persisted instate/.wake-queuebin/fm-peer-relay-reply.sh send <id> --text-file …over the ssh-carbon leg, thentmux capture-paneon pane %0 to confirm literal reply text + separate Enter landedRepeatsendafter resolution - refused withpeer relay request is resolved; send is allowed only while pending(exit 1)README.md:52- README.md was intentionally left untouched: it introduces user-facing product features (optional X and Telegram modes), while the carbon peer relay is a captain-machine-specific operator channel whose activation and mechanics are owned by docs/peer-relay.md and docs/configuration.md. The doc-audience check requires no README routing for it. Flagging as a judgment call in case a README mention is wanted.🔧 **Lint** - 1 issue found → auto-fixed ✅
🔧 Fix: no lint changes needed; shellcheck run clean
✅ Re-checked - no issues remain.
✅ **Push** - passed
✅ No issues found.