Skip to content

feat(fleet): attach-first opencode client helper — forward lifecycle, service discovery, stdin-safe run wrapper #1357

Closed

Description

@dezren39

From the access-pattern benchmark (code#1344; report: usage-billing-hub goal files/opencode-access-benchmark-2026-10-27.md). Decision: programmatic opencode work defaults to ATTACH — a persistent SSH forward to the laptop background service (127.0.0.1:13420) with raw API control + opencode run --server for turns.

Build one small fleet helper (script/library in the pm-stack orbit) that:

  • discovers the laptop service (url + password) from the laptop's service-prod.json via laptop-ssh.sh, provisioning the password into a 0600 local secret file — never argv, never logs;
  • opens/reuses a multiplexed SSH forward (idempotent; health-checks the local port; reopens on death);
  • exposes run/prompt/list operations with the two safety defaults baked in: stdin closed for every opencode run (open-pipe stdin hangs the CLI — separate follow-on) and session location passed in the POST body (the ?directory= query param is silently ignored — separate follow-on);
  • is the single documented entry point stewardship dispatch + sandbox tooling use for opencode work, so the pattern stops being re-improvised per workstream.
    Acceptance: from the sandbox, one command runs a prompt turn against the laptop service end-to-end; killing the forward mid-turn and re-running the helper recovers the view of the still-running session; no secret value appears in any output.

Acceptance criteria

  • One fleet helper exists that discovers the laptop opencode service (url + password) from service-prod.json via laptop-ssh.sh, provisioning the password into a 0600 local secret file — never argv, never logs.
  • The helper opens/reuses a multiplexed SSH forward idempotently, health-checks the local port, and reopens it on death.
  • Its run/prompt/list operations bake in the two safety defaults: stdin closed for every opencode run, and session location passed in the POST body (not ?directory=).

Activity

  1. developing-today commented on Oct 27, 2026

    @developing-today
    Contributor
  2. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    Load-bearing as of 2026-10-27: the attach pattern is now the fleet DEFAULT (benchmark + decision record on #1344; Horizon here raised to Today). The dispatching/supervising jobs have already been switched in their instructions — stewardship-cycle (OPENCODE ACCESS PATTERN block), jules-review (supervision target = laptop server via the forward), orchestration-pass (session answers + dashboard session actions via the laptop server; opencode-sandbox actions rejected as retired). Until this helper lands, those jobs hold one persistent forward per batch and drive the API / run --server by hand — this issue is what makes that cheap and uniform. Note the stdin trap (#1359) in the wrapper: always close or redirect stdin for opencode run.

  3. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    Intake review

    Implements the attach-first decision from the #1344 benchmark report (usage-billing-hub goal, opencode-access-benchmark-2026-10-27.md). Security note: the credential handling in the acceptance criteria (0600 file, no argv/logs) is part of done, not a nicety. Suggested approach: small script/library in the pm-stack orbit, reusing ~/tools/laptop-ssh.sh multiplexing.

    Related: Related: #1344 (benchmark + decision: attach-first); #1359 (stdin hang — workaround baked in here); #1360 (?directory= ignored — body-location default baked in here); #1363 (tailnet evaluation that could later change the transport). Labels normalized by fleet monitor: the issue arrived with only meta/follow-up.

    Still live: checked this run — no merged PR in the recent merged list of this repo implements or resolves this issue, and no closing reference was found; the issue stays open.

    🤖 Agent note · filed

  4. added
    kind/featureNew feature or capability request
    priority/normalOrdinary priority (the default)
    effort/mMedium: expected under 1 day of work
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 27, 2026
  5. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    Scope update (2026-10-27, from the #1363 correction): the route is no longer an SSH forward. The laptop opencode server is published via tailscale serve at https://amd-6.raptor-pumpkinseed.ts.net, and the sandbox reaches it through the documented tailnet proxy route (runtime proxy host on port 3130 — ~/docs/devices/tailscale.md). The helper should therefore wrap: the serve URL + the 3130 proxy env for its HTTP calls (or the equivalent client config), the server password from the laptop's service-prod.json discovery, directory-scope on every call, and stdin closed/redirected for opencode run (#1359). No forward lifecycle to manage — that part of the original scope is gone, which makes this helper smaller than filed.

  6. added
    queue/queuedHas a queued task in the Supabase agent queue
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 28, 2026
  7. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

    • Agent: queue worker (repo-worker-code), lane A
    • Session / ID: queue task 1918 · repo-queue-worker-shift 2026-10-28 10:24 CDT
    • Found via: queue claim
    • Task: Built the attach-first OpenCode client helper and verified every acceptance criterion live against the laptop service (v2.0.30+56590c5, 127.0.0.1:13420).
    • Expectation: done — helper at ~/tools/oc-attach.py (symlink ~/tools/oc-attach), usage doc ~/tools/oc-attach.md

    What exists

    • discover: reads the laptop's service-prod.json via laptop-ssh.sh, provisions {url, password} into ~/tools/secrets.d/opencode-laptop-service.json (dir 700, file 600). Password never printed, never logged, never argv (grep over helper source + all test outputs: absent).
    • forward: dedicated multiplexed SSH ControlMaster (~/.ssh/cm-ocattach@…, pinned host key + tailnet proxy like laptop-ssh.sh), idempotent, health-checked via /api/info, reopened on death. Local port 13421 (the sandbox's 13420 is held by an unrelated wrapper with different credentials — verified 401 with ours).
    • prompt (raw API): session create with location in the POST body (location: {directory} — no ?directory=), POST prompt, wait, print reply. run: opencode run --server <forward> with stdin closed (DEVNULL) and the password only via OPENCODE_SERVER_PASSWORD env; since the v2 CLI has no --directory flag, the session is created via the API first and the CLI attaches with --session. list/health included.

    Live verification (2026-10-28)

    • prompt turn end-to-end from the sandbox: session ses_e7cafc3edffeQQ21O3jivltnkK replied exactly as asked (~7s, model opencode-route/workhorse).
    • run turn end-to-end: exact reply received.
    • Forward killed mid-turn (ssh -O exit during a sleep-40 shell turn): local port dead → next oc-attach list reopened the forward, session ses_e7caf4bb3ffebCob3VTsjdIN3r visible, turn finished with outcome "succeeded" and the exact reply.
    • Note for operators: the laptop's default model route currently picks commandcode/gpt-5.6-terra, which 403s (MODEL_NOT_IN_PLAN) — pass --model opencode-route/workhorse when creating sessions until the laptop default is fixed. Documented in oc-attach.md.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

effort/mMedium: expected under 1 day of workkind/featureNew feature or capability requestmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedmeta/follow-upFollow-up spun out of earlier workpriority/normalOrdinary priority (the default)status:done

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions