diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..bfe0706 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,12 @@ +# Agent instructions + +Publish exclusively through `.github/workflows/release.yml` with GitHub OIDC. +Its package release script is a workflow entrypoint: never publish locally, +request npm publishing tokens/login, or troubleshoot local publishing auth. +Use the existing Changesets flow and verify Actions plus the registry before +updating installations. + +Delete dead code, obsolete scripts, duplicate workarounds, and unused legacy +installs. Check active owners/references first; preserve auth, operator env, +durable data, and intentional duplicate suppression. Prefer existing helpers, +stdlib, and native features over new wrappers or fallback frameworks. diff --git a/docs/superpowers/plans/2026-09-15-codex-conversation.md b/docs/superpowers/plans/2026-09-15-codex-conversation.md deleted file mode 100644 index c8d8045..0000000 --- a/docs/superpowers/plans/2026-09-15-codex-conversation.md +++ /dev/null @@ -1,52 +0,0 @@ -# Codex Conversation Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Expose thread discovery, guarded messaging and accurate completion receipts through generated plugin/MCP tools and CLI, as the shared foundation of an automatic Grok↔Codex relay. - -**Architecture:** A conversation wrapper scopes the persistent client to a thread and reconciles bounded history. Existing submit logic is shared by one-shot and persistent callers. Agent Bundle projects the same result/progress contract onto MCP tools, generated plugins and CLI commands. A following task owns the managed automatic relay; this task is not the complete user experience. - -**Tech Stack:** Node.js >=22.19.0, JavaScript/JSDoc core, TypeScript/TSX routes, node:test and existing route tests; Codex 0.154.0. - -**Spec:** docs/superpowers/specs/2026-09-15-codex-conversation-design.md - -## Global Constraints - -- No new dependency, no second daemon, no private Desktop API, no global permission change. -- Preserve accepted/rejected/queued/unknown submission semantics, allowlists and provenance. -- Observers never refuse or approve requests; waiting never interrupts work. -- Scratch sockets and explicit test environments for tests; preserve existing send behavior. - -### Task 1: Conversation collector, guarded messaging and plugin/MCP surfaces - -**Files:** Create `src/core/codex/conversation.js`, `test/codex-conversation.test.js`, `src/cli/codex/watch.tsx`, `src/cli/codex/wait.tsx`. Modify `src/core/codex-bridge.js` only to share existing submission behavior, `src/cli/codex/send.tsx`, `tests/route-unit/tools.test.ts` when appropriate, and add a feature changeset. Create the four `src/mcp/grok-bot/tools/codex_{threads,send,wait,watch}.tsx` routes and shared TypeScript adapters/schemas if useful. Update `src/skills/talk-to-grok-bot/SKILL.md`; tests for generated MCP may live under `test/`. Shared socket fixture code may live under `test/helpers/`. Do not change the existing gbot_send route yet (next task owns automatic reply routing). - -**Interfaces:** Consume `openCodexSession(env,options)` and the transport listeners. Produce exactly the `openCodexConversation`, send/wait/watch/close contracts in the named spec. A supplied session is shared and must not be closed by an individual conversation. - -- [ ] Write failing tests with a fake daemon where `turn/start` sends completion before its acknowledgment and where a resumed turn is already completed. Assert observable outputs: - -```js -const conversation = await openCodexConversation('thread-1', {env,expectedCwd:cwd}); -const sent = await conversation.send('hello', {envelope}); -const result = await conversation.wait({turnId:sent.turnId,messageId:sent.messageId}); -assert.equal(sent.delivery, 'accepted'); -assert.equal(result.execution.state, 'completed'); -assert.equal(result.reply.text, 'final answer'); -assert.deepEqual(result.reply.items.map(x => x.id), ['final-1']); -await conversation.close(); -``` - -Construct literal mixed commentary/final/reasoning fixtures, failed/empty turns, repeated pagination cursors and foreign request IDs. Run the new test file and record expected failures before implementing. - -- [ ] Implement the bounded collector, history reconciliation, shared-session ownership and canonical send delegation. Separate timeout/abort from turn interruption. Validate IDs, cwd, page shapes, timeouts and output budgets; retain correlation on uncertain outcomes. -- [ ] Add MCP discovery/send/wait/watch routes with actual socket-backed invocation tests and generated-server tools/list/call coverage. Implement explicit expected-turn guarded steering without fallback or observer auto-approval. Validate generated plugin artifacts and update installed skill descriptions. -- [ ] Add CLI routes/flags with `signal`, result-derived exits, render budget and framework progress. Ensure these actual commands work after building: - -```sh -gbot codex watch --timeout-ms 1000 --max-events 20 THREAD_ID --json -gbot codex wait --timeout-ms 1000 THREAD_ID TURN_ID --json -gbot codex send --wait --timeout-ms 1000 THREAD_ID hello --json -``` - -- [ ] Test that an accepted send followed by timeout is still `delivery: accepted`, has `execution.state: timeout`, and exits nonzero; a plain send retains its previous immediate receipt. Test command discovery/validation against the built CLI, not package metadata. -- [ ] Run `npm run check`, inspect the diff for duplicated submission logic and unbounded retained state, commit owned files and report exact test output. Parent will review before the durable binding consumes this API. diff --git a/docs/superpowers/plans/2026-09-15-codex-session.md b/docs/superpowers/plans/2026-09-15-codex-session.md deleted file mode 100644 index 90c629b..0000000 --- a/docs/superpowers/plans/2026-09-15-codex-session.md +++ /dev/null @@ -1,56 +0,0 @@ -# Persistent Codex Session Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Expose a bounded, persistent app-server connection that can deliver events and serve as the foundation for completion waiting and a recoverable Grok binding. - -**Architecture:** Extend the existing Unix WebSocket implementation. Preserve one-shot send behavior and expose its existing initialization path. Keep conversation scheduling and durable delivery state outside the transport. - -**Tech Stack:** JavaScript/JSDoc, Node.js >=22.19.0, node:test, existing Agent Bundle build; app-server schema 0.154.0. - -**Spec:** docs/superpowers/specs/2026-09-15-codex-session-design.md - -## Global Constraints - -- No new dependencies or Desktop/private-pipe APIs. -- Preserve current envelope, route, receipt, busy and approval ownership contracts. -- One writer owns `src/core/codex-bridge.js` during this task. -- Use scratch Unix sockets and explicit test env; no live gateway messages in unit tests. -- Failures after a submission cannot be mislabeled as rejected deliveries. - -### Task 1: Event-capable persistent transport - -**Files:** Modify `src/core/codex-bridge.js`; create `test/codex-session.test.js`. A focused `src/core/codex/transport.js` extraction is permitted only if needed to keep the transport understandable, with compatibility re-exports from `codex-bridge.js`. Do not modify CLI routes, existing test files, gateway modules or package metadata. - -**Interfaces:** Keep `connectCodexAppServer(path, options)` and add the listener/response APIs defined in the spec. Export `openCodexSession(env, options)` as the canonical initialized persistent connection. Existing send/list/status callers keep their behavior. - -- [ ] Write failing tests using a scratch Unix HTTP Upgrade server. The minimum observable cases are: - -```js -const seen = []; -const off = client.onNotification(message => seen.push(message)); -// Server sends two notification frames in one write. -assert.deepEqual(seen.map(x => x.method), ['turn/started', 'turn/completed']); -off(); -// Later notifications must not reach this listener. - -client.onServerRequest(request => client.respond(request.id, {decision: 'decline'})); -// The peer receives exactly one matching response; a duplicate local respond throws. -assert.throws(() => client.respond('already-resolved', {})); - -const closed = new Promise(resolve => client.onClose(resolve)); -// Destroy the idle peer without a pending request. -assert.match((await closed).message, /closed|disconnect|socket/i); -await assert.rejects(client.request('thread/list', {})); -``` - -Also test AbortSignal cleanup, observer silence on foreign approvals, post-resolution response refusal, absolute limits on outgoing writes and remembered requests, a throwing listener, and notification listeners passed at connection construction. Tests must distinguish a healthy idle connection from a dead one and use short injected test deadlines. - -- [ ] Run `TMPDIR=/tmp GROK_BOT_TEST=1 node --test test/codex-session.test.js` and record the expected failures. -- [ ] Implement event dispatch in `onMessage`, close notification in all cleanup paths, bounded registration/request state, safe response methods and the exported initialization path. Validate numeric limits and timeouts. Attach initial hooks before any bytes can be handled. Maintain existing refusal semantics for legacy one-shot callers. -- [ ] Run the new test file, then `npm run build` and `TMPDIR=/tmp GROK_BOT_TEST=1 node --test test/codex-bridge.test.js test/codex-session.test.js`. -- [ ] Self-review for resource leaks, unbounded state and changed legacy delivery semantics. Commit only the task-owned implementation/test files and write the report with test commands and results. - -## Continuation roadmap - -The controller continues without another user checkpoint: completion waiting and watch commands; atomic delivery ledger and one foreground binding; explicit steering/operator interaction and optional supervision; live loop/recovery proofs; final review, merge and release verification. Each continuation gets its own task brief after the preceding interfaces are verified. diff --git a/docs/superpowers/plans/2026-09-15-managed-relay.md b/docs/superpowers/plans/2026-09-15-managed-relay.md deleted file mode 100644 index 5565b30..0000000 --- a/docs/superpowers/plans/2026-09-15-managed-relay.md +++ /dev/null @@ -1,29 +0,0 @@ -# Managed Grokbot and Codex relay implementation - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development, task review before dependent implementation. - -**Goal:** Deliver Grokbot↔Codex messages and replies automatically through generated plugins/MCP while callers continue working. -**Spec:** docs/superpowers/specs/2026-09-15-managed-relay-design.md -**Architecture:** One durable relay engine and single-writer state store; managed local worker provides the same API to MCP and CLI. Existing gateway, app-server and conversation contracts remain canonical. -**Constraints:** No private Desktop interfaces or global permission edits. Unknown delivery never blindly retries. No automatic approvals. Exact observed source identity or explicit route. Bounded state and explicit coverage gaps. Parent owns live calls. - -### Task 1: Durable conversation relay engine - -**Files:** Create `src/core/relay/state.js`, `src/core/relay/engine.js` and focused helper modules if needed, `test/relay-state.test.js`, `test/relay-engine.test.js`, optional `test/helpers/` fixtures; narrowly update the existing `test/codex-bridge.test.js` fixture to reuse safe short Unix socket paths on macOS (same reproduced EINVAL as the new fixture). May add narrowly needed public conversation/history helpers in `src/core/codex/conversation.js` with tests; avoid duplicated protocol logic. Do not modify surface routes, runtime config or package files in this task. - -- [ ] Read exact spec and reviewed conversation interfaces; write failing state/engine tests for automatic request replies and explicit linked Grok→Codex→Grok return. -- [ ] Implement a bounded, validated relay adapter over the existing Agent Bundle SQLite state kernel (do not duplicate its journal/transaction code) and intake/receipt/checkpoint transitions, scoped transcript correlation and echo prevention. -- [ ] Implement bounded reconciliation after uncertain sends/restarts, guarded active delivery, output coalescing and completion, and cancellation/backoff/visible pause behavior. -- [ ] Expose bounded status and generation-scoped interactions, method-specific response validation without auto-approval. -- [ ] Prove duplicate polling, crash boundaries, missing cursors, empty startup, out-of-order correlation, state bounds/corruption, own-response echo suppression, foreign/stale requests and disconnect behavior using fixtures. Test expected failures before fixes. -- [ ] Run affected core and conversation suites plus typecheck/build; self-review, commit owned files and report. Parent reviews before Task2 consumes API. - -### Task 2: Managed worker and fluid plugin/MCP experience - -**Files:** Create process/control modules in `src/core/relay/`, bundled worker entry `src/scripts/gbot-relay.ts` through the existing script pipeline (verified all-host emission); modify plugin description in `agent-bundle.config.ts`, `src/mcp/grok-bot/tools/gbot_send.tsx`, `codex_send.tsx`, new bridge start/status/stop/respond tools, shared TS adapter/schema module, CLI bridge routes and explicit gbot send auto-route options. Update installed skill, README, feature changeset and route/packed-worker tests. - -- [ ] Write failing generated MCP tests for native source identity automatic routing, source-unavailable manual receipt and explicit return route, plus worker survival after caller exits and concurrent starts. -- [ ] Implement private bounded worker control protocol, verified startup/profile identity, stable mutation request IDs, concurrency-safe lifetime and foreground mode. Locate packaged worker correctly from CLI and generated MCP/host installations, including paths with spaces. -- [ ] Wire gbot_send automatic reply routing from native Codex lineage, explicit links and codex_send return routes. No silent fallback to untracked sending on worker failure. Add bridge lifecycle/status and explicit method-specific operator response surfaces. -- [ ] Verify actual packed stdio tool discovery/calls and persisted worker lifecycle against fixtures, all generated Codex/Cursor/portable artifacts, cancellation and compatibility of existing manual/CLI paths. -- [ ] Update installed skill and README to explain normal asynchronous delivery and one-time explicit binding, without claims beyond verified host support. Run full npm run check plus packed smoke at supported minimum Node22.19.0; self-review, commit, report. Parent performs live proof and whole-branch review before merge. diff --git a/docs/superpowers/specs/2026-09-15-codex-conversation-design.md b/docs/superpowers/specs/2026-09-15-codex-conversation-design.md deleted file mode 100644 index 0f43f89..0000000 --- a/docs/superpowers/specs/2026-09-15-codex-conversation-design.md +++ /dev/null @@ -1,37 +0,0 @@ -# Codex conversation messaging through plugins and MCP - -This is the second slice of the approved Grok↔Codex implementation. Zack clarified that Grokbot must communicate with Codex as naturally as Codex Desktop communicates with other threads, through the generated Grokbot/Cursor/Codex plugin and MCP surfaces. The finished product must receive messages and route replies automatically during active work; models must not poll wait/watch tools to operate the normal flow. This slice provides the shared conversation API and first-class MCP messaging surface; the immediately following durable relay slice provides the background lifecycle, automatic routing and recovery. Do not call this slice the complete user experience. - -Consume `openCodexSession` and the persistent transport APIs without adding another Codex daemon or changing global configuration. Package the same core behavior in every existing generated plugin target (Codex, Cursor, Claude and portable MCP for Grok Bot). Do not invent unsupported host APIs. - -## Public core API - -Create `src/core/codex/conversation.js` exporting `openCodexConversation(threadId, options = {})`. Options are `env`, `expectedCwd`, `signal`, `onEvent`, and optionally an already initialized `session` (`{client,path,init}`) for sharing one connection across explicit bindings. A conversation owns only its listeners/subscription when a session is supplied; otherwise it owns and closes its connection. Return `{threadId,cwd,send,wait,watch,close}`. - -Attach notification, server-request and disconnect listeners before `thread/resume`. Resume with `{threadId,excludeTurns:true}` and no execution/model/permission/workspace overrides. Verify returned thread ID and, when provided, the canonical expected working directory. Route through the existing socket and thread allowlists. A mismatch fails before submission. - -`send(text, {envelope,whenBusy='reject',expectedTurnId})` returns the existing canonical submission receipt. Reuse the one-shot submission/validation logic rather than implementing a second version of envelope, busy, queue and error semantics. A persistent conversation stays connected and records requests for observation rather than applying the one-shot owned-request refusal policy. Existing CLI `send` without waiting retains its current policy and disconnect behavior. Add `whenBusy: 'steer'` to the persistent and MCP send contract, requiring an explicit nonempty `expectedTurnId`. Send `turn/steer` with that guard and `clientUserMessageId`; never silently fall back to turn/start on guard rejection. The response shape is `{turnId}` (verify installed generated schema). It preserves canonical submission delivery and envelope fields. `reject` and `queue` remain compatible. The background relay can discover the active turn from bounded history and use the guarded API; a stale active turn returns a visible rejection, not a send into different work. - -`wait({turnId,messageId,timeoutMs=120000,signal,maxOutputBytes=1048576})` observes one submitted turn and returns `{threadId,turnId,messageId,execution:{state,error?},reply:{text,items,truncated},interactions:[]}`. Execution state is `completed`, `failed`, `interrupted`, `waiting-for-input`, `timeout`, `disconnected`, or `unknown`. Wait cancellation/timeout never interrupts the daemon's turn. `messageId` is optional for explicit turn waits, but when supplied it remains in every result. - -The collector installs before send/resume, tolerates events preceding the turn/start acknowledgment, ignores unrelated threads/turns, and reconciles history before waiting for future events. Use `thread/turns/list` with bounded pages and `thread/items/list` for the selected turn. Shapes are pinned in `/tmp/gbot-codex-protocol-20260915`: turns response `data:Turn[]`, items response `data:{turnId,item}[]`. Do not use deprecated unbounded full-history resume/read. Permit at most 20 pages of 100 entries per reconciliation and return `unknown` with a coverage explanation when the selected turn cannot be established. Protect against repeated pagination cursors. - -Return explicit `final_answer` agent items; if absent, use completed phase-null agent items as a documented fallback at terminal status. Do not forward commentary, reasoning or tool output as the final answer. Deduplicate by item ID. Empty successful output is still completed. Preserve failed/interrupted status even when text exists. Keep result text/items within maxOutputBytes (validated positive integer at most 4 MiB), and expose truncation. Bound retained notification and interaction state; surface overflow rather than losing a completion silently. - -`watch({timeoutMs=30000,maxEvents=100,signal})` returns a bounded observation `{threadId,events,reason,truncated}` and supports the `onEvent` callback for progress. Limit events to the selected thread plus relevant connection state; no automatic responses. Reason distinguishes timeout, event limit, cancellation and disconnect. A quiet healthy connection can time out without being reported disconnected. - -## MCP and generated plugins - -Add tools on the existing `grok-bot` MCP server: `codex_threads` (bounded discovery using existing listCodexThreads), `codex_send` (send with optional bounded completion wait), `codex_wait` and `codex_watch` (diagnostics/explicit observation). `codex_send` defaults to immediate acceptance; normal automatic reply routing will be added by the next relay slice. Descriptions must not imply accepted means finished, nor require a model to poll for the final product workflow. Expose delivery, execution and output as distinct fields in structured results, with concise human text. Support expectedCwd, guard/whenBusy and correlation inputs according to the core contracts. Keep schemas explicit and bounded. Route errors use the canonical outcomes and preserve known identities. - -Place surface-neutral route operations and schemas in a small shared TypeScript module as needed so CLI and MCP wrappers do not fork protocol behavior. Tool handlers receive cancellation from Agent Bundle invocation context when supported. New tools and existing gbot tools must all be discovered by actual generated MCP server tools/list. Use actual route invocation/socket fixtures for tools/call; test accepted then timeout and guarded active delivery. Build/validate the Codex and Cursor manifests plus portable MCP artifact. Update the installed talk-to-grok-bot skill with the new tool purposes and current availability; do not promise the next relay slice before it exists. - -## CLI - -Add `gbot codex watch ` and `gbot codex wait `, and `gbot codex send --wait ...`. Support timeout and expected-cwd flags, plus explicit guarded steer options; input timeouts are positive integers up to 600000 ms. Watch max-events is 1..500. Use existing Agent Bundle routes, CliRouteProps.signal and result-derived exit codes. Set rendered route maxElapsedMs to 660000 to encompass the maximum operation plus shutdown; use `agent().progress.report` for lifecycle updates and framework `--ndjson` rather than writing competing stdout records. Default JSON output remains one final result document. - -`send --wait` returns the original flat submission receipt plus `execution`, `reply` and `interactions`; accepted submission remains accepted after a wait timeout or execution failure. Queued/rejected/unknown submissions do not pretend a turn completed. Explicit wait/watch failures must preserve known thread/turn IDs. Exit 0 for a completed wait, nonzero for incomplete/failed execution; a bounded watch that reaches its requested timeout/event count is successful. Rendering or signal cleanup must not cause a duplicate submission. - -## Tests - -Use socket fixtures and the built CLI. Cover early completion in the same packet as acknowledgment, resumed completed turns, paginated item wrappers, unrelated events, phase filtering and empty output, failure/interruption, timeout/abort/disconnect, missing-turn coverage, pagination cycles, output bounds, cwd mismatch, foreign approvals remaining unanswered, and no observer-induced interruption. Retain old send tests and add route/built CLI checks for the new flags and receipt separation. Add MCP route tests and generated stdio server discovery/call tests. Verify guard mismatch never resubmits, and persistent sends never auto-answer approvals. diff --git a/docs/superpowers/specs/2026-09-15-codex-session-design.md b/docs/superpowers/specs/2026-09-15-codex-session-design.md deleted file mode 100644 index 78a3d72..0000000 --- a/docs/superpowers/specs/2026-09-15-codex-session-design.md +++ /dev/null @@ -1,24 +0,0 @@ -# Persistent Codex session design - -This implements the first part of the Grok↔Codex design approved by Zack's request to do all next steps. Keep the existing managed daemon and gateway. The later binding will consume this session layer; it will not run another Codex engine. - -## Contract - -Extend the existing WebSocket-over-Unix-socket client with synchronous registration methods `onNotification(listener)`, `onServerRequest(listener)`, and `onClose(listener)`, each returning an unsubscribe function. Notifications carry the original `{method, params}` object. Server requests carry original `{id, method, params}`. Close listeners receive an Error explaining closure, once. Registration after closure must still expose closed state (through `closed` and/or immediate close callback). Constructor options may install the three listeners before connection/initialization messages arrive. - -Keep request/notify/close and the existing one-shot refusal/ownership behavior working. New passive listeners must never reject another client's approval. Add `respond(id, result)` and `rejectRequest(id, error)` for pending server requests; reject duplicate or resolved IDs locally. Clear pending request ownership on `serverRequest/resolved` and connection close. The high-level session will enforce thread/turn ownership and method-specific response validation before invoking these low-level methods. - -Expose the existing initialization path as `openCodexSession(env, options)` returning `{client, path, init}`. It must use the same socket selection, route checks, initialize validation, version identity and cleanup as today's `openSession`. Support `signal`, `timeoutMs`, `experimental`, and initial event listeners. Keep existing internal callers compatible. - -## Resource and lifecycle limits - -- Retain 16 KiB upgrade header, 4 MiB message and 8 MiB aggregate receive bounds and absolute handshake/RPC deadlines. -- Outbound encoded frames and queued socket bytes must fit an 8 MiB budget; a nonreading peer must cause a visible bounded failure. Await/drain or fail rather than silently accumulating writes. -- Bound outstanding client requests and remembered server requests/refusals/deferred requests to 128 each. Exceeding a bound closes the connection with an explicit error and rejects pending operations. -- Close on protocol errors; complete cleanup on abort and local/remote close. No new requests after closure. Dispose listeners and pending timers; no unhandled rejection or process-level exception from a throwing listener. -- Idle healthy connections survive the RPC timeout. Disconnection must notify observers even when no RPC is pending. Local close must not stop the daemon or other clients. -- No new dependency, no raw private Desktop pipes, no Desktop patch, and no daemon/global permission change. - -## Validation - -Use real Unix socket fake servers for framing and lifecycle tests. Verify notification ordering, listener disposal, pending server request response exactly once, resolution invalidation, listener failure, abort, idle disconnect, request-after-close, bounded outgoing pressure and server-request floods. Retain the existing codex bridge suite, including its one-shot ownership tests. A live metadata-only probe may connect two clients to the existing daemon; no model prompt is needed for this layer. diff --git a/docs/superpowers/specs/2026-09-15-managed-relay-design.md b/docs/superpowers/specs/2026-09-15-managed-relay-design.md deleted file mode 100644 index 64c2d8d..0000000 --- a/docs/superpowers/specs/2026-09-15-managed-relay-design.md +++ /dev/null @@ -1,80 +0,0 @@ -# Managed Grokbot and Codex conversation relay - -## User outcome - -Grokbot must communicate with Codex like Desktop communicates with its other threads. Plugin/MCP is the primary flow, including the generated Codex and Cursor plugins. Grok Bot receives/sends through its existing gateway conversation, which the relay connects to Codex; native Grok Bot loading of this generated plugin is not established and must not be claimed. CLI commands expose the same controls for administration. A model sends once, continues work, receives the other agent's message in its thread, and answers normally. Session Miner verified local host stdio MCP→HTTPS Grok gateway and a separate Grok Computers local-execution facility; no native Grok plugin loader or remote stdio MCP tunnel was found. Do not invent either to complete this task. Models do not run polling loops or keep a tool call open to receive messages. - -This consumes the reviewed persistent transport and conversation APIs. It is a client of the existing Codex app-server, not another Codex daemon. Use supported app-server and Grok gateway contracts only; no private Desktop pipes, binary patches, or global permission/model changes. Preserve existing plain CLI sends and explicit diagnostic tools. - -## Routing and ownership - -Two supported flows share the same durable relay engine: - -1. **A Codex thread sends to Grok.** `gbot_send` defaults to automatic reply delivery when the invocation has a host-observed Codex conversation identity. Snapshot the target tail first when its tracking state is new, then persist a request record, that baseline and stable gateway nonce before sending, return the submission receipt promptly, then follow only Grok messages sharing the outbound user entry's actual `requestId`. Deliver each new visible Grok response to the originating Codex thread automatically. These reply deliveries do not return Codex's next final answer to Grok by default, preventing an implicit ping-pong. A model can deliberately send the next message as another request. -2. **A Grok conversation is linked to a Codex thread.** `gbot_bridge_start` creates one explicit durable bot/group-to-Codex binding. Subsequent visible Grok bot `send-message` entries are delivered to that Codex thread; its corresponding terminal final answer and status return to that Grok conversation automatically. `codex_send` may also explicitly request a Grok return target, using the same tracked delivery path. Explicit links allow proactive Grok messages while Codex works. Binding creation snapshots the existing tail and starts with new entries; no historical replay by default. - -A binding identifies exact resolved Grok target ID, Codex thread ID, canonical expected cwd, endpoint/profile, busy policy and creation checkpoint. Resolve target names once; persist IDs. Resume verifies exact thread and cwd before any submission. Existing socket/thread allowlists apply. Do not attach unrelated threads or infer destinations from filesystem recency. - -Source auto-detection uses `await agent()` request context: available host normalized to `codex` with the runtime's `lineageHostFromClient` helper (a real daemon call reports `codex-mcp-client`, not literal `codex`), available lineage with `source: native` and `resolution: native`, then `lineage.value.conversation`. Installed Agent Bundle 8e55ab832d derives this from MCP `_meta['x-codex-turn-metadata']` thread_id/session_id. Require exact source identity; do not treat Cursor tool-window inference, arbitrary session IDs, process-wide CODEX_THREAD_ID, or stale environment as a current Codex thread. Explicit `codexThreadId` works when the host omits identity. An existing explicit binding may be selected by bindingId. For an unidentifiable source, preserve ordinary gbot_send and return `replyRoute: {mode:'manual',reason:'source-unavailable'}` instead of claiming automatic delivery. `replyMode: 'manual'` explicitly selects old behavior. Once an automatic route is requested, do not silently downgrade a relay startup/storage/route failure into an untracked send. - -Inbound text names its Grok sender and message identity and explains whether a normal final answer returns automatically. This is ordinary user-message provenance, not an authentication or system-instruction boundary. Actual correlation, reply destinations and hop ancestry are engine-owned records; models need not copy text headers. - -## Shared core and durable state - -For auto-routed sends without an explicit expectedCwd, verify the source via resume, adopt its canonical cwd once and persist that expectation. If invocation workspace evidence is available, check it consistently rather than treating plugin installation cwd as the user workspace. - -Create a small relay core under `src/core/relay/`, separating state storage, engine transitions and process control. Public engine operations should cover `startBinding`, `stopBinding`, `status`, `sendToGrok`, `sendToCodex`, `tick` or a cancellable `run`, and `close`. Exact function signatures may fit the existing code, but route adapters must share them; never duplicate network/delivery policy in MCP and CLI. Test seams inject the gateway and conversation/session interfaces, clock and state directory. - -Reuse the already-installed Agent Bundle state kernel (`@agent-bundle/runtime/state` and its `/sqlite` durable driver) for versioned JSON-safe state, schema validation, atomic commits and idempotent state events. It supports the minimum Node22.19.0; no new dependency or custom database engine is needed. Wrap it in the relay state module, rather than reimplementing its transaction/journal machinery. Persist in a user-owned relay directory, default `~/.grok-bot-cli/relay/` with explicit `GROK_BOT_RELAY_DIR` override. Do not place state in a versioned plugin cache. A single worker owns mutation, enforced by an exclusive lock and control endpoint. Use the kernel's atomic durable commits and bounded state/journal policies, with bounded domain events and a pure reducer. Avoid journaling the entire accumulated state for every poll/checkpoint; unchanged polls commit nothing. Load the optional SQLite driver only when durable relay state is opened so ordinary stateless commands keep their existing runtime behavior. Directories mode0700, files0600; inspect the database, WAL/SHM and lock paths and reject symlink/nonregular targets before opening. A corrupt, oversized or unsupported-version ledger fails visibly and does not reset or resend. Keep service ownership separate from the state driver's SQLite locking; an atomic state commit does not prevent two workers from sending the same prepared record. A dedicated ownership SQLite database holds an exclusive transaction for the entire worker lifetime, acquired before opening the state engine. The OS releases this ownership on process death. Validate its database and journal/WAL/SHM paths too, and never remove or replace a lock database another worker may hold. This avoids a stale recovery-gate file that could strand startup after a crash. Store only routing, necessary bounded message text, delivery receipts and dedupe state; never credentials, raw gateway results or unrelated transcripts. Persisted text is an inherent part of the requested durable relay, independent of opt-in general history. - -Record source entry IDs, clientNonce/clientUserMessageId, correlation/replyTo/hop, target/thread/turn IDs, submission state, execution state, reply delivery and checkpoints separately. States include prepared (definitely not submitted), sending (uncertain after crash), accepted, rejected, unknown, completed, needs-input, paused. Write intent before network submission and acknowledgment after. A missing ack cannot become accepted; an accepted submission cannot become rejected because waiting timed out. A client ID is correlation evidence, not an assumed upstream idempotency guarantee. - -Use one bounded serialized state mutation path; do not hold its lock across network waits. Intake checkpoints advance only after all entries through that checkpoint are durably recorded or deliberately ignored. Bound active records, text bytes, historical receipts, interactions and total ledger bytes. Never evict pending/uncertain records to make space. If capacity is exhausted, pause intake with a visible reason and retain the last safe cursor. Completed record compaction may drop text, but must preserve dedupe/echo evidence until a safe coverage boundary proves it irrelevant; otherwise pause instead of guessing. No silent drop/replay. - -## Transcript correlation and loops - -Use existing raw `getTranscriptTail` plus `sourceEntryId` and `entryText`; the MCP thread presentation strips metadata and is not the relay's input. Treat IDs as opaque strings. Gateway `sendPrompt` supports stable `clientNonce` and optional `replyToId`. Actual transcript user entries contain clientNonce and requestId, and matching bot send-message entries share requestId (verified live). Persist that relationship. For accepted gateway sends without observed user entry, keep matching pending; for unknown sends, reconcile the nonce in bounded history before any resend. No match within available coverage remains unknown and needs attention; do not automatically resend it. - -Read up to200 entries per bounded tail poll (default2s, backoff on errors). On initial empty tail, retain an explicit empty-baseline state so the first new entry is handled once. If a nonempty saved cursor is absent, pause with `gap` and expose its previous/current checkpoints. Do not treat transcriptDelta's reset snapshot as new messages. Validate all consumed entry IDs and required kinds/metadata; unidentifiable message entries cause a visible coverage problem rather than checkpoint advancement past possibly relevant content. Tool/reasoning entries are never forwarded. - -Bindings forward visible bot `send-message` entries. Ordinary user posts are used for nonce/requestId correlation, not forwarded as duplicate bot messages. Ignore the relay's own posted user entries and **all** bot outputs sharing the requestId of a returned Codex result. Own outgoing user entries may appear after their bot result in a fetched page: gather correlations for the entire page before classifying outputs. An automatic Codex→Grok request is a distinct tracked request, and its matching Grok replies are injected once; do not also forward them as binding unsolicited messages. Stable source IDs dedupe repeated polls and restarts. A single Grok target may have multiple request routes to different Codex threads; requestId matching routes each reply to only its originating thread. An unsolicited persistent link for a target is unambiguous (reject a second conflicting link unless stopped). - -Default behavior bounds an exchange to request and reply, with no automatic follow-replies loop. Preserve envelope hop/maxHops and reject at the bound for explicit chained requests. No infinite autonomous conversations or inferred ancestry from freeform body text. - -## Codex delivery and completion - -One persistent initialized session per endpoint generation can serve explicit conversations; close/disconnect invalidates that generation's requests. Use `openCodexConversation` with shared session where practical. Attach listeners before resume/send. Use the reviewed bounded history API to reconcile reconnects and uncertain Codex submissions by exact userMessage.clientId. Scan at most20 pages of100 entries, detect repeated cursors, and distinguish missing coverage from known rejection. If a sent-but-unacknowledged clientId is found, adopt its observed turn and resume completion; never resubmit merely because receipt persistence was interrupted. - -Incoming messages should reach active work. The managed route's default busy policy is explicit guarded steering: discover the actual active turn from bounded thread state/history, then send `turn/steer` with expectedTurnId. If no active turn exists, use canonical normal send. A stale guard is a definite rejection: re-observe and make at most3 guarded attempts, never retry unknown delivery. Do not use turn/start as fallback after a steer error. Preserve current documented idle-check/turn-start race as a protocol limit; no local lock can serialize another Desktop client. A `reject` policy remains available. Native queue mode remains explicitly experimental and is not required for normal relay delivery. - -Each accepted message is associated with the returned turn ID. Multiple messages steered into the same turn may share its terminal answer: coalesce the automatic Grok return per target+thread+turn and include the source message IDs/correlation records, rather than posting the same final repeatedly. A live steer probe confirmed that an active turn can contain an already-emitted final_answer before the steered user message and another final_answer afterward. Anchor automatic returns to the earliest associated clientUserMessageId in that turn and exclude agent items before its userMessage.clientId. Extend the shared collector with optional `afterMessageId` (or an equivalent narrow reply-selection helper) and test this actual ordering; a plain turn-level wait can keep returning all final items. Missing anchor/coverage must be explicit, never forward earlier unrelated content as the reply. The anchor bounds history selection; a shared active turn can still combine subsequent inputs, which should be described accurately. Use the collector's completed final_answer items or terminal phase-null fallback; never forward commentary, reasoning, tool logs or unrelated turns. Preserve failed/interrupted status and empty successful replies. Default outbound text at most64KiB, explicit truncation. Send status once if no final text is present. A needs-input turn is visible and remains resumable; timeout does not interrupt it. No automatic approvals/refusals from observers. - -After reconnect, re-establish subscriptions, reconcile pending receipt IDs and turn completion, then resume new intake. Backoff bounded1..30s; no tight reconnect loop. Auth failures use a visible auth reason with bounded retry backoff; after credentials are restored, resume transcript reads from the unchanged checkpoint. Persisted auth-paused state can retry under the same nextPoll bound. Missing cursor coverage still pauses as a gap, and no auth recovery resets a cursor or resends an unknown submission. Other paused states remain paused. Stop cancels relay observation/submissions and closes owned sockets but never cancels another client's Codex turn or deletes pending records. Restart resumes from safe checkpoints. A worker reconnects lost network/app-server connections on its own. Distinguish this from process/OS supervision: if login persistence is not installed, report that a stopped/crashed process needs restart, and ensure the next tool-driven worker start resumes saved routes. Never report a dead pid as a running route. - -## Managed process and tools - -Start a background worker on demand for tracked sends or binding start. A successful MCP call must not depend on its render promise or stdio process staying alive. Prefer one local worker per endpoint/state directory with a private Unix-domain control socket; no unauthenticated public listener. Worker readiness is a successful version/profile handshake, not a pid or file. Concurrent starters must converge on the same owner. Never unlink a live listener or kill a PID based only on stale metadata. Verify endpoint ownership and protocol identity; close bounded requests/connections. Startup timeout is a visible failure before an untracked send. A worker disconnection never causes automatic re-execution of a control send without a durable idempotent request ID. - -Ship the worker as a conventional plain `src/scripts/gbot-relay.ts` entry with a top-level worker invocation, compiled to `scripts/gbot-relay.mjs` in every host artifact and npm dist. A parent prototype verified the script is declared in executables.scripts and files with a checksum for Claude/Codex/Cursor/portable, and executes from an artifact path containing spaces. `config.bin` alone is insufficient: it emitted the custom worker only in npm dist, absent from host artifacts and their manifest. Use the existing script pipeline, not a post-build copy or extra source-code runner. This plain bundled script has its own process lifetime, independent of CLI/MCP rendering budgets. Resolve it from the emitting package/plugin root, verify existence, and spawn with process.execPath plus argv arrays (no shell). Do not assume process.argv[1] is the CLI when invoked via MCP. Avoid copying credential text into command lines/logs/state. The worker may inherit already-authorized environment and refresh app auth through existing connectGateway logic. Profile mismatch between an existing worker and caller is an error, not credential replacement. The fingerprint includes effective endpoint and relevant gateway routing/auth override identity, thread allowlists, max-hop policy and test/local-gateway policy; a restricted caller must never reuse an unrestricted worker. Hash sensitive override values without retaining or printing them. Do not fingerprint unrelated host/plugin installation paths or ephemeral per-call thread IDs, since Codex and Cursor copies with the same policy should share a worker. Existing app-session refresh should keep its stable auth-source identity rather than treating every refreshed access token as a new profile. Test installed artifact paths containing spaces. Windows should report the existing Codex Unix-socket limitation clearly. - -Tools: -- `gbot_send`: retain target/message, add optional replyMode(auto/manual), codexThreadId, expectedCwd, bindingId as needed; native Codex invocation auto-routes replies. Return existing submission receipt plus replyRoute and durable exchange ID. Explicit auto route first ensures worker and valid destination, then sends exactly once. -- `gbot_bridge_start`: grokTarget and codexThreadId (or proven native source) with expectedCwd and busy policy; return binding ID and verified ready/running or explicit paused/error state. -- `gbot_bridge_status`: optional bindingId, bounded receipts and current pending interactions. Distinguish worker health, binding coverage, submission, execution and return delivery; no raw transcript dump. -- `gbot_bridge_stop`: bindingId, preserving ledger. Provide optional all/worker shutdown only through explicit input. -- Extend `codex_send` with optional replyToGrok target/binding so the same worker returns its answer automatically. Without a return route, retain the conversation tool's immediate/explicit-wait behavior. -- CLI `gbot codex bridge start/status/stop/run` and existing gbot send equivalent auto-route flags when explicitly requested. All adapters share core behavior. `run` is an explicitly bounded foreground session that shuts down before the Agent Bundle renderer's 24-hour hard ceiling; an explicit duration option allows short lifecycle verification. The plain packaged `scripts/gbot-relay.mjs` is the unlimited service-manager entry. Ordinary plugin users need no terminal process and the on-demand background worker has no render lifetime ceiling. - -Correct the existing README claim of a permanent Desktop app-tools impossibility: the current shim does not forward spawn-time overrides, and no restoration path has been demonstrated here; do not claim a permanent protocol impossibility or app-tools parity. - -Install/skill documentation describes the fluid send/receive sequence, explicit one-time binding when native identity is unavailable, current Grok host delivery, and recovery statuses. Do not require users to understand transport internals or pretend a generated config means a host loaded it. Verify generated Codex/Cursor plugins and portable MCP tools on packed installation. Describe persistent background lifetime and stop control clearly. Optional login service is not necessary for basic on-demand worker survival, but if supplied it is explicitly installed/removed and scoped to this relay, not the Codex daemon. - -## Operator interactions - -Expose pending scoped interactions as human-readable status, with connection generation and opaque interaction ID, exact thread/turn and method. Return only supported bounded question/approval fields, never credentials/token refresh or arbitrary tool execution requests. Never automatically answer an approval. Provide `gbot_codex_respond` / CLI bridge respond for an explicit operator response to supported command/file approvals and request-user-input questions. Command/file approval responses support only one-time accept, decline or cancel, respecting availableDecisions when present. Session-wide acceptance, policy amendments and file grantRoot requests remain unsupported here and require the owning Codex UI. User-input answers are keyed by the exact pending question IDs with bounded string arrays. A response validates method-specific result shape, matching binding/thread/turn/generation and pending identity before sending; consume ownership before serialization and mark resolved. Reject foreign/unscoped requests, stale connection IDs, already-resolved IDs and unsupported methods. `serverRequest/resolved` invalidates local pending entries. No generic arbitrary JSON-RPC passthrough or permission widening. Requests needing unsupported UI remain visible for the owning Codex client. - -## Acceptance and proof - -Use hermetic gateway/socket fixtures first; tests must not read real app auth. Prove crash boundaries before/after both submissions and acknowledgment persistence, duplicate polls, out-of-order page correlation, cursor loss, empty baseline, failed/empty Codex output, disconnect/backoff, concurrent starters, stopping, malformed ledger, bounds, symlink refusal, isolated profiles and stale interactions. Test actual generated stdio tools/list and tools/call plus a packed worker lifecycle after caller exit, not only module mocks or executable metadata. - -Controlled live test artifacts are /tmp/gbot-live-bot.json and /tmp/gbot-live-codex-thread.json; created only for this task. Parent owns all live calls. Test one Grok visible message → one Codex accepted/steered message → correct final return. Test Codex MCP-originated gbot_send with native metadata → automatic incoming reply on that exact Codex thread. Repeat through worker restart and bounded disconnect; validate IDs and counts. Test active guarded delivery without interrupting unrelated work. Never use Session Miner, General or unrelated real threads as fixtures. No automatic cleanup of user data; stop verification bindings after receipts are captured.