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.mddocs/specs/oxagen-rust-cli/01-product-spec.mddocs/specs/oxagen-rust-cli/02-architecture.mddocs/specs/oxagen-rust-cli/03-plan.mddocs/specs/oxagen-rust-cli/04-benchmark-strategy.mddocs/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
| Doc | Contents |
|---|---|
00-overview.md | This file. |
01-product-spec.md | Mission, non-negotiables, feature parity matrix (keep/cut/rebuild), provider model, licensing, distribution, success metrics. |
02-architecture.md | Crate layout, port/trait boundaries, data flow, on-disk formats, security model. |
03-plan.md | Phased build plan (0→6), branch/worktree strategy, exit criteria per phase, effort estimates. |
04-benchmark-strategy.md | How 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.md | What can go wrong, mitigations, kill criteria. |
TL;DR decisions
- Language: Rust, edition 2024,
tokioasync runtime,clapfor CLI,ratatuifor TUI. - 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,rustlsare all MIT/Apache-2.0 dual). - 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 justANTHROPIC_API_KEYset. - 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.
- 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). - 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 publicoxagen-cliGitHub repo via a one-way export script once Phase 3 lands (see03-plan.md§6). It does not become apnpmworkspace 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. - Distribution:
cargo install oxagen-cli, Homebrew tap, prebuilt binaries (GitHub Releases,cargo-distorcross+ GH Actions for macOS/Linux/Windows × x86_64/arm64), and acurl | shinstaller 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)
- 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. - 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. - 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. - 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).
muslstatic linking on Linux; universal or per-arch binaries on macOS; no dynamic OpenSSL dependency (userustls). - 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.
- 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.
- #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.mdfor 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-coreandoxagen-toolsmust be usable as library crates by other Rust projects.
4. Provider model (BYOK, no gateway)
| Provider | Auth | Notes |
|---|---|---|
| Anthropic | ANTHROPIC_API_KEY | Direct Messages API, streaming, native tool-use, extended thinking. |
| OpenAI | OPENAI_API_KEY | Responses API (streaming, tool-use, reasoning effort param). |
| AWS Bedrock | Standard AWS credential chain (env, profile, IMDS, SSO) + region | bedrock-runtime Converse/ConverseStream API — covers both native Bedrock models (Claude, Titan, Llama, Nova) and Bedrock Model Garden custom-imported models by ARN. |
| Google Vertex AI | ADC (GOOGLE_APPLICATION_CREDENTIALS or workload identity) + project/region | Vertex generateContent/streaming — covers native Gemini and Vertex Model Garden (Llama, Mistral, Claude-on-Vertex, custom-deployed endpoints by endpoint ID). |
| OpenRouter | OPENROUTER_API_KEY | One 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-compatible | none, or --base-url | vLLM, 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 token | Escape 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)
| Capability | TS source (reference) | Rust target |
|---|---|---|
| Step-driver agent loop (evaluate→enhance→route→execute→judge→revise) | packages/agent-engine/src/pipeline/index.ts, loop-driver.ts | oxagen-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.ts | oxagen-tools |
| Code-graph context engine: tree-sitter parse, symbol/import-edge index, semantic search, domain assist | packages/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 card | apps/cli/src/agent/model-router.ts, rate-card.ts | oxagen-model |
Multi-provider AgentAi port abstraction | packages/agent-engine/src/ports.ts | oxagen-model::Provider trait |
| Best-of-N candidate generation + selection (test signal + diff-judge) | docs/specs/cli-swe-bench/02-spec.md §5 | oxagen-pipeline |
| Evidence-based judge (diff + test-tail, judge≠worker) | same | oxagen-pipeline |
| Fleet / multi-agent orchestration: worktree isolation, planner DAG, commit ledger | apps/cli/src/agent/fleet/* | oxagen-fleet |
| Interactive REPL/TUI: streaming render, diff view, slash commands, HUD | apps/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-trip | apps/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 guard | apps/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-first | oxagen-cli::slash, filesystem-first unchanged |
| MCP client (connect to external MCP servers as tools) | apps/cli/src/mcp/client.ts | oxagen-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.ts | oxagen-fleet::pr_monitor (shells to gh CLI or uses GitHub REST directly) |
Init / project scaffolding (.oxagen/ dir, rules seed) | apps/cli/src/project/init.ts | oxagen-cli::init |
| Config file + env var resolution | apps/cli/src/lib/config.ts | oxagen-cli::config (TOML, ~/.config/oxagen/config.toml) |
| Trace/trajectory recording (JSONL, replay) | apps/cli/src/agent/trace*.ts, verbose-log.ts | oxagen-core::trace |
| `--output-format text | json | stream-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 mechanism | Why it can't carry over as-is | Rust replacement |
|---|---|---|
| Vercel AI Gateway model routing | Gateway is an oxagen.sh-operated proxy | Direct per-provider SDK clients (oxagen-model), see §4 |
AI_GATEWAY_API_KEY credential resolution | Same | Provider-native credential chains (env, AWS SDK default chain, GCP ADC, OpenRouter key, --base-url) |
Login/OAuth+PKCE against oxagen.sh, ~/.config/oxagen/config.json session | No account to log into | No 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 default | If 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 adapters | Embedded 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 platform | Local-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 binary | Not 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")
| Metric | Target | How verified |
|---|---|---|
| SWE-bench Verified resolve rate vs. best public comparable | ≥ +3.0 percentage points, same pinned model | bench/swe-bench harness (Rust-adapted, see 04-benchmark-strategy.md) |
| Cold start to first token | < 150ms process start, < 100ms of that pre-network | hyperfine oxagen --version / instrumented startup trace |
| Binary size (static, stripped) | < 40MB per platform target | CI artifact size check |
Zero network calls with only a model key configured, no --telemetry flag | 0 calls other than the model API | Network-namespace/strace-gated integration test |
| Test coverage (workspace-wide) | ≥ 85% line coverage on oxagen-core/oxagen-tools/oxagen-pipeline, ratchet toward 90 | cargo llvm-cov in CI |
| Golden-trajectory parity with the frozen TS spec (migration period only) | 100% byte-identical event stream on recorded inputs | CI conformance suite, retired once the TS spec is fully ported |
| License scan | 0 GPL/AGPL/SSPL transitive dependencies | cargo deny in CI |
| Distribution | cargo install, Homebrew, curl | sh, GH Releases (4 OS/arch combos) all green | Release 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
- 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'sports.ts, carried over directly (seepackages/agent-engine/src/ports.tsfor the shape being ported). - No
unsafeoutside FFI boundaries (the local-modelllama.cppbinding is the one legitimate exception; isolate it behind a narrow, fully-tested wrapper crate/module and document everyunsafeblock). - 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, noSend/Syncceremony needed). - Serde-first. Every cross-boundary type (provider request/response,
tool call/result, trace event, protocol message) derives
Serialize/Deserializeand is versioned. This is what makes golden- trajectory replay and future protocol stability possible. - Fail loud, recover gracefully. Provider errors, tool errors, and
malformed model output are typed (
thiserror), neverpanic!in the hot path; the step-driver treats retryable vs. terminal errors distinctly (mirrors TS Phase-1 retry/backoff design indocs/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 noDisplay). edit_file/write_file/execrespect a workspace-root jail by default (no path traversal outside the initialized project root without an explicit--unsafe-full-fsescape 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.exectimeout + process-group kill is native (nix::sys::signal::killpgand Windows job objects viawindows-syswhere applicable) — closes the TS CLI's documented bash-process-group leak on abort (GAPS.md/01-gap-audit.mdP1).- Dependency policy:
cargo denyin 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.
- Cargo workspace scaffold: all 9 crates from
02-architecture.md§2 as empty stubs with correct inter-crate dependency edges (oxagen-clidepends on everything;oxagen-protocoldepends on nothing internal). oxagen-protocol:AgentEvent,ModelRunRequest/ModelStream,ToolCall/ToolOutput— the types from02-architecture.md§3–4, withserdederives and unit tests for round-trip (de)serialization.oxagen-modelspike: Anthropic adapter (direct HTTP + SSE parse viareqwest+eventsource-streamor hand-rolled) and Bedrock adapter (aws-sdk-bedrockruntime,ConverseStream) — both implementingProvider, 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.- CI:
cargo fmt --check,cargo clippy -D warnings,cargo test,cargo deny check,cargo auditas a new GitHub Actions job (.github/workflows/rust-cli.yml), triggered only oncrates/**changes (mirrors howbench/webis excluded from unrelated CI per existing conventions) — do not let this job block unrelated PRs. - 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).
read_file: line-numbered output (cat -n-style), range support, size cap.write_file/edit_file: exact-match edit with fuzzy-match failure diagnostics (closest-line search via Levenshtein — portclosestLine/similarity/occurrenceLines/describeEditFailurefromtools.tsline-for-line logic,replace_alloption.exec:tokio::process::Command, process-group creation (nix::unistd:: setsidorsetpgid), timeout backstop per the TStoolBackstopMstable, real signal-based kill on abort/timeout (closes the documented bash leak), middle-out (head+tail) output truncation.grep/glob: shell torg/fdwhen present on$PATH(fast path); pure-Rust fallback (grep+ignorecrates, which already respect.gitignore— this is a Python-repo win vs. the TS JS-walker: no bespoke ignore-list needed,ignorecrate handles it natively).diff:git2(libgit2 bindings) for tracked-file diffs; synthetic--no-index-equivalent diff for untracked files (port the untracked-file fix from the TSworkspace.ts).- Conformance tests: for every TS
tools.test.ts/tools.extra.test.tscase, 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.
- Round out
oxagen-model: OpenAI, Vertex AI, OpenRouter, generic OpenAI- compatible (covers Ollama/vLLM/LM Studio in one adapter), local GGUF viallama-cpp-2bindings (native, replacing the TSnode-llama-cppbridge — should be strictly faster to first token, no N-API marshaling overhead). - 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. oxagen-corestep-driver: one model call per step, explicit message accumulation,AgentEventemission 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 monolithicstreamTextcall; Rust has no such legacy to work around).- Retry+backoff (jittered exponential, retryable-error classification per provider — 429/5xx/transport vs. 4xx-terminal), resumes from last completed step.
- Compaction: token estimator (tiktoken-compatible via
tiktoken-rsfor OpenAI-family, provider-specific estimators elsewhere), ~80%-of-window trigger, summarize-old-keep-recent strategy, stable system-prefix preserved for prompt caching. - 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.
- Rules engine (
.oxagen/rules/Tier-1 prompt injection + Tier-2 tool-gate guard) and hooks engine (Session/PreToolUse/PostToolUse) — ported directly fromapps/cli/src/rules/*andapps/cli/src/settings/*semantics. - Local memory:
rusqlite-backed episodic store, salience scoring, rule- promotion candidate surfacing — same concepts asapps/cli/src/agent/ memory.ts/packages/engram, new storage (no ClickHouse/DuckDB-adapter dependency; SQLite is the whole point of "no server"). - 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
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_rsorusearch), persisted per-workspace SQLite/DuckDB.oxagen-pipeline: evaluate→enhance→route→execute→judge→revise orchestration overoxagen-core::Engine; evidence-based judge (diff + test-tail, judge≠worker enforced via a distinctProviderinstance); best-of-N (--candidates N) generation + selection (test-outcome + diff-judge-panel).oxagen-mcp: MCP client — stdio + streamable-http transports, tool discovery, registration intooxagen-core's tool registry alongside the native tool set.- 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
oxagen-fleet: planner DAG, git-worktree isolation (isolate-by-default — fixing the TS default-unsafe-concurrency finding from01-gap-audit.mddirectly, not carrying the bug forward), commit ledger (SQLite), PR/CI monitor (shells toghCLI first for simplicity,octocrabif a native GitHub client proves worth the dependency weight).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 ontoAgentEvent— never touchesoxagen-coreinternals directly.oxagen-cli:clapcommand 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.- Distribution scaffolding:
cargo-distconfig for GH Releases across macOS (x86_64/arm64), Linux (x86_64/arm64, musl static), Windows (x86_64); Homebrew tap formula;curl | shinstaller 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.
- 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 adjustoxagen_terminal_bench.oxagen_agentfor a native binary instead of a Node bundle path. - Smoke: 1 instance end-to-end, non-empty patch, cost line parsed.
- 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).
- 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 inbench/swe-bench, needs the Rust-agent wiring from step 1). - 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). - Publish methodology + raw results (
bench/webdashboard already has the schema/plumbing —oxagen.eval.v1) with every fairness caveat from the existingbench/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
cargo deny/cargo audit/license-header lint fully green; every dependency's license reviewed against Apache-2.0/MIT compatibility.git subtree splitcrates/oxagen-cli/history into a new publicoxagen-cliGitHub repo (preserves commit history, per02-architecture.md§7). Set up its own CI (mirrors the internal job, now public-facing).- Public docs site (README, CONTRIBUTING with DCO instructions, security
policy, architecture doc adapted from
02-architecture.md). - Public issue tracker seeded with the known-gaps/risk items from
05-risk-register.mdthat are acceptable to ship with (labeledknown-limitation), not hidden. - Announce with the benchmark results from Phase 5, methodology and raw
data linked, comparison framing identical to the existing
bench/swe-benchfairness rules (never present a number without its methodology attached). - 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 testas a substitute for the narrowest proving command — same spirit as this repo's "never run all tests" rule for the TS workspace; usecargo test -p <crate>orcargo 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-graphandoxagen-mcpin 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-cliresolves ≥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.mdalready 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:
- 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'sCOMPETITORSlist), on the same pinned model as oxagen-cli's run. - 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. - 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_SLUGpassed to-min the existingcompare.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=1for 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)
- 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. - Context compaction that never wedges (
oxagen-core, Phase 2): a context-overflow failure is a scaffold bug, not a hard task — every instance lost tocontext_length_exceededis a free percentage point on the table. Zero-tolerance target: 0 instances fail purely from context overflow in the final run. - 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.
- 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. - 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. - 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)
- No test-set leakage. Never let the agent or any tuning loop see
FAIL_TO_PASS/PASS_TO_PASStest 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. - 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,--candidatesvalue, 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. - Publish raw trajectories for the headline run (
bench/web'soxagen.eval.v1schema already supports this) so a third party can audit individual instance outcomes, not just the aggregate percentage. - 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.shalready guarantees for the TS harness and must carry over unchanged for the Rust harness. - 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
| # | Risk | Likelihood | Impact | Mitigation | Kill/pivot trigger |
|---|---|---|---|---|---|
| R1 | Porting 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 rework | Freeze/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. |
| R2 | Vertex 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. | Medium | Medium | Build 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. |
| R3 | Local 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-Medium | High (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). |
| R4 | Resolve-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. | Medium | High — the headline claim depends on this | Golden-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. |
| R5 | Best-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. | Medium | Medium | Publish 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). |
| R6 | Workspace-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). | Low | Low-Medium | Document 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. |
| R7 | Open-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. | Medium | Medium | Accepted 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. |
| R8 | Distribution/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. | Medium | Medium | cargo-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. |
| R9 | Telemetry 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. |
| R10 | Scope 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. | Medium | High (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. |