Skip to content

Add paired desktop remote access over Iroh - #1170

Merged
AnthonyRonning merged 10 commits into
masterfrom
codex-agent-remote-p2-maple
Oct 20, 2026
Merged

AnthonyRonning merged 10 commits into
masterfrom
codex-agent-remote-p2-maple

Conversation

@AnthonyRonning

@AnthonyRonning AnthonyRonning commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Desktop groups paired computers and their folders alongside local projects in the sidebar and project selectors. Tasks run through Iroh on the selected computer, which retains its files, tools, runs and send receipts. Its local desktop and ACP clients share the same work. This remains a draft for review and trials.

Behavior and boundaries

  • Each local daemon owns its persistent device identity and connections. Remote is off/lazy by default. The remote allowlist covers task, composer, model/reasoning, summary, question and selected integration operations. Account/auth/billing and whole-host administration stay local. ACP stays local.
  • Authenticated OpenSecret Transport V2 registration/discovery/admission uses bounded shared PostgreSQL records and canonical account/project/deployment/kind/identity AEAD/AAD bindings. Valid foreign-row and lookup-column swaps are tested. The service stores no pairing codes, PAKE transcripts or device control grants.
  • A locally opened five-minute window provides eight random Base32 characters and one attempt. Direct PAKE binds device keys and scope; execution confirms first and persists the grant before acknowledgement. Reconciliation only queries an existing grant.
  • Each request/reply has its own bounded QUIC stream, alongside an ordered event stream. Stop/question answers have reserved capacity and native priority. Wire version 4 has typed handshake refusals, base64 image readback and inactivity deadlines. Ordinary request failures do not reset a healthy link. Reconnect queries the original receipt and snapshots without replaying prompts; the desktop retains an uncertain send's ID, text and images in memory. On execution-host restart, an unfinished receipt becomes interrupted: its identity stays reserved, the UI warns that effects may exist, and the task can continue without overwriting a newer draft.
  • Window close preserves remote serving through the macOS Dock or an available Windows/Linux tray. Without a usable tray, Close offers Keep open or Quit Maple. Explicit Quit requests local Stop; confirmed owner absence permits exit, while an unreachable owner offers Keep open / Quit anyway even without a main window; an incompatible leftover daemon has a user-confirmed Stop-and-reopen action. Enabled remote hosts retry transient startup failures; Disable/revoke take precedence over older initialization.
  • Returning to Settings recovers the existing pairing code, remaining time and Cancel without extending its deadline or attempt. Endpoint registration writes are serialized so a background refresh cannot erase a just-opened window's advertisement.
  • A stock Iroh relay admission callback is prepared; infrastructure, DNS, enclave, release and production configuration are not deployed here. Public relays require an explicit unpackaged validation setting.

Desktop navigation

Groups are computer · folder, with globe icons for remote folders; empty folders remain selectable in project menus without occupying the sidebar. Pairing and computer names live in Settings → Remote computers. Names default to the OS hostname and can be renamed on that computer, with changes published through existing discovery metadata. Paired devices learn them on discovery refresh or reconnect; a local nickname overrides the advertised name. Naming does not enable networking, change grants, or change the Iroh wire protocol. Discovery and device selection reveal an eight-box code field; filling it never automatically spends the attempt.

Computers load independently through a shared project/task summary projection. Conversations load on use; each computer retains its draft and live state. Offline groups remain cached. Endpoint-scoped navigation separates identical paths/task IDs, including keyboard navigation and notifications. Task updates stream; a small thirty-second folder refresh discovers projects created elsewhere.

Validation

Full Agent just ci and the full pre-commit hook pass locally on Apple Silicon/macOS 27.0.1: four lint configurations, 271 runtime / 510 desktop / 96 headless tests, plus existing workspace suites. Intentional ignores and backend/SDK/database/crypto checks are recorded in remote-validation.md.

