Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions docs/ai/design/2026-08-11-feature-codex-print-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
phase: design
title: Codex Print-Mode Agent Design
description: Provider-minted session binding and run-per-message Codex execution
---

# Codex Print-Mode Agent Design

## Architecture Overview

Codex is added beside the existing Claude provider modules, sharing only the proven durable store/state primitives.

```mermaid
flowchart LR
CLI[agent start/list/detail/send] --> Resolver[provider-aware print resolver]
Resolver --> Claude[ClaudePrintAgentService]
Resolver --> Codex[CodexPrintAgentService]
Claude --> Store[PrintAgentStore]
Codex --> Store
Codex --> Runner[CodexPrintRunner]
Runner -->|prompt via stdin| Exec[codex exec process]
Exec -->|JSONL thread/turn/item events| Runner
Runner -->|bind thread UUID during run| Store
Exec --> Native[(Codex native session)]
```

Interactive adapters remain unchanged. No generic provider framework or persistent server is introduced.

## Data Models

```ts
type PrintProvider = 'claude' | 'codex';
type PrintAgent = ClaudePrintAgent | CodexPrintAgent;

interface PrintAgentBase {
id: string;
name: string;
mode: 'print';
cwd: string;
state: 'ready' | 'running' | 'degraded';
sessionHealth: 'uninitialized' | 'healthy' | 'unknown' | 'mismatch';
createdAt: string;
updatedAt: string;
lastActiveAt: string | null;
lastResult: PrintLastResult | null;
activeRun: PrintActiveRun | null;
}

interface ClaudePrintAgent extends PrintAgentBase {
provider: 'claude';
providerSessionId: string;
}

interface CodexPrintAgent extends PrintAgentBase {
provider: 'codex';
providerSessionId: string | null;
}
```

The store remains versioned. Its reader explicitly accepts the legacy Claude schema and the new discriminated schema, then validates provider-specific invariants. It rejects duplicate non-null `(provider, providerSessionId)` pairs.

## API Design

```ts
create(input: { name: string; cwd: string; provider?: PrintProvider }): Promise<PrintAgent>;
bindProviderSession(agentId: string, runToken: string, providerSessionId: string): Promise<PrintAgent>;

interface CodexPrintRunRequest {
agent: CodexPrintAgent;
prompt: string;
executable?: string;
onSpawn(identity: ProcessIdentity): Promise<void>;
onSession(providerSessionId: string): Promise<void>;
}
```

`bindProviderSession` rereads under the mutation lock, verifies active token ownership and UUID validity, permits only Codex null-to-value or same-value idempotence, checks global uniqueness, and atomically persists.

Initial argv is `exec --json -`; resume argv is `exec resume --json UUID -`. The prompt never enters argv.

## Component Breakdown

- `PrintAgent`: shared base and provider discriminants.
- `PrintAgentStore`: provider-aware creation, strict migration, uniqueness, atomic binding, existing locking/reconciliation.
- `CodexCliProbe`: non-model version/help capability checks.
- `CodexPrintRunner`: safe spawn, process handshake, bounded JSONL parser, immediate session callback, assistant-result extraction.
- `CodexPrintAgentService`: resolve → acquire → run → bind → complete, with provider-specific health classification.
- CLI: selects service by requested/persisted provider and renders provider-specific labels/session state.
- `fake-codex.cjs`: deterministic executable contract and failure controls.

## Design Decisions

- Parallel Codex modules minimize Claude regression risk; shared-service extraction waits for another provider or demonstrated need.
- `thread.started.thread_id` is authoritative because initial and resumed 0.147.0 runs emit the same UUID.
- Binding occurs immediately during the owned first run so post-binding failure resumes instead of forking.
- Explicit UUID resume is mandatory; `--last`, names, transcript scanning, and `exec-server` are rejected.
- Unknown object events are forward-compatible, while required identity/result/completion events remain strict.

## Non-Functional Requirements

- Atomic per-agent exclusion prevents concurrent turns on one Codex thread.
- Stdout lines, stderr capture, and persisted summaries are bounded; malformed streams fail closed.
- Spawn uses no shell and no permission-bypass flags; prompt and native transcripts are never persisted.
- Creation/probe are non-billable and sends have no implicit retry.
- Existing schema records and interactive/Claude behavior remain compatible.
96 changes: 96 additions & 0 deletions docs/ai/implementation/2026-08-11-feature-codex-print-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
phase: implementation
title: Codex Print-Mode Agent Implementation
description: Implementation record, decisions, validation, and deviations
---

# Codex Print-Mode Agent Implementation

## Status

- Current task: Task 4.4, publish the reviewed branch and open the PR.
- Completed: Tasks 1.1–4.3.
- Task tracing: unavailable (`unknown command 'task'`).

## Development Setup

- Worktree: `feature-codex-print-mode`.
- Bootstrap: `npm ci` from the repository lockfile.
- Provider validation and tests are non-billable; only the deterministic fake Codex executable is used.

## Code Structure

- `packages/agent-manager/src/print`: shared durable store plus parallel Claude/Codex probe, runner, service, and errors.
- `packages/agent-manager/src/__tests__/print`: unit/service/integration tests.
- `packages/agent-manager/src/__tests__/fixtures/fake-codex.cjs`: executable provider fixture.
- `packages/cli/src/commands/agent.ts` and CLI tests: provider-aware routing/rendering.

## Implementation Notes

### Tasks 1.1–1.2

- Generalized `PrintAgent` into a `claude | codex` discriminated union without weakening Claude's non-null session invariant.
- Made store creation provider-aware; omitted provider preserves the legacy Claude default and Codex starts unbound.
- Added strict version-1 record validation, including provider-specific IDs and duplicate binding rejection.
- Added token-owned atomic `bindProviderSession` with UUID validation, identical-value idempotence, replacement rejection, and cross-record uniqueness.

TDD red: focused store tests reported four expected failures (hard-coded Claude creation, weak schema validation, and missing binding API). Green/refactor: `npx vitest run src/__tests__/print/PrintAgentStore.test.ts` passed 12/12; `npm run typecheck` and `npm run lint` exited 0.

### Tasks 2.1–2.3

- Added provider-specific classified errors and a three-command, non-model Codex capability probe.
- Added safe initial/resume runner argv, process-identity-before-stdin handshake, strict bounded JSONL parsing, immediate async thread binding, ordered assistant messages, and terminal success requirements.
- Added Codex create/send orchestration with provider-aware create, run-token callbacks, mismatch/unknown health classification, and no retry.

TDD red: 14 focused tests failed on absent Codex exports. Green/refactor: those 14 tests passed; the full agent-manager suite passed 27 files/515 tests; typecheck and lint exited 0.

### Tasks 3.1–3.3

- Added an executable fake Codex CLI with deterministic provider-minted UUID, exact resume validation surface, stdin/cwd/argv capture, chunked results, and configurable protocol/process failures.
- Added integration proof that creation remains unbound/non-billable, first send binds, second send explicitly resumes, and post-binding failure retains the UUID.
- Made CLI print startup accept Claude or Codex, select the persisted provider for sends, render `Codex (print)`/`not started`, and derive JSON provider from the record.
- Preserved the common store resolver, exact-ID precedence, cross-mode ambiguity, synchronous timeout behavior, and interactive command paths.

TDD red: Codex fixture execution and two CLI routing tests failed before executable/routing support. Green/refactor: agent-manager passed 28 files/518 tests; CLI passed 79 files/932 tests; both typechecks and lints exited 0 (five existing CLI warnings).

### Tasks 4.1–4.3

- Hardened runner callback/process error classification and probe recognition of the standalone stdin dash token.
- Replaced new version-1 writes with version 2 and added a strict Claude-only version-1 compatibility reader; malformed or version-1 Codex records are rejected.
- Reviewed all changed files against requirements/design and traced CLI/service/store call sites. No blocking security, compatibility, or integration findings remain.

TDD red/green evidence includes the standalone-dash false-positive probe test, child-process error classification test, and explicit version-1-to-version-2 migration test.

## Integration Points

- The existing print store remains the single durable mapping and exclusion authority.
- CLI start selects probe/service by requested type; send selects by persisted record provider.
- Runner callbacks persist provider process identity before stdin and provider session identity on `thread.started`.

## Error Handling

- `CodexPrintError` classifies unsupported CLI, process, protocol, session mismatch, and missing result failures.
- The service records failures through token-owned completion, mapping well-formed UUID mismatch to `mismatch` and other session/protocol failures to `unknown`.
- There is no retry, replacement session, or fallback to `--last`.

## Performance Considerations

- Each send spawns one process; no idle process or server is retained.
- JSONL line buffering, stderr capture, and stored summaries are bounded.
- Store mutation locks are short-lived; the per-agent lock spans the provider run.

## Security Notes

- Prompt only via stdin after provider identity persistence; `shell: false`; fixed argv.
- Exact canonical cwd; explicit UUID resume; no permission bypass or transcript copying.
- Provider output is untrusted and validated before affecting durable identity or success.

## Validation Evidence

- Base and feature lifecycle lint: passed.
- Root lint: passed with six existing warnings in unrelated files and no errors.
- Root build: six projects passed.
- Root tests: six projects passed; agent-manager 28 files/527 tests and CLI 79 files/932 tests in their fresh coverage runs.
- Agent-manager coverage: 90.23% statements and 93.4% lines overall; every new Codex module has 100% lines/functions, and `CodexCliProbe` has 100% statements/branches/functions/lines. Runner/service residual branch-only gaps are injected/default process plumbing, not pure parsing logic.
- CLI coverage: 79 files/932 tests; 71.6% statements, 61.67% branches, 69.77% functions, 72.74% lines overall.
- Known test-run warning: pre-existing max-listener warnings in agent-manager tests; no new persistent process listeners were added.
79 changes: 79 additions & 0 deletions docs/ai/planning/2026-08-11-feature-codex-print-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
phase: planning
title: Codex Print-Mode Agent Implementation Plan
description: Ordered TDD work for durable Codex print agents
---

# Codex Print-Mode Agent Implementation Plan

## Milestones

- [x] Milestone 1: Provider-aware durable model, migration, and session binding.
- [x] Milestone 2: Codex probe, runner, service, and deterministic fixture.
- [x] Milestone 3: CLI integration and compatibility coverage.
- [ ] Milestone 4: Documentation, full validation, review, and PR publication.

## Task Breakdown

### Phase 1: Foundation

- [x] Task 1.1: Drive the discriminated `PrintAgent` union and provider-aware creation with failing store/domain tests.
- Outcome: Claude and Codex records coexist; legacy Claude files remain valid.
- Validation: focused `PrintAgent`/`PrintAgentStore` tests and typecheck.
- [x] Task 1.2: Drive `bindProviderSession` integrity behavior with failing tests.
- Outcome: token-owned atomic null-to-UUID binding, idempotence, mismatch and duplicate rejection.
- Dependencies: Task 1.1.
- Validation: focused store tests for every binding branch and persistence after failure.

### Phase 2: Codex execution

- [x] Task 2.1: Drive `CodexCliProbe` and provider error types with failing tests.
- Outcome: version/help-only capability validation and sanitized errors.
- [x] Task 2.2: Drive `CodexPrintRunner` with fake spawn/fixture tests.
- Outcome: exact argv/cwd/stdin handshake; bounded strict JSONL; immediate UUID binding; ordered assistant output.
- Validation: normal, chunked, unknown, malformed, oversized, truncated, missing, mismatch, stderr, and exit branches.
- [x] Task 2.3: Drive `CodexPrintAgentService` orchestration with failing tests.
- Outcome: first/resume lifecycle, correct health degradation, no retry, binding retained after later failure.

### Phase 3: CLI and integration

- [x] Task 3.1: Add provider-aware exports and fake-Codex integration journey.
- Outcome: create performs probes only; first send binds; second send resumes same UUID; concurrency/recovery/cwd work offline.
- [x] Task 3.2: Drive CLI start/list/detail/send behavior with failing command tests.
- Outcome: `--type codex --mode print`, `Codex (print)`, `not started`, record-derived JSON provider, provider-selected send.
- [x] Task 3.3: Run Claude-print and interactive-Codex regression tests and inspect excluded command paths.

### Phase 4: Validation and publication

- [x] Task 4.1: Reconcile implementation/testing docs and reach 100% coverage on new pure logic.
- [x] Task 4.2: Run feature/base lifecycle lint, lint, typecheck, build, package/full tests, and coverage.
- [x] Task 4.3: Perform design-alignment and holistic code review; fix blocking findings via TDD.
- [ ] Task 4.4: Create conventional commits, fetch/rebase `origin/main`, rerun gates, push, and open the requested PR.

## Dependencies

Tasks are ordered because the domain/store contract underpins runner/service and CLI behavior. Tests use only injected process boundaries and `fake-codex.cjs`; no model credentials or calls are required. Optional task tracing is unavailable (`npx ai-devkit@latest task list --name codex-print-mode --json` returned `unknown command 'task'`).

## Timeline & Estimates

- Foundation: medium; migration and binding integrity are highest risk.
- Provider execution: medium/high; protocol and crash ordering dominate.
- CLI/integration: medium; compatibility tests dominate.
- Validation/publication: medium; coverage and rebase can reveal follow-up fixes.

Work proceeds sequentially through the approved lifecycle without a calendar commitment.

## Risks & Mitigation

- Orphan/forked sessions: bind on `thread.started`; never recover through `--last`.
- Concurrent resume: reuse fail-fast per-agent locks and token ownership.
- Protocol drift: capability probe, strict required events, tolerant unknown objects.
- Secret leakage: stdin-only prompt, bounded/sanitized diagnostics, no transcript storage.
- Regression: parallel provider modules plus focused and full existing suites.
- Scope growth: deletion, Pi, capacity routing, server mode, and generic adapters remain deferred.

## Resources Needed

- Existing Claude print implementation/tests/docs as the template.
- Codex 0.147.0 empirical event contract supplied in the build brief.
- Node/Nx/Vitest toolchain and temporary fake-provider files.
Loading
Loading