supercode-core 0.1.0

A lightweight, fully-customizable AI coding agent SDK in Rust. Talks to any model via OpenRouter or any OpenAI-compatible endpoint.
Documentation
# supercode

A lightweight, fully-customizable AI **coding-agent SDK** in Rust.

`supercode` is a native agent loop — it talks directly to any model through
[OpenRouter](https://openrouter.ai) (or any other OpenAI-compatible endpoint),
drives a configurable set of tools, and is built to be a **superset** of what
tools like Claude Code and Codex do. Three goals shape it:

1. **Highly customizable** — every prompt, every tool description, and every
   tool's on/off state is yours to set.
2. **Light and fast** — pure Rust, a thin async core, streaming by default. The
   agent loop runs in **~13–19 MB** of memory — measured **~7× lighter than
   Codex and ~27× lighter than Claude Code** on identical tasks (see
   [Benchmarks & footprint]#benchmarks--footprint).
3. **A superset of existing agents** — it natively **loads and continues real
   Claude Code and Codex sessions** from disk, so you can pick up any prior
   session against any model.

> Status: early but real. The core, the OpenRouter/OpenAI provider, the
> built-in tools, the agent loop, and the session loaders are implemented and
> tested. See [Status]#status.

## Benchmarks & footprint

"Light and fast" is measured, not asserted. [`bench/`](bench/) is a task harness
that runs the agent against a live model **and profiles the harness's own
footprint** (peak RSS, CPU, startup, binary size) — because low memory/CPU is the
whole point.

**Footprint vs the incumbents.** Same model (DeepSeek V4 Flash via OpenRouter),
same tasks, same verifier, same per-process sampler — only the harness changes.
Harness **own-process** resident memory:

| harness | own-process RSS | vs supercode | runtime |
|---|--:|--:|---|
| **supercode** | **~13–19 MB** || single 5.5 MB Rust binary |
| codex | ~89 MB | ~7× | Rust core (+ Node launcher) |
| claude code | ~346 MB | ~27× | Node / TypeScript |

All three solved the same tasks; supercode also used the least CPU. The numbers
above are each harness's *own* process — the clean, conservative metric. Codex
and Claude Code additionally launch heavyweight MCP/helper processes (hundreds of
MB) that supercode does not. Full methodology, per-task data, and the honest
tree-sum caveats are in
[`bench/suites/harness-comparison.md`](bench/suites/harness-comparison.md).

**Capability.** On a real subset of the [Aider polyglot
benchmark](https://github.com/Aider-AI/polyglot-benchmark) (12 Exercism exercises
across Python/Rust/Go, real test suites), supercode driving DeepSeek V4 Flash
scores **12/12**, with a profile block in every scorecard
([`bench/suites/polyglot-scorecard.json`](bench/suites/polyglot-scorecard.json)).
It also speaks the [SWE-bench](https://www.swebench.com) instance format
(loader + fixtures; Docker is the citable grading lane — see
[`bench/suites/swebench/`](bench/suites/swebench/)).

```sh
export OPENROUTER_API_KEY=sk-or-...
cargo run -p supercode-bench -- --tasks bench/suites/polyglot --sandbox danger-full-access
python3 bench/tools/compare_harnesses.py     # supercode vs claude vs codex
```

## Why OpenRouter

OpenRouter exposes a single OpenAI-compatible API in front of essentially every
frontier model. `supercode` therefore ships **one** provider implementation
([`OpenAiProvider`]) that reaches Claude, GPT, Gemini, Llama, and anything else
OpenRouter routes to. Point `base_url` at any other OpenAI-compatible endpoint
(a local server, a gateway, a mock) and it just works.

## Install

```sh
curl -fsSL https://raw.githubusercontent.com/volter-ai/supercode/main/scripts/install.sh | sh
```

Or pick your channel:

| Channel | Command |
|---|---|
| Install script | `curl -fsSL .../scripts/install.sh \| sh` (prebuilt binary, checksum-verified) |
| cargo | `cargo install supercode-cli` |
| cargo-binstall | `cargo binstall supercode-cli` (prebuilt, no compile) |
| Homebrew | `brew install volter-ai/tap/supercode` — once the tap is published¹ |
| from source | `git clone … && cargo install --path crates/cli` |

> Prebuilt channels resolve to GitHub Releases; until the first public release is
> cut they fall back to `cargo install`. Requires a Rust toolchain (1.85+) only
> when building from source.
>
> ¹ Each release renders and publishes `supercode.rb` (real checksums) as a
> release asset; the `volter-ai/homebrew-tap` repo is populated automatically
> when a `HOMEBREW_TAP_TOKEN` is configured. Until then, use the install script
> or `cargo install`.

### First run

```sh
supercode login          # paste your OpenRouter key — saved to ~/.config/supercode
supercode doctor         # ✓ config, key, and live provider reachability
supercode run "hello"
```

No key yet? Any one of these works: `supercode login`, `export OPENROUTER_API_KEY=…`,
or `--api-key`. Shell completions: `supercode completions zsh` (also bash/fish/powershell).

## CLI

```sh
# One-shot
supercode run "List the Rust files and summarize the module layout."

# Interactive
supercode chat

# Inspect a real Claude Code or Codex session — no API key needed
supercode inspect ~/.codex/sessions/2026/05/04/rollout-*.jsonl

# Load a prior session and CONTINUE it against your chosen model
supercode --model openai/gpt-5 resume ~/.claude/projects/<proj>/<id>.jsonl \
  "Pick up where we left off and finish the refactor."

# Convert a session between formats (GIMP-style "export as") — no API key needed
supercode convert ~/.codex/sessions/.../rollout-*.jsonl --to claude-code -o out.jsonl

# Audit a corpus: typed-parse every log and report what we model/drop/miss
supercode audit ~/.codex/sessions  --format codex
supercode audit ~/.claude/projects --format claude-code
```

Global flags: `--model`, `--base-url`, `--cwd`.

## Library

```rust
use supercode::{Agent, Config};

# async fn run() -> supercode::Result<()> {
let config = Config::builder()
    .model("anthropic/claude-opus-4-8")
    .system_prompt("You are a terse, expert pair programmer.")
    .disable_tool("bash")                          // toggle tools off…
    .tool_description("search", "Grep the repo.")  // …or re-describe them
    .build();

let mut agent = Agent::new(config)?;
let reply = agent.send("Find every TODO and group them by file.").await?;
println!("{reply}");
# Ok(())
# }
```

### Continue a Claude Code or Codex session

```rust
use supercode::{Agent, Config};
use supercode::session::Session;

# async fn run() -> supercode::Result<()> {
let session = Session::load("~/.codex/sessions/.../rollout-….jsonl")?;
let mut agent = Agent::resume(Config::builder().build(), session)?;
let reply = agent.send("Continue from here.").await?;
# let _ = reply;
# Ok(())
# }
```

## Typed schema & coverage audit

Both formats are modeled as **typed Rust schemas**
([`src/schema/`](crates/core/src/schema)) with two deliberate escape hatches:
every discriminated enum has a `#[serde(other)] Unknown` variant, and every
record struct has a flattened `extra` catch-all. So anything a real log contains
that we don't model is *captured and countable* rather than silently lost.

The `audit` command deserializes a whole corpus through those types and reports,
per discriminant, whether it's **normalized / dropped / unmodeled** — plus the
unmodeled field names and tool frequencies. This is how
[`ROADMAP.md`](ROADMAP.md) is produced: the gaps fall out of the type system
instead of being guessed. On the maintainer's local corpus (opt-in,
`SUPERCODE_CORPUS=1` — **not run in CI**) the audit reports `parse_errors=0`
across up to **1,500 files per corpus** (~1.2M Codex lines); a CI regression
test built on synthetic fixtures fails if a new unmodeled record type appears.

## How session loading works

Both tools persist conversations as JSONL:

| Tool        | Location                                          | Shape |
|-------------|---------------------------------------------------|-------|
| Claude Code | `~/.claude/projects/<encoded-cwd>/<id>.jsonl`     | Anthropic message events, linked by `uuid`/`parentUuid` |
| Codex       | `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl`    | `{timestamp,type,payload}` envelopes; `response_item` lines are canonical |

[`Session::load`] auto-detects the format and **normalizes** either one into a
provider-neutral `Vec<ChatMessage>` in the OpenAI chat-completions shape, so it
can be handed straight back to any model to continue. Provider-internal
artifacts that don't replay across vendors — Anthropic `thinking` blocks, Codex
`reasoning` items — are dropped.

### Saving and converting (GIMP model)

There's one canonical in-memory model plus **importers and exporters** per
format — exactly like an image editor that opens and exports several file types:

```rust
use supercode::{Session, SessionFormat};

# fn run() -> supercode::Result<()> {
let session = Session::load("session.jsonl")?;           // import (auto-detect)
session.save("out.jsonl", SessionFormat::ClaudeCode)?;   // export as Claude Code
let codex = session.to_jsonl(SessionFormat::Codex);      // …or Codex, as a String
# let _ = codex; Ok(())
# }
```

The correctness property is a **semantic round-trip**: load → save → load yields
the same conversation. The opt-in corpus test (`SUPERCODE_CORPUS=1`, **not run
in CI**) asserts **≥97% of sampled files round-trip stably** on the maintainer's
local logs; CI covers the same normalization logic with synthetic fixtures.
Converting *between* formats is an "export" — framing with no slot in the target
(a Codex developer/system turn) may be dropped, but the user/assistant/tool
conversation is preserved.

**Manually verified once (not automated).** A session supercode wrote was
resumed by the stock `claude` and `codex` CLIs in headless mode, and each
correctly recalled a fact established earlier in the conversation — a one-off
check, not part of the test suite:

```sh
# Claude Code: supercode re-exports a session under a new id; claude resumes IT
supercode convert <claude session> --to claude-code --session-id <new> -o <dir>/<new>.jsonl
claude -r <new> -p "…"        # → recalls prior context ✔

# Codex: same round-trip; codex resumes supercode's rollout
supercode convert <codex session> --to codex --session-id <new> -o <…>/rollout-…-<new>.jsonl
codex exec resume <new> "…"   # → recalls prior context ✔
```

Codex validates the rollout header strictly, so the exporter **replays the
original `session_meta`/`turn_context` records** (preserved on load) and
synthesizes the conversation around them; converting *from* another format
synthesizes a header with the fields Codex requires.

## Customization surface

Everything lives on [`Config`] (built via `Config::builder()`):

- `model`, `base_url`, `api_key` / `api_key_env`
- `system_prompt`
- `temperature`, `max_tokens`, `max_iterations`
- `cwd` — where tools operate
- per-tool **enable/disable** and **description overrides**
- `extra_headers` — e.g. OpenRouter attribution headers
- an `event_sink` for streaming text + tool activity

Register your own tools by implementing [`Tool`] and calling
`agent.register_tool(...)`.

## Built-in tools

`read_file`, `write_file`, `edit_file`, `list_dir`, `glob`, `search` (regex,
gitignore-aware), `apply_patch`, `bash`, `shell` (persistent), and
`update_plan`. Each can be disabled or re-described per config.

## Architecture

```
Config ── model / endpoint / key / prompt / tool overrides / event sink
  │
Agent ── the loop: stream a turn → run requested tools → feed results back → repeat
  ├── Provider (OpenAiProvider → OpenRouter / any OpenAI-compatible endpoint)
  ├── ToolRegistry (built-ins + your tools)
  └── Session  ── load & normalize Claude Code / Codex logs to continue them
```

## Status

Implemented and tested:

- ✅ OpenRouter / OpenAI-compatible streaming provider with tool calls
- ✅ Built-in tool suite + per-tool customization
- ✅ Agent loop with streaming events and an iteration budget
- ✅ Native Claude Code **and** Codex session loading + continuation
- ✅ Saving / converting sessions back to Claude Code and Codex formats
- ◑ Written files **manually** verified resumable by the stock `claude` and
  `codex` binaries (a one-off check, not part of CI)

Exercised against the maintainer's local corpus (up to ~**3,000** logs across
both formats) via **opt-in** tests (`SUPERCODE_CORPUS=1`, **not run in CI**):
the load smoke asserts **0 parse errors** and ≥90% non-empty, and the round-trip
test asserts **≥97% stable**. CI runs synthetic-fixture tests that exercise the
same normalization logic. Run the opt-in sweeps yourself:

```sh
SUPERCODE_CORPUS=1 cargo test -p supercode-core -- --ignored --nocapture
```

Not yet built (natural next steps): a lossless native session format, richer
prompt-cache controls, and Linux (landlock/seccomp) sandboxing — the OS process
sandbox is macOS-only today.

## License

MIT OR Apache-2.0.