Actual Iroh stream tests stall an upload and leave a download unread while ordinary capacity is full, then verify Stop/question answers complete. They cover 10 MiB image readback, oversized-reply isolation, inactivity deadlines, handshake parsing/refusals and selected real event/request/result wire examples. Final regressions also cover pairing re-entry with an existing controller, transient acknowledgement EOF, interrupted receipt recovery, draft preservation and visible tray Quit recovery. Fresh Local Pro forced-public-relay probes repeated one-attempt pairing, same-window reattachment, a 5.8 MB PNG plus a subsequent request on the same link, live GLM Flash/Bash execution, controller restart with an unread acknowledgement, original-receipt recovery, exactly one file write and revocation. A synthetic unfinished receipt in a stopped disposable execution profile was classified as interrupted at restart, and remote task access recovered. A gated local service proxy confirmed offline startup retry and Disable winning over unfinished initialization. A separate fresh Local relay smoke verified offline naming, both names during pairing, rename propagation, unchanged identities/grants, remote rename refusal, and task access after both daemons restart.

OpenSecret all-feature Clippy and unit tests passed (865 passed / 33 ignored), plus 22 AEAD/database, 2 OAuth and 8 callback tests on disposable PostgreSQL. Expired window reclamation authenticates expiry and uses compare-and-delete so a concurrent replacement survives; the current endpoint's repeated-window guard remains. Capacity errors no longer masquerade as failed authentication.

Earlier isolated native tests covered desktop/ACP continuation, remote Stop and child-process cleanup, window-close/Quit, three computer/project groups, retained drafts, offline recovery and pairing UX. Installed production Maple and Paseo were not changed. At ca4b2bbf, actual Linux/macOS/Windows Agent CI and unsigned macOS/Linux artifact checks passed; this final follow-up requires fresh hosted results. The rebase includes master 339d306e and the merged Windows ACP streaming-test fix (#1174).

Review and release limits

The pinned 1Password CPace implementation is draft-06 Ristretto255/SHA-512, not an RFC/draft-21 claim. Its eleven tests/vectors pass. The 2022 audit does not establish an audit of the exact 2026 pin or Maple. See remote-security.md.

Remaining rollout findings are unused-endpoint lifetime, destructive-reset/idle enrollment-record cleanup, dedicated enrollment request-rate and per-peer validation bounds, and best-effort discovery unpublish on Quit/sign-out. They are recorded explicitly in the validation note. Physical machines on independent networks, sleep/wake, signed macOS permissions/CUA, Windows/Linux tray interaction and the deployed Maple relay/enclave path remain trial/release gates. No merge or deployment is requested.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@AnthonyRonning
AnthonyRonning force-pushed the codex-agent-remote-p2-maple branch from 4ee72f0 to ca4b2bb Compare October 20, 2026 04:34
@AnthonyRonning

Copy link
Copy Markdown
Contributor Author

Reference notes from the Agent local-store research. Neither blocks this PR. Checked against ca4b2bbf.

  1. Window rows: fixed at this head. Earlier heads never purged window enrollment rows. After 64 identities had ever paired, a new pairing would have failed with RemoteEnrollmentCapacity (HTTP 429). This head deletes window rows 24 h after they expire (services/opensecret/src/web/remote/mod.rs:31-33, :224-228), which resolves it.

    What remains is by design: there is no deregistration route (mod.rs:35-58). A computer whose local data is erased stays discoverable and relay-admissible until its 15-minute device lease lapses. The local-store "erase local data" flow will document this.

  2. MCP secrets over remote: low-priority hardening.

    • ListMcpServers is a remote method (apps/maple-agent/app/src/remote/wire.rs:135). It returns each server's environment and headers values unredacted (apps/maple-agent/crates/maple-agent/src/agent/mcp.rs:352-358; fields at agent/types.rs:106-119).
    • SaveMcpServers (wire.rs:140) replaces the whole list, stdio commands included.

    This is not an escalation, because a paired controller already drives the agent's shell and file tools on that computer. Redacting secret values in responses to remote callers (write-only secrets) would keep tokens off controllers' screens, memory and logs.

@AnthonyRonning
AnthonyRonning marked this pull request as ready for review October 20, 2026 19:06
@AnthonyRonning
AnthonyRonning merged commit 483af36 into master Oct 20, 2026
51 checks passed
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