OxagenDocs
Specs & Plans

Oxagen Rust CLI (OSS BYOK)

Archived spec & plan — status: not started (audited 2026-07-03).

Status: Not started — verified against the codebase on 2026-07-03 by an automated audit.

The Oxagen Rust CLI specification was published on 2026-07-03 (PR #544) as a comprehensive multi-phase plan to rebuild the CLI as a standalone Rust binary with BYOK, multi-provider support, and SWE-bench benchmarking. However, zero implementation code exists: no Cargo crates, no workspace structure, no CI, no Rust files outside node_modules. The spec explicitly states "proposed spec, not yet started."

Implementation evidence

  • docs/specs/oxagen-rust-cli/00-overview.md — spec status header declares 'not yet started'
  • docs/specs/oxagen-rust-cli/01-product-spec.md — product requirements and feature matrix
  • docs/specs/oxagen-rust-cli/02-architecture.md — crate layout and trait design
  • docs/specs/oxagen-rust-cli/03-plan.md — 7-phase build plan with effort estimates
  • docs/specs/oxagen-rust-cli/04-benchmark-strategy.md — SWE-bench methodology
  • docs/specs/oxagen-rust-cli/05-risk-register.md — risk register
  • PR #544 merged 2026-07-04 — spec documentation commit only

Known gaps at time of archive

  • crates/oxagen-protocol/ — protocol types and trait definitions
  • crates/oxagen-core/ — step-driver engine
  • crates/oxagen-tools/ — workspace trait impl (fs/exec/grep/glob)
  • crates/oxagen-model/ — provider adapters (Anthropic, OpenAI, Bedrock, Vertex, OpenRouter, Ollama)
  • crates/oxagen-graph/ — code-graph context engine
  • crates/oxagen-pipeline/ — orchestration and best-of-N
  • crates/oxagen-fleet/ — multi-agent coordination
  • crates/oxagen-mcp/ — MCP client
  • crates/oxagen-tui/ — interactive REPL
  • crates/oxagen-cli/ — CLI binary and command tree
  • Cargo workspace infrastructure (Cargo.toml at repo root)
  • .github/workflows/rust-cli.yml — CI job for Rust builds
  • Phase 0 exit criteria: binary, provider spikes, smoke tests

Source documents (archived verbatim below)

  • docs/specs/oxagen-rust-cli/00-overview.md
  • docs/specs/oxagen-rust-cli/01-product-spec.md
  • docs/specs/oxagen-rust-cli/02-architecture.md
  • docs/specs/oxagen-rust-cli/03-plan.md
  • docs/specs/oxagen-rust-cli/04-benchmark-strategy.md
  • docs/specs/oxagen-rust-cli/05-risk-register.md

Document — 00-overview.md

Oxagen Rust CLI — Overview & Index

Status: proposed spec, not yet started. Owner: Mac Anderson. Linear: file one epic ticket (oxagen-v2 project, label agents+tech-debt) linking this directory, then sub-issues per phase in 03-plan.md.

What this is

A ground-up rebuild of the Oxagen CLI as oxagen-cli: a single static Rust binary, MIT/Apache-2.0 open source, with zero required dependency on oxagen.sh. It talks directly to whatever model provider the user configures — Anthropic, OpenAI, AWS Bedrock (incl. Model Garden), Google Vertex AI (incl. Model Garden), OpenRouter, Ollama, or any OpenAI-compatible endpoint — using the user's own keys (BYOK). It bakes in everything that makes today's TypeScript @oxagen/cli good (agent loop, tool set, code-graph context engine, REPL/TUI, fleet/multi-agent, memory) and removes everything that assumes an Oxagen account, billing, or platform round-trip. Target: #1 on SWE-bench Verified by >3 points over the next-best agentic coding CLI, at a fixed/pinned model.

This is a fork-and-diverge, not a fork-and-sync: oxagen-cli (Rust, OSS) and @oxagen/cli (TypeScript, platform-integrated, stays proprietary per the repo's LICENSE) become two separate products from day one of the port, sharing only ideas and, during migration, a golden-trajectory test corpus. The proprietary CLI is not deprecated — it keeps serving oxagen.sh customers who want the metered/managed experience, graph sync to the web app, org/ workspace commands, billing, plugins, etc. Those ~120 platform-bound commands (org, workspace, billing, plugin, document, image/video generation, MCP registry, automations — see apps/cli/GAPS.md) have no home in the OSS product and are deliberately left behind.

Documents in this set

DocContents
00-overview.mdThis file.
01-product-spec.mdMission, non-negotiables, feature parity matrix (keep/cut/rebuild), provider model, licensing, distribution, success metrics.
02-architecture.mdCrate layout, port/trait boundaries, data flow, on-disk formats, security model.
03-plan.mdPhased build plan (0→6), branch/worktree strategy, exit criteria per phase, effort estimates.
04-benchmark-strategy.mdHow we prove and defend the ">3pp #1 on SWE-bench" claim: harness, methodology, anti-p-hacking rules, best-of-N design, continuous leaderboard tracking.
05-risk-register.mdWhat can go wrong, mitigations, kill criteria.

TL;DR decisions

  1. Language: Rust, edition 2024, tokio async runtime, clap for CLI, ratatui for TUI.
  2. License: Apache-2.0 for the engine/tools crates, MIT for the CLI binary crate and public SDK/protocol crate — dual so either downstream license preference is satisfied (matches the Rust ecosystem norm: tokio, ratatui, rustls are all MIT/Apache-2.0 dual).
  3. No Oxagen account required, ever, for core agentic coding. Login/telemetry/graph-sync/memory-sync to oxagen.sh are strictly optional, additive, opt-in plugins — never on the critical path, never required for oxagen run "fix the failing test" to work with just ANTHROPIC_API_KEY set.
  4. Providers: first-class native adapters for Anthropic, OpenAI, AWS Bedrock (incl. Bedrock Model Garden / custom imported models), Google Vertex AI (incl. Vertex Model Garden), OpenRouter, Ollama/local OpenAI-compatible servers (LM Studio, vLLM, llama.cpp server). No Vercel AI Gateway dependency in the OSS binary — that was the platform-specific routing layer; direct provider SDKs only.
  5. Reuse strategy: port the spec, not the code (per the existing 04-rust-port.md). TS engine (packages/agent-engine) becomes the executable spec + golden-trajectory oracle during migration, then is retired for this product's purposes (the proprietary CLI keeps using it independently).
  6. Where it lives: new top-level directory crates/oxagen-cli/ in this monorepo initially (fastest to build/test against existing bench harness + CI), mirrored out to a public oxagen-cli GitHub repo via a one-way export script once Phase 3 lands (see 03-plan.md §6). It does not become a pnpm workspace member — it's a Cargo workspace living inside the pnpm/turbo monorepo, same pattern as any polyglot subtree, wired into CI as its own job.
  7. Distribution: cargo install oxagen-cli, Homebrew tap, prebuilt binaries (GitHub Releases, cargo-dist or cross + GH Actions for macOS/Linux/Windows × x86_64/arm64), and a curl | sh installer script. No npm package for the Rust binary (avoids Node dependency entirely — the whole point).

Spec — 01-product-spec.md

Oxagen Rust CLI — Product Spec

1. Mission

Build the fastest, most token-efficient, most capable open-source terminal coding agent — installable in one command, usable with any model provider's own keys, with no account, no telemetry-by-default, and no server dependency — and make it demonstrably #1 on SWE-bench Verified by more than 3 percentage points over the next-best publicly comparable agentic CLI at a fixed, identical worker model (methodology in 04-benchmark-strategy.md — this is a scaffold claim, not a model claim, and every number we publish says so).

2. Non-negotiables (binding for every phase)

  1. No phone-home requirement. oxagen run (the core one-shot/interactive coding loop) must complete a real task with zero network calls other than the one the user's configured model provider requires. No license check, no update ping (opt-in only, see §7), no mandatory account.
  2. BYOK, multi-provider, no gateway lock-in. The binary talks directly to provider APIs. Users bring their own ANTHROPIC_API_KEY / OPENAI_API_KEY / AWS credentials (SigV4, standard credential chain) / GCP credentials (ADC) / OpenRouter key / a local Ollama or OpenAI-compatible base URL. No Oxagen-operated routing layer sits between the user and their model calls.
  3. Open source, permissive license, no CLA-gated contributions trap. Apache-2.0 (engine/tools) + MIT (CLI/protocol) dual license, DCO-based contribution (git commit -s), no copyright assignment. Public repo, public issue tracker, public roadmap.
  4. Single static binary, sub-100ms cold start to first prompt render, no runtime dependency (no Node, no Python, no Docker required for the base product). musl static linking on Linux; universal or per-arch binaries on macOS; no dynamic OpenSSL dependency (use rustls).
  5. Feature-complete relative to what makes today's CLI good as a coding agent — not relative to its platform-integration surface. See the parity matrix in §5.
  6. Privacy by default. Telemetry, if present at all, is anonymous, aggregate, and opt-in (not opt-out — this inverts the current TypeScript CLI's opt-out default, deliberately, because an OSS tool with a phone-home-by-default violates the trust this project depends on). Code, prompts, file contents, file paths, and API keys are never transmitted to Oxagen infrastructure by the OSS binary, full stop — not even in aggregate/anonymized telemetry.
  7. #1 on SWE-bench Verified by >3pp, reproducible by a third party from the public repo with only a model API key, against the current best publicly documented comparable result at the time of the claim. See 04-benchmark-strategy.md for exact methodology, refresh cadence, and the rules that keep this claim honest as competitors move.

3. Target users

  • Individual developers who want a fast, scriptable, local-first coding agent and refuse to install Node/Python toolchains just to run a CLI.
  • Teams that want to self-host / air-gap (BYOK to their own Bedrock/Vertex tenancy, no third-party SaaS in the loop) — this is the AWS/GCP Model Garden requirement: enterprises with existing Bedrock/Vertex spend and compliance posture want their coding agent billed through their own cloud account. CI/CD pipelines that need a fast, deterministic, JSON-first agent CLI (SWE-bench-style automated fixing, PR review bots, release-note generation) without a Node cold-start tax.
  • OSS contributors who want to extend/embed the agent (crate-level API, not just a CLI binary) — oxagen-core and oxagen-tools must be usable as library crates by other Rust projects.

4. Provider model (BYOK, no gateway)

ProviderAuthNotes
AnthropicANTHROPIC_API_KEYDirect Messages API, streaming, native tool-use, extended thinking.
OpenAIOPENAI_API_KEYResponses API (streaming, tool-use, reasoning effort param).
AWS BedrockStandard AWS credential chain (env, profile, IMDS, SSO) + regionbedrock-runtime Converse/ConverseStream API — covers both native Bedrock models (Claude, Titan, Llama, Nova) and Bedrock Model Garden custom-imported models by ARN.
Google Vertex AIADC (GOOGLE_APPLICATION_CREDENTIALS or workload identity) + project/regionVertex generateContent/streaming — covers native Gemini and Vertex Model Garden (Llama, Mistral, Claude-on-Vertex, custom-deployed endpoints by endpoint ID).
OpenRouterOPENROUTER_API_KEYOne key, any vendor's model behind OpenRouter's routing — useful as a zero-setup on-ramp for users without direct provider accounts.
Ollama / local OpenAI-compatiblenone, or --base-urlvLLM, LM Studio, llama.cpp server, text-generation-inference — anything speaking the OpenAI chat/completions wire format. Fully offline capable.
Generic OpenAI-compatible--base-url + optional bearer tokenEscape hatch for any other vendor (Groq, Together, Fireworks, Mistral La Plateforme, DeepSeek, etc.) without a bespoke adapter.

Selection: oxagen config model set <provider>/<model-id> persists a default; --model <provider>/<model-id> overrides per-invocation; oxagen models list enumerates known model ids per configured provider (a small curated catalog, data-driven like today's models.json, not hard-coded per call site). Credential resolution order: CLI flag → env var → provider-native config (AWS profile / ADC file / ~/.config/oxagen/credentials.toml) → interactive prompt on first use (never silently fails with an opaque provider error).

No default model is billed through Oxagen. There is no oxagen login requirement anywhere on the core coding path. (An optional oxagen cloud login plugin may exist later purely for opt-in features like cross-device memory sync to oxagen.sh — never required, always visibly separate, off by default, and covered by its own explicit consent screen — but it is out of scope for the initial OSS release and is not part of this spec's success criteria.)

5. Feature parity matrix — keep / rebuild / cut

Derived from the TS CLI's actual command inventory (apps/cli/GAPS.md, apps/cli/README.md) and engine internals (packages/agent-engine, apps/cli/src/agent/**, apps/cli/src/runtime/**).

KEEP — core agentic coding loop (the product)

CapabilityTS source (reference)Rust target
Step-driver agent loop (evaluate→enhance→route→execute→judge→revise)packages/agent-engine/src/pipeline/index.ts, loop-driver.tsoxagen-core
Tool set: read_file (line numbers), write_file, edit_file (fuzzy-match failure feedback, replace_all), bash (middle-out truncation, signal-aware, timeout backstop), grep/glob (ripgrep-backed)packages/agent-engine/src/tools.tsoxagen-tools
Code-graph context engine: tree-sitter parse, symbol/import-edge index, semantic search, domain assistpackages/code-graph/src/*, apps/cli/src/daemon/code-graph/*, apps/cli/src/agent/context/*oxagen-graph (native tree-sitter, no WASM)
Model router (cost/tier-aware) + rate cardapps/cli/src/agent/model-router.ts, rate-card.tsoxagen-model
Multi-provider AgentAi port abstractionpackages/agent-engine/src/ports.tsoxagen-model::Provider trait
Best-of-N candidate generation + selection (test signal + diff-judge)docs/specs/cli-swe-bench/02-spec.md §5oxagen-pipeline
Evidence-based judge (diff + test-tail, judge≠worker)sameoxagen-pipeline
Fleet / multi-agent orchestration: worktree isolation, planner DAG, commit ledgerapps/cli/src/agent/fleet/*oxagen-fleet
Interactive REPL/TUI: streaming render, diff view, slash commands, HUDapps/cli/src/repl/*, apps/cli/src/tui/*oxagen-tui (ratatui)
On-device/local model runtime (GGUF via llama.cpp bindings)apps/cli/src/runtime/providers/on-device*.ts, runtime/provisioning/*oxagen-model::local (native llama-cpp-2/llama.cpp FFI, not a WASM bridge)
Memory (episodic recall/write, salience, promotion to rules) — local-only, no server round-tripapps/cli/src/agent/memory.ts, packages/engram/* (concepts, not the ClickHouse-backed impl)oxagen-core::memory backed by embedded SQLite/DuckDB, no ClickHouse dependency in OSS build
Workspace rules (.oxagen/rules/) — Tier-1 prompt injection + Tier-2 tool-gate guardapps/cli/src/rules/*oxagen-core::rules
Settings/hooks (Session/PreToolUse/PostToolUse)apps/cli/src/settings/*oxagen-core::hooks
Slash commands, skills (.md-defined)apps/cli/src/slash/*, ADR-008 skills-filesystem-firstoxagen-cli::slash, filesystem-first unchanged
MCP client (connect to external MCP servers as tools)apps/cli/src/mcp/client.tsoxagen-mcp (rmcp or hand-rolled client over the official MCP Rust SDK)
PR/CI monitor (watch a PR to green, offer auto-merge)apps/cli/src/lib/pr-monitor.ts, gh-pr.tsoxagen-fleet::pr_monitor (shells to gh CLI or uses GitHub REST directly)
Init / project scaffolding (.oxagen/ dir, rules seed)apps/cli/src/project/init.tsoxagen-cli::init
Config file + env var resolutionapps/cli/src/lib/config.tsoxagen-cli::config (TOML, ~/.config/oxagen/config.toml)
Trace/trajectory recording (JSONL, replay)apps/cli/src/agent/trace*.ts, verbose-log.tsoxagen-core::trace
`--output-format textjsonstream-json` machine-readable output

CUT — platform-bound, no home in an account-free OSS product

Everything whose entire purpose is talking to oxagen.sh: org.*, workspace.*, billing.*, plugin.* (marketplace/registry/credential commands), document.*/documents.* (server-side doc generation + PDF), image.*/video.*/svg.* (server-side media generation), agent mcp register/list (the Oxagen platform's MCP registry — connecting to external MCP servers as tools stays, see KEEP), agent task background * (server-managed background tasks), conversation.* (server-side chat history), automation.* (server-side scheduled triggers), api-key.* (Oxagen platform API keys), notifications.*, privacy export/erase (GDPR endpoints against Oxagen's own data store — not applicable, there is no Oxagen-held data), skill workspace list (server-synced skill catalog — filesystem-first skills stay), user preferences *, system install instructions (Oxagen MCP server connection instructions), telemetry's platform-side ingest route (v1/telemetry/usage) and its opt-out-default posture (inverted per non-negotiable #6 if kept at all), graph-sync-to-web-app (ADR-018), Vercel AI Gateway routing, streamAgentReply/metered billing path, Neo4j-backed cloud code-graph.

Rationale: these ~100+ commands exist to integrate the CLI with the Oxagen SaaS. An account-free OSS product has no SaaS to integrate with. Users who want that integration keep using @oxagen/cli (proprietary, unaffected by this project).

REBUILD DIFFERENTLY — same user value, different mechanism

TS mechanismWhy it can't carry over as-isRust replacement
Vercel AI Gateway model routingGateway is an oxagen.sh-operated proxyDirect per-provider SDK clients (oxagen-model), see §4
AI_GATEWAY_API_KEY credential resolutionSameProvider-native credential chains (env, AWS SDK default chain, GCP ADC, OpenRouter key, --base-url)
Login/OAuth+PKCE against oxagen.sh, ~/.config/oxagen/config.json sessionNo account to log intoNo login command in the base product; config file holds only provider keys/model defaults, never a session token
Telemetry to POST /v1/telemetry/usage (ClickHouse-backed, opt-out)No Oxagen ingest endpoint to call by defaultIf retained at all: opt-in, points at a public, documented, self-hostable ingest (or removed entirely for v1 — see 03-plan.md Phase 5 decision point)
Memory backed by @oxagen/engram (ClickHouse/DuckDB adapters tied to platform config)Platform-coupled storage adaptersEmbedded SQLite (via rusqlite) for episodic memory + rules; no ClickHouse dependency ships in the OSS binary
Code-graph sync to Neo4j (ADR-018, cloud graph)Cloud-only, requires the platformLocal-only oxagen-graph index (tree-sitter + local vector index, e.g. usearch or hnsw_rs), no server sync
MCP server hosted by Oxagen (mcp.oxagen.sh)N/A to a standalone binaryNot applicable — the CLI is an MCP client only in this product, connecting to whatever external MCP servers the user configures

6. Success metrics (definition of done for "v1.0")

MetricTargetHow verified
SWE-bench Verified resolve rate vs. best public comparable≥ +3.0 percentage points, same pinned modelbench/swe-bench harness (Rust-adapted, see 04-benchmark-strategy.md)
Cold start to first token< 150ms process start, < 100ms of that pre-networkhyperfine oxagen --version / instrumented startup trace
Binary size (static, stripped)< 40MB per platform targetCI artifact size check
Zero network calls with only a model key configured, no --telemetry flag0 calls other than the model APINetwork-namespace/strace-gated integration test
Test coverage (workspace-wide)≥ 85% line coverage on oxagen-core/oxagen-tools/oxagen-pipeline, ratchet toward 90cargo llvm-cov in CI
Golden-trajectory parity with the frozen TS spec (migration period only)100% byte-identical event stream on recorded inputsCI conformance suite, retired once the TS spec is fully ported
License scan0 GPL/AGPL/SSPL transitive dependenciescargo deny in CI
Distributioncargo install, Homebrew, curl | sh, GH Releases (4 OS/arch combos) all greenRelease CI job

7. Explicitly out of scope for v1.0

  • Windows-native TUI parity (ratatui supports Windows terminals reasonably well via crossterm; full parity is a stretch goal, not a v1 blocker).
  • Cloud memory/graph sync, any oxagen.sh integration (see CUT list) — may return later as an optional plugin crate, never in the base binary.
  • GUI/desktop app wrapper (Tauri, etc.) — CLI/TUI only.
  • Server/daemon mode beyond what's needed for the code-graph live index (ADR-016's daemon concept ports as an in-process background task or a short-lived local watcher, not a persistent network service).

Document — 02-architecture.md

Oxagen Rust CLI — Architecture

1. Design principles

  1. Ports, not concretions. The engine (oxagen-core) never imports a provider SDK, a filesystem call, or a terminal library directly. It drives through traits (Provider, Workspace, Memory, Trace, CodeGraph) — the same seam discipline as the TS engine's ports.ts, carried over directly (see packages/agent-engine/src/ports.ts for the shape being ported).
  2. No unsafe outside FFI boundaries (the local-model llama.cpp binding is the one legitimate exception; isolate it behind a narrow, fully-tested wrapper crate/module and document every unsafe block).
  3. Async everywhere I/O happens (tokio), sync/pure everywhere logic happens (the step-driver's decision logic, compaction, budget eviction, loop detection are plain synchronous functions over owned data — easy to property-test, no Send/Sync ceremony needed).
  4. Serde-first. Every cross-boundary type (provider request/response, tool call/result, trace event, protocol message) derives Serialize/Deserialize and is versioned. This is what makes golden- trajectory replay and future protocol stability possible.
  5. Fail loud, recover gracefully. Provider errors, tool errors, and malformed model output are typed (thiserror), never panic! in the hot path; the step-driver treats retryable vs. terminal errors distinctly (mirrors TS Phase-1 retry/backoff design in docs/specs/cli-swe-bench/03-plan.md).

2. Crate layout (Cargo workspace)

crates/
├── oxagen-protocol/    # serde types shared by every crate: events, tool
│                        # schemas, trace records, provider request/response
│                        # envelopes. Zero logic, zero I/O. The stability
│                        # contract of the whole workspace.
├── oxagen-core/         # The step-driver: one model call per step, message
│                        # accumulation, retry+backoff, context compaction,
│                        # tool-output budget+eviction, loop detection,
│                        # malformed-call repair, rules engine, hooks engine,
│                        # local SQLite-backed memory. NO I/O of its own —
│                        # drives entirely through the `Provider`/`Workspace`/
│                        # `Memory`/`Trace` traits from oxagen-protocol.
├── oxagen-tools/        # Workspace trait impl: fs (read/write/edit with
│                        # fuzzy-match diagnostics), ripgrep-backed grep/glob
│                        # (shells to `rg` if present, falls back to an
│                        # in-process `grep` crate walk), diff (`similar` or
│                        # `git2`), process exec with real process-group
│                        # signal handling (`nix` + `tokio::process`).
├── oxagen-model/        # Provider trait + concrete adapters: Anthropic,
│                        # OpenAI, Bedrock (aws-sdk-bedrockruntime), Vertex
│                        # (hand-rolled REST client over `reqwest`+`hyper`,
│                        # or `google-cloud-rust` if mature enough at build
│                        # time), OpenRouter, generic OpenAI-compatible
│                        # (covers Ollama/vLLM/LM Studio), local GGUF via
│                        # llama.cpp FFI. Owns per-vendor streaming/SSE
│                        # parsing, tool-call schema translation, reasoning-
│                        # effort mapping, retry-on-transport-error.
├── oxagen-graph/        # Code-graph context engine: tree-sitter parsers
│                        # (native crate per language, not WASM), symbol +
│                        # import-edge index, local embedding + vector index
│                        # (candle or ONNX Runtime for embeddings; `hnsw_rs`/
│                        # `usearch` for the vector index), persisted to a
│                        # local SQLite/DuckDB file per workspace (no server).
├── oxagen-pipeline/     # evaluate → enhance → route → execute → judge →
│                        # revise orchestration; verifyWork evidence gate;
│                        # best-of-N candidate generation + selection.
├── oxagen-fleet/        # Multi-agent: planner DAG, git-worktree isolation,
│                        # commit ledger (SQLite), PR/CI monitor (shells to
│                        # `gh` or hits GitHub REST via `octocrab`).
├── oxagen-mcp/          # MCP *client* — connect to external MCP servers
│                        # (stdio + streamable-http transports) and expose
│                        # their tools into the engine's tool registry.
├── oxagen-tui/          # ratatui-based interactive REPL: streaming render,
│                        # diff view, slash-command menu, HUD, mouse
│                        # selection — maps 1:1 onto oxagen-protocol's event
│                        # vocabulary so it never touches the engine directly.
└── oxagen-cli/          # `clap`-based command tree; the actual `oxagen`
                         # binary. Wires config, credential resolution, one-
                         # shot / interactive / fleet entrypoints, `--output-
                         # format text|json|stream-json`, init/scaffolding.

Each crate publishes independently to crates.io once stable (oxagen-core and oxagen-tools are useful standalone to other Rust agent projects — this is deliberate, matches non-negotiable #3 in the product spec about library usability).

3. Core traits (the port boundary)

Sketch (final signatures land during Phase 1 implementation; this fixes the shape, ported directly from packages/agent-engine/src/ports.ts):

// oxagen-protocol
pub trait Provider: Send + Sync {
    async fn stream(&self, req: ModelRunRequest) -> Result<ModelStream, ProviderError>;
    async fn generate_object<T: DeserializeOwned>(&self, req: ObjectRunRequest) -> Result<ObjectRunResult<T>, ProviderError>;
}

pub trait Workspace: Send + Sync {
    async fn read_file(&self, path: &Path, range: Option<LineRange>) -> Result<String, ToolError>;
    async fn write_file(&self, path: &Path, content: &str) -> Result<(), ToolError>;
    async fn edit_file(&self, path: &Path, old: &str, new: &str, replace_all: bool) -> Result<EditOutcome, ToolError>;
    async fn exec(&self, cmd: &str, timeout: Duration, signal: Option<CancellationToken>) -> Result<ExecOutcome, ToolError>;
    async fn grep(&self, pattern: &str, opts: GrepOpts) -> Result<Vec<GrepMatch>, ToolError>;
    async fn glob(&self, pattern: &str) -> Result<Vec<PathBuf>, ToolError>;
    async fn diff(&self) -> Result<String, ToolError>;
}

pub trait Memory: Send + Sync {
    async fn recall_context(&self) -> Result<String, MemoryError>;
    async fn remember(&self, kind: &str, content: serde_json::Value, status: Option<&str>) -> Result<(), MemoryError>;
}

pub trait CodeGraph: Send + Sync {
    async fn query(&self, req: GraphQuery) -> Result<GraphResult, GraphError>;
}

pub trait Trace: Send + Sync {
    fn record(&self, event: TraceEvent);
}

oxagen-core::Engine::run_turn(providers: &dyn Provider, workspace: &dyn Workspace, memory: &dyn Memory, graph: &dyn CodeGraph, trace: &dyn Trace, ...) is the single entrypoint every caller (one-shot CLI, interactive TUI, fleet worker, library consumer) drives through. This is the direct Rust analog of runTurn/runCodingAgent in packages/agent-engine/src/pipeline/index.ts.

4. Event vocabulary (protocol)

Ported from the existing boundary spec (docs/specs/cli-swe-bench/04-rust-port.md §"Boundary"), now internal trait-boundary events rather than a cross-process JSON-over-stdio protocol (that transport was a migration-period device; the shipped product is a single process, so events are plain Rust enum variants flowing over a tokio::sync::mpsc channel from oxagen-core to whichever renderer (oxagen-tui or the JSON serializer in oxagen-cli) is listening):

pub enum AgentEvent {
    Stage { name: String },
    Text { delta: String },
    Reasoning { delta: String },
    ToolStart { call_id: String, name: String, input: serde_json::Value },
    ToolResult { call_id: String, output: ToolOutput, duration_ms: u64 },
    FileChange { path: PathBuf, kind: FileChangeKind },
    Retry { attempt: u32, reason: String },
    Compaction { before_tokens: u64, after_tokens: u64 },
    JudgeVerdict { passed: bool, evidence: JudgeEvidence },
    Commit { sha: String, message: String },
    Pr { url: String, status: PrStatus },
    Complete { result: TurnResult },
    Error { error: EngineError, retryable: bool },
}

--output-format stream-json is a serde_json serialization of this exact enum, one line per event — giving external tooling (CI scripts, dashboards, the bench/swe-bench harness) a stable, versioned machine interface for free.

5. On-disk layout

~/.config/oxagen/
├── config.toml           # provider defaults, model aliases, telemetry opt-in flag
└── credentials.toml       # optional: provider keys (mode 0600), only if the user
                            #   chooses file storage over env vars / native chains

<workspace>/.oxagen/
├── rules/                 # Tier-1/Tier-2 workspace rules (.md), unchanged format
├── skills/                # skill.md files, unchanged format (ADR-008)
├── memory.db               # SQLite: episodic memory, salience, rule-promotion candidates
├── graph.db                 # SQLite/DuckDB: code-graph symbol/edge/embedding index
├── trace/*.jsonl           # per-run trajectory logs
└── ledger.db                # SQLite: fleet commit ledger (hash/branch/task/trace/files)

No global daemon, no background network listener. The code-graph "daemon" concept (ADR-016) becomes an in-process incremental indexer with an optional filesystem-watch task (notify crate) for interactive sessions — started and stopped with the CLI process, not a persistent system service.

6. Security model

  • Credentials never logged, never included in trace/trajectory JSONL (redact by type, not by best-effort string matching — the credential resolver returns a SecretString-wrapped value that intentionally has no Display).
  • edit_file/write_file/exec respect a workspace-root jail by default (no path traversal outside the initialized project root without an explicit --unsafe-full-fs escape hatch, off by default) — this is new relative to the TS CLI and should be flagged in the risk register as a behavior change worth a migration note.
  • exec timeout + process-group kill is native (nix::sys::signal::killpg and Windows job objects via windows-sys where applicable) — closes the TS CLI's documented bash-process-group leak on abort (GAPS.md/01-gap-audit.md P1).
  • Dependency policy: cargo deny in CI enforces license allowlist (no GPL/ AGPL/SSPL transitively) and a security-advisory check (cargo audit/ RustSec) on every push.

7. Why this repo, then a mirror (not day-one public repo)

Building inside oxagen-platform/crates/oxagen-cli first — not a brand-new public repo — because: (a) the existing bench/swe-bench + bench/terminal- bench Harbor harness, CI, and ClickHouse eval dashboard already exist here and are the fastest way to get a real resolve-rate number during development; (b) the golden-trajectory oracle is the TS engine already in this tree; (c) it keeps one CI, one review process, one place Mac's other sessions can see the work in flight (per this repo's own operating-mode rules). Once Phase 3 exit criteria are met (native bench parity, own CI green, no dependency on the TS bench harness for day-to-day dev), a one-way export script (tools/scripts/export-oxagen-cli.sh) splits crates/ oxagen-cli/ history into the public oxagen-cli GitHub repo via git subtree split (preserves commit history for the OSS project), and that public repo becomes the source of truth going forward — the monorepo copy is deleted, not kept as a second copy to maintain.

Plan — 03-plan.md

Oxagen Rust CLI — Build Plan (phased)

Branch/worktree per this repo's operating mode: cut feat/oxagen-rust-cli from a fresh main, work in git worktree add ../oxagen-rust-cli -b feat/oxagen-rust-cli (this is unambiguously a "large body of work" per CLAUDE.md), commit+push frequently, open a draft PR immediately after the Cargo workspace skeleton lands (Phase 0 exit). Each phase below is sized to land as its own PR (or a small stack of PRs) against that feature branch, or directly against main once the crate exists and is gated in CI — team's call at Phase 0 exit based on how disruptive a long-lived branch feels.

Sub-issue this in Linear as one epic (oxagen-v2 project) with one sub-issue per phase (7 phases → 7 sub-issues, further split 3–6 ways within a phase if a single dispatched subagent can't reasonably carry it). Assignee: Mac Anderson. Labels: agents, tech-debt, plus ci/infra where the phase is mostly tooling.

Phase 0 — Workspace skeleton + provider spike (prove the riskiest bet first)

Goal: a cargo build that produces a binary that can stream one turn against Anthropic and against Bedrock, with zero engine logic — pure plumbing risk retirement before investing in the step-driver.

  1. Cargo workspace scaffold: all 9 crates from 02-architecture.md §2 as empty stubs with correct inter-crate dependency edges (oxagen-cli depends on everything; oxagen-protocol depends on nothing internal).
  2. oxagen-protocol: AgentEvent, ModelRunRequest/ModelStream, ToolCall/ToolOutput — the types from 02-architecture.md §3–4, with serde derives and unit tests for round-trip (de)serialization.
  3. oxagen-model spike: Anthropic adapter (direct HTTP + SSE parse via reqwest + eventsource-stream or hand-rolled) and Bedrock adapter (aws-sdk-bedrockruntime, ConverseStream) — both implementing Provider, both proven against a real API key with a hardcoded "say hello and call a fake tool" smoke test. This retires the two biggest unknowns (raw SSE parsing quality vs. an official AWS SDK) before Phase 1 commits to a design.
  4. CI: cargo fmt --check, cargo clippy -D warnings, cargo test, cargo deny check, cargo audit as a new GitHub Actions job (.github/workflows/rust-cli.yml), triggered only on crates/** changes (mirrors how bench/web is excluded from unrelated CI per existing conventions) — do not let this job block unrelated PRs.
  5. Push the branch, open the draft PR now, per operating mode.

Exit: cargo run -p oxagen-cli -- --version works; both provider spikes stream a real response in a manual smoke test (documented, not yet automated E2E); CI job green on the skeleton.

Phase 1 — oxagen-tools (fs/exec/grep/glob/diff)

Highest speed win, lowest logic risk, easiest to conformance-test against the TS tool set's exact behavior (packages/agent-engine/src/tools.ts).

  1. read_file: line-numbered output (cat -n-style), range support, size cap.
  2. write_file / edit_file: exact-match edit with fuzzy-match failure diagnostics (closest-line search via Levenshtein — port closestLine/similarity/occurrenceLines/describeEditFailure from tools.ts line-for-line logic, replace_all option.
  3. exec: tokio::process::Command, process-group creation (nix::unistd:: setsid or setpgid), timeout backstop per the TS toolBackstopMs table, real signal-based kill on abort/timeout (closes the documented bash leak), middle-out (head+tail) output truncation.
  4. grep/glob: shell to rg/fd when present on $PATH (fast path); pure-Rust fallback (grep + ignore crates, which already respect .gitignore — this is a Python-repo win vs. the TS JS-walker: no bespoke ignore-list needed, ignore crate handles it natively).
  5. diff: git2 (libgit2 bindings) for tracked-file diffs; synthetic --no-index-equivalent diff for untracked files (port the untracked-file fix from the TS workspace.ts).
  6. Conformance tests: for every TS tools.test.ts / tools.extra.test.ts case, an equivalent Rust test asserting the same tool-call → same observable output shape (not byte-identical strings necessarily, but same semantic outcome: same error class, same truncation boundary behavior).

Exit: oxagen-tools usable standalone (cargo test -p oxagen-tools green, ≥85% coverage); a tiny hand-written harness proves fs/grep/exec against a fixture repo including a Python fixture (validates the ignore-set win).

Phase 2 — oxagen-model (full provider matrix) + oxagen-core step-driver

The score-critical phase — same reasoning as the TS Phase 1 (docs/specs/cli-swe-bench/03-plan.md Phase 1), now in Rust from the start rather than retrofitted.

  1. Round out oxagen-model: OpenAI, Vertex AI, OpenRouter, generic OpenAI- compatible (covers Ollama/vLLM/LM Studio in one adapter), local GGUF via llama-cpp-2 bindings (native, replacing the TS node-llama-cpp bridge — should be strictly faster to first token, no N-API marshaling overhead).
  2. Credential resolution chain per §4 of 01-product-spec.md: env → CLI flag → AWS default credential chain / GCP ADC → credentials.toml → interactive prompt. Unit tests per provider per resolution source.
  3. oxagen-core step-driver: one model call per step, explicit message accumulation, AgentEvent emission at every step boundary. This is the direct Rust port of the TS Phase-1 step-driver design — build it as a step-driver from day one (the TS version had to retrofit this onto a monolithic streamText call; Rust has no such legacy to work around).
  4. Retry+backoff (jittered exponential, retryable-error classification per provider — 429/5xx/transport vs. 4xx-terminal), resumes from last completed step.
  5. Compaction: token estimator (tiktoken-compatible via tiktoken-rs for OpenAI-family, provider-specific estimators elsewhere), ~80%-of-window trigger, summarize-old-keep-recent strategy, stable system-prefix preserved for prompt caching.
  6. Global tool-output budget + eviction (oldest-bulky-first, one-line stub replacement), loop detection (N identical failing calls → nudge, M → structured failure), malformed tool-call repair.
  7. Rules engine (.oxagen/rules/ Tier-1 prompt injection + Tier-2 tool-gate guard) and hooks engine (Session/PreToolUse/PostToolUse) — ported directly from apps/cli/src/rules/* and apps/cli/src/settings/* semantics.
  8. Local memory: rusqlite-backed episodic store, salience scoring, rule- promotion candidate surfacing — same concepts as apps/cli/src/agent/ memory.ts / packages/engram, new storage (no ClickHouse/DuckDB-adapter dependency; SQLite is the whole point of "no server").
  9. Property tests: compaction never drops a still-referenced tool result; budget eviction is monotonic; retry never re-executes a non-idempotent tool call that already completed (state-machine test).

Exit: a synthetic 200-step turn (mocked Provider returning scripted responses incl. injected 429s, a stream drop, and simulated context pressure) survives end-to-end, matching the TS Phase-1 exit bar (docs/specs/cli-swe-bench/03-plan.md Phase 1 exit) but native from the start; cargo llvm-cov ≥85% on oxagen-core.

Phase 3 — oxagen-graph + oxagen-pipeline + oxagen-mcp

  1. oxagen-graph: native tree-sitter parsers per language (start with the set the TS code-graph already supports; prioritize fixing the TS gap where Python import-edge resolution is thin — this is a chance to do Python right from the start, not a port of a known limitation), local embedding (candle-based small model or ONNX Runtime) + vector index (hnsw_rs or usearch), persisted per-workspace SQLite/DuckDB.
  2. oxagen-pipeline: evaluate→enhance→route→execute→judge→revise orchestration over oxagen-core::Engine; evidence-based judge (diff + test-tail, judge≠worker enforced via a distinct Provider instance); best-of-N (--candidates N) generation + selection (test-outcome + diff-judge-panel).
  3. oxagen-mcp: MCP client — stdio + streamable-http transports, tool discovery, registration into oxagen-core's tool registry alongside the native tool set.
  4. Golden-trajectory conformance harness: record TS-engine trajectories on the same fixed tasks (small deterministic fixture set + a handful of real SWE-bench instances with recorded model responses for determinism), replay through the Rust stack, assert event-stream parity per docs/specs/cli-swe-bench/04-rust-port.md's existing conformance design. This is the point where the "port the spec, not the code" strategy pays off — the TS engine's tests become this suite's oracle.

Exit: golden-trajectory replay green in CI on the fixed fixture set; a real best-of-N run on a small sample beats single-shot; oxagen-mcp connects to at least one real external MCP server (e.g. a filesystem or GitHub MCP server) end to end.

Phase 4 — oxagen-fleet + oxagen-tui + oxagen-cli

  1. oxagen-fleet: planner DAG, git-worktree isolation (isolate-by-default — fixing the TS default-unsafe-concurrency finding from 01-gap-audit.md directly, not carrying the bug forward), commit ledger (SQLite), PR/CI monitor (shells to gh CLI first for simplicity, octocrab if a native GitHub client proves worth the dependency weight).
  2. oxagen-tui: ratatui interactive REPL — streaming render, diff view, slash-command menu, HUD (rendered from day one, not built-then-orphaned as happened in TS per the gap audit), mouse selection. Maps onto AgentEvent — never touches oxagen-core internals directly.
  3. oxagen-cli: clap command tree — run (one-shot), no-subcommand (interactive TUI, matches today's default-to-interactive UX), agents/fleet entrypoint (headless-capable from day one — fixes the TS TTY-lock P0 finding), init, config, models list/set, --output- format text|json|stream-json, --max-steps, credential setup wizard.
  4. Distribution scaffolding: cargo-dist config for GH Releases across macOS (x86_64/arm64), Linux (x86_64/arm64, musl static), Windows (x86_64); Homebrew tap formula; curl | sh installer script.

Exit: a person with only ANTHROPIC_API_KEY set can curl | sh install and run oxagen run "fix the failing test in this repo" against a real small repo, interactively and headlessly, with --output-format json producing a clean result envelope; fleet runs headless in CI.

Phase 5 — Bench proof (the #1-by->3pp claim)

Full methodology lives in 04-benchmark-strategy.md; this phase is the execution against it.

  1. Adapt bench/swe-bench's Harbor adapter to install/run the Rust binary instead of (or alongside) the TS bundle — the adapter interface (install/ run/patch-capture) is harness-side already generic per its own README; confirm and adjust oxagen_terminal_bench.oxagen_agent for a native binary instead of a Node bundle path.
  2. Smoke: 1 instance end-to-end, non-empty patch, cost line parsed.
  3. Small mixed sample (~20 instances); baseline resolve rate + failure buckets from trajectories (same iterate-on-failure-buckets discipline as the existing TS plan's Phase 4).
  4. Full SWE-bench Verified run, oxagen-cli vs. the current best publicly documented comparable agent, same pinned model, via compare.sh- equivalent tooling (already exists in bench/swe-bench, needs the Rust-agent wiring from step 1).
  5. Best-of-N tuning pass — this is the primary lever expected to deliver the

    3pp margin, per 01-product-spec.md §1 and the existing TS spec's own framing (docs/specs/cli-swe-bench/02-spec.md §5).

  6. Publish methodology + raw results (bench/web dashboard already has the schema/plumbing — oxagen.eval.v1) with every fairness caveat from the existing bench/swe-bench/README.md "Fairness & methodology" section carried forward verbatim into the Rust project's own docs.

Exit: a reproducible, documented run showing resolve rate ≥ +3.0pp over the comparison target at a fixed model, with raw trajectories published for third-party audit. If the target is missed, this phase does not "ship anyway" — see 05-risk-register.md for the kill/pivot criteria.

Phase 6 — Open-source the repo

  1. cargo deny/cargo audit/license-header lint fully green; every dependency's license reviewed against Apache-2.0/MIT compatibility.
  2. git subtree split crates/oxagen-cli/ history into a new public oxagen-cli GitHub repo (preserves commit history, per 02-architecture.md §7). Set up its own CI (mirrors the internal job, now public-facing).
  3. Public docs site (README, CONTRIBUTING with DCO instructions, security policy, architecture doc adapted from 02-architecture.md).
  4. Public issue tracker seeded with the known-gaps/risk items from 05-risk-register.md that are acceptable to ship with (labeled known-limitation), not hidden.
  5. Announce with the benchmark results from Phase 5, methodology and raw data linked, comparison framing identical to the existing bench/swe-bench fairness rules (never present a number without its methodology attached).
  6. Delete crates/oxagen-cli/ from this monorepo once the public repo's CI and release pipeline are proven for one full release cycle — do not maintain two copies.

Exit: public repo live, installable by a stranger with no access to this monorepo, cargo install oxagen-cli and curl | sh both work from a clean machine, benchmark claim published with full methodology.

Cross-cutting notes

  • Never run a full workspace cargo test as a substitute for the narrowest proving command — same spirit as this repo's "never run all tests" rule for the TS workspace; use cargo test -p <crate> or cargo nextest run -p \<crate> \<test-name> while iterating, full workspace test only in CI / pre-merge.
  • Every phase leaves the branch green and pushed. Commit at every meaningful sub-step (per crate, per trait impl, per test file), not just at phase boundaries.
  • Phases 1–2 are the score-critical path (mirrors the TS plan's own framing) — deepest review, most tests, no shortcuts. Phases 3–4 can partially parallelize across subagents once the Phase 2 trait surface is stable (dispatch oxagen-graph and oxagen-mcp in parallel; they don't share files). Phase 5 cannot start meaningfully before Phase 2's exit bar (compaction/retry) — earlier bench numbers are noise from avoidable harness failures, exactly as the existing TS plan notes.
  • Effort estimate (rough, for Linear sizing): Phase 0: S. Phase 1: M. Phase 2: XL (the score-critical crux, budget the most review here). Phase 3: L. Phase 4: L. Phase 5: M (mostly compute time + iteration, not code volume). Phase 6: S.

Document — 04-benchmark-strategy.md

Oxagen Rust CLI — Benchmark Strategy ("#1 by >3pp" claim)

This document defines exactly what we will measure, how, and the rules that keep the claim honest — reusing and tightening the fairness discipline already established in bench/swe-bench/README.md ("Fairness & methodology").

1. The claim, precisely

"oxagen-cli resolves ≥3.0 percentage points more of SWE-bench Verified than the best publicly documented comparable agent, at the same pinned worker model, measured by the official Harbor/SWE-bench verifier — not self-graded."

Two things this claim is not:

  • It is not "oxagen's base model is better" — it is a scaffold-quality claim at a fixed model, exactly the distinction bench/swe-bench/README.md already draws for the existing TS harness.
  • It is not a claim against every number on the public leaderboard (swebench.com) indiscriminately — leaderboard entries use different models, prompts, task subsets, and retry budgets. We compare against the best entry we can run ourselves under controlled, identical conditions (compare.sh-style), and separately cite the public leaderboard rank only with explicit labeling of which number is which — never merged in one table without that label.

2. Comparison target selection

At the time of the Phase 5 run, pick the comparison target as:

  1. The highest-resolve-rate agent we can install and run ourselves through Harbor (Claude Code, Codex CLI, Aider, OpenHands, Gemini CLI, SWE-agent — whatever Harbor supports natively at that time, per compare.sh's COMPETITORS list), on the same pinned model as oxagen-cli's run.
  2. If the single best public leaderboard number (swebench.com) at a comparable model class is higher than what we can reproduce locally with any Harbor-supported agent, we do not simply claim victory over the local number and ignore the leaderboard — we either (a) attempt to reproduce that leaderboard entry's public harness ourselves if one exists, or (b) explicitly caveat the published claim as "vs. the best locally-reproducible comparison; leaderboard entry X reports Y% under different conditions (model/harness/subset), see methodology." Never silently drop an inconvenient number.
  3. The >3pp margin must hold against both the best locally-reproduced competitor run and, where directly comparable (same model, same full Verified set, no undisclosed retry budget), the best leaderboard entry.

3. Fixed variables (controlled comparison)

Per run, hold constant across oxagen-cli and every competitor:

  • Dataset: swe-bench/swe-bench-verified (official 500-instance set), full set for the headline claim — not Lite, not a subsample (subsample results may be published as directional/early signal but never as the headline number).
  • Worker model: one pinned model id, passed via each agent's native model-pin flag (mirrors OXAGEN_MODEL_SLUG passed to -m in the existing compare.sh). Run the claim at more than one model tier if resources allow (e.g. a mid-tier and a frontier-tier model) to show the margin is not an artifact of one model's quirks.
  • Verifier: the official Harbor/SWE-bench verifier only — the agent never sees or influences the verifier, exactly as today's harness guarantees (bench/swe-bench/README.md §"What this measures").
  • Attempts per instance: N_ATTEMPTS=1 for the headline single-shot number; best-of-N numbers are reported as a clearly separate row (--candidates N), never blended into the single-shot claim.
  • Concurrency / hardware: same container class, same N_CONCURRENT, documented in the published methodology (wall-clock comparisons are secondary to resolve-rate but must also be reported honestly per instance where feasible).

4. What's allowed to differ (and must be disclosed)

  • Prompt engineering, tool design, context-engineering (code-graph), retry/compaction policy, best-of-N selection strategy — this is the scaffold being benchmarked; it's expected to differ and is the entire point.
  • Provider routing mechanics (oxagen-cli talks directly to the provider; competitors may route through their own gateway) — disclosed, not hidden, and does not affect the verifier's pass/fail decision.

5. Levers to earn the margin (ranked by expected impact)

  1. Best-of-N with evidence-based selection (oxagen-pipeline, Phase 3): N independent trajectories, selected by agent-authored repro-test outcome + existing targeted-test signal + a diff-level judge panel. Historically the single biggest lever for resolve-rate at fixed cost per the existing TS spec's own framing (docs/specs/cli-swe-bench/02-spec.md §5) — the Rust port inherits this design and should tune N against a cost/resolve-rate curve, not just maximize N blindly.
  2. Context compaction that never wedges (oxagen-core, Phase 2): a context-overflow failure is a scaffold bug, not a hard task — every instance lost to context_length_exceeded is a free percentage point on the table. Zero-tolerance target: 0 instances fail purely from context overflow in the final run.
  3. Retry/backoff on transient provider errors: same logic — a 429 or transient 5xx killing a turn is a scaffold failure, not a model failure. Target: 0 instances fail purely from an unretried transient error.
  4. Code-graph-informed context (oxagen-graph, Phase 3): graph-first navigation over blind grep on unfamiliar repos, including the Python-import-edge fix noted as a known TS gap — likely the second- biggest lever after best-of-N on repos the model hasn't memorized.
  5. Tool precision (oxagen-tools, Phase 1): fuzzy-match edit-failure feedback, ripgrep-backed search with correct .gitignore/Python-ignore handling, middle-out truncation that preserves failing-test tails — each individually small, cumulatively meaningful across 500 instances.
  6. Loop detection + malformed-call repair: prevents a small number of instances from silently burning their entire step budget on a repeating failure with zero forward progress.

6. Anti-p-hacking rules (binding)

  1. No test-set leakage. Never let the agent or any tuning loop see FAIL_TO_PASS/PASS_TO_PASS test names or SWE-bench metadata beyond what the official harness exposes to any agent (the issue text + repo state). Tuning best-of-N selection heuristics against the verifier's own pass/fail signal on a held-out dev subset, not the Verified set itself, before the final headline run.
  2. Pre-register the run. Before executing the full-set headline run, commit (to the branch/PR, publicly once open-sourced) the exact config: model id, N_ATTEMPTS, --candidates value, prompt profile, code-graph on/off, pipeline on/off. No post-hoc cherry-picking of the best of several full-set runs — if a full run under-performs, iterate on the scaffold (with a fresh dev-subset validation), then re-run the full set again with a new pre-registered config, and report all runs' configs if more than one full-set run is published.
  3. Publish raw trajectories for the headline run (bench/web's oxagen.eval.v1 schema already supports this) so a third party can audit individual instance outcomes, not just the aggregate percentage.
  4. Re-run competitors under the same conditions, not cite their own self-reported numbers, wherever a Harbor adapter for them exists — this is what compare.sh already guarantees for the TS harness and must carry over unchanged for the Rust harness.
  5. Refresh cadence. Competitors ship new agents/scaffolds too. Re-run the comparison at least quarterly (or whenever a competitor publicly claims a new SWE-bench Verified state-of-the-art) and update the public claim — a stale ">3pp as of six months ago" claim left unrefreshed is a credibility risk, not a badge.

7. Reporting format

Every published number carries, inline, not in a footnote:

  • Dataset + subset size (e.g. "500/500 SWE-bench Verified").
  • Pinned model id.
  • Attempts per instance (1 for single-shot; N for best-of-N, labeled).
  • Harness + verifier (Harbor + official SWE-bench verifier).
  • Date of run + git SHA of the oxagen-cli build used.
  • Link to raw trajectories.

Table format mirrors bench/web's existing dashboard conventions — reuse that infrastructure rather than building a second one.

Document — 05-risk-register.md

Oxagen Rust CLI — Risk Register

#RiskLikelihoodImpactMitigationKill/pivot trigger
R1Porting a moving target — TS engine keeps changing under the Rust port, invalidating golden trajectories mid-migration.Medium (TS CLI is actively developed by parallel sessions per this repo's own operating model)High — wasted reworkFreeze/tag the TS spec (git tag cli-spec-freeze-vN) before Phase 3's conformance work starts; any TS spec change after the freeze goes through TS first, re-record goldens, then ported. Document the frozen tag in 03-plan.md Phase 3 kickoff commit.If TS spec churn rate makes freezing infeasible for >2 sprints, abandon TS-parity-first and design the Rust engine directly from 01-product-spec.md's KEEP list instead — the product spec is stable even if the TS implementation isn't.
R2Vertex AI Rust client immaturity — no first-class official Rust SDK for Vertex AI as of writing; hand-rolled REST client carries maintenance burden and drift risk against Google's API surface.MediumMediumBuild a thin, well-tested REST adapter (reqwest + typed request/response structs) scoped to exactly the generateContent/streaming + Model Garden endpoint surface needed; do not attempt full Vertex API coverage. Re-evaluate google-cloud-rust maturity at Phase 2 kickoff — adopt if it covers streaming Gemini + Model Garden by then.If Vertex integration consistently breaks on Google API changes with no upstream Rust SDK maturing within two quarters, de-scope Vertex to "community-maintained adapter, not core-team-guaranteed" in the product spec rather than blocking the release on it.
R3Local GGUF (llama.cpp FFI) unsafe surface — the one legitimate unsafe boundary in the workspace; a memory-safety bug here undermines the "safer" pitch of the whole Rust rewrite.Low-MediumHigh (reputational — this is a security-conscious OSS audience)Isolate behind a narrow wrapper module, exhaustive tests, prefer a maintained binding crate (llama-cpp-2) over hand-rolled FFI, run cargo fuzz against the wrapper's public entrypoints, document every unsafe block per architecture doc §1.If the chosen binding crate is abandoned/unmaintained and no fork is viable, drop native on-device support from v1.0 (still ship remote-provider BYOK; on-device becomes a fast-follow rather than a launch blocker).
R4Resolve-rate parity gap between TS and Rust engines — subtle behavior differences (compaction thresholds, retry classification, tool-output truncation boundaries) cause the Rust engine to underperform the TS engine's already-measured baseline, missing the >3pp target.MediumHigh — the headline claim depends on thisGolden-trajectory conformance suite (Phase 3) catches behavioral drift before any bench run; Phase 5's small-sample run (~20 instances) catches resolve-rate drift cheaply before the full 500-instance run; iterate on failure buckets exactly as 03-plan.md Phase 5 specifies.If the small-sample run shows the Rust engine measurably behind the TS baseline after one full iteration pass, do not proceed to the full-set headline run — return to Phase 2/3 hardening. The >3pp claim is never published against a full run known to under-perform a cheaper diagnostic.
R5Best-of-N cost blowup — the primary lever for the margin (best-of-N) multiplies token spend by N; if N is tuned purely for resolve-rate without a cost lens, the "efficient" pillar of the product spec (§6 token-efficiency metric) is undermined by the same feature that wins the benchmark.MediumMediumPublish a cost/resolve-rate curve (not just a single N), let users tune N via --candidates, default N conservatively (e.g. 1–3) rather than defaulting to whatever N won the benchmark headline.N/A — this is a design discipline, not a stop-ship risk; enforced via code review on the Phase 3 oxagen-pipeline PR (does the default N ship with a cost justification comment, per this repo's engineering-policy conventions).
R6Workspace-root jail is a behavior change vs. the TS CLI — the new default-on path jail (architecture doc §6) could break legitimate workflows the TS CLI silently allowed (e.g. editing a file outside the repo root via a monorepo-relative symlink).LowLow-MediumDocument the change prominently in release notes and the product spec; ship the --unsafe-full-fs escape hatch from day one, not as a fast-follow; add an integration test for the exact "legitimate symlink out of root" case before calling this policy final.If early adopters report the jail breaking common legitimate workflows (not just a security-theater case), relax the default to a warn-not-block posture for v1.0 and revisit for v1.1.
R7Open-sourcing exposes internal architecture/roadmap signals to competitors — a public oxagen-cli repo reveals prompt design, tool schemas, and the exact best-of-N/judge mechanics that constitute the competitive moat this project is trying to build.MediumMediumAccepted risk, explicit tradeoff of the "open source" non-negotiable (product spec §2.3) — the bet is that OSS trust/adoption/contribution velocity outweighs the moat cost, consistent with how Aider/OpenHands/SWE-agent already operate fully open. Mitigate by keeping any genuinely proprietary Oxagen-platform-integration code (the @oxagen/cli TS product) in the private monorepo — nothing platform-specific ships in the public export.If competitive copying demonstrably erases the benchmark margin faster than the project can innovate ahead of it (i.e., the OSS release makes the >3pp claim unsustainable within a few refresh cycles), that is a signal to invest harder in the parts that don't commoditize (code-graph quality, best-of-N selection sophistication) — not a signal to close the source; re-closing an OSS project destroys the trust it was meant to build.
R8Distribution/CI complexity — cross-compiling a static binary for 4+ OS/arch targets (esp. musl Linux + the llama.cpp FFI dependency, which has its own native build requirements per target) is nontrivial and can silently break one target while others stay green.MediumMediumcargo-dist or cross-based CI matrix from Phase 0 (not bolted on at Phase 6) so target breakage is caught immediately, not discovered at release time. Consider making local-GGUF support conditional/feature-flagged per target if musl+FFI proves too fragile on a given combination (ties to R3's fallback).If one target (most likely: musl Linux + FFI) can't be made reliably green within Phase 4's timeframe, ship that target without on-device support (feature-flag it out) rather than blocking the whole release.
R9Telemetry opt-in-by-default-off means near-zero usage data during early OSS adoption, making it hard to prioritize fixes/features by real-world signal.High (by design — non-negotiable #6)Low-Medium (a product-management cost, not a correctness risk)Lean on the public issue tracker, bench/swe-bench/bench/terminal-bench continuous benchmark runs, and direct community engagement (Discord/GitHub Discussions) as the primary signal channels instead of telemetry. If an opt-in telemetry feature is built later, make the value exchange explicit (e.g. an opt-in "share anonymized run stats, see them on a public dashboard" feature) rather than assuming opt-out is the only way to get signal.N/A — accepted tradeoff, consistent with non-negotiable #6; not a blocker.
R10Scope creep re-adding platform features — pressure (support tickets, feature requests) to re-add oxagen.sh integration (login, memory sync, graph sync) into the OSS binary over time, eroding the "no phone-home" non-negotiable.MediumHigh (undermines the entire trust premise of the OSS release)Any future oxagen.sh integration ships as a separate, clearly-named optional plugin crate (oxagen-cloud or similar) that the base binary does not depend on and does not bundle by default — enforced structurally (a separate crate/binary target, not a compile-time feature flag buried inside oxagen-cli, which is too easy to flip to default-on later). Revisit this structural boundary explicitly in any PR proposing platform integration.If a PR proposes bundling oxagen.sh integration into the default oxagen-cli binary or making it default-on, that is treated as a spec violation requiring explicit product-level sign-off against 01-product-spec.md non-negotiable #1/#2/#6 — not a routine feature PR.

On this page

Document — 00-overview.mdOxagen Rust CLI — Overview & IndexWhat this isDocuments in this setTL;DR decisionsSpec — 01-product-spec.mdOxagen Rust CLI — Product Spec1. Mission2. Non-negotiables (binding for every phase)3. Target users4. Provider model (BYOK, no gateway)5. Feature parity matrix — keep / rebuild / cutKEEP — core agentic coding loop (the product)CUT — platform-bound, no home in an account-free OSS productREBUILD DIFFERENTLY — same user value, different mechanism6. Success metrics (definition of done for "v1.0")7. Explicitly out of scope for v1.0Document — 02-architecture.mdOxagen Rust CLI — Architecture1. Design principles2. Crate layout (Cargo workspace)3. Core traits (the port boundary)4. Event vocabulary (protocol)5. On-disk layout6. Security model7. Why this repo, then a mirror (not day-one public repo)Plan — 03-plan.mdOxagen Rust CLI — Build Plan (phased)Phase 0 — Workspace skeleton + provider spike (prove the riskiest bet first)Phase 1 — oxagen-tools (fs/exec/grep/glob/diff)Phase 2 — oxagen-model (full provider matrix) + oxagen-core step-driverPhase 3 — oxagen-graph + oxagen-pipeline + oxagen-mcpPhase 4 — oxagen-fleet + oxagen-tui + oxagen-cliPhase 5 — Bench proof (the #1-by->3pp claim)Phase 6 — Open-source the repoCross-cutting notesDocument — 04-benchmark-strategy.mdOxagen Rust CLI — Benchmark Strategy ("#1 by >3pp" claim)1. The claim, precisely2. Comparison target selection3. Fixed variables (controlled comparison)4. What's allowed to differ (and must be disclosed)5. Levers to earn the margin (ranked by expected impact)6. Anti-p-hacking rules (binding)7. Reporting formatDocument — 05-risk-register.mdOxagen Rust CLI — Risk Register