Skip to content

About

Rust port of the Claude Code agent CLI, backed by a local OLLAMA server. 15 SSH-signed commits, ~97% line/function/region coverage.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

18 Commits

Folders and files

Repository files navigation

agent-code-cli-rust

A Rust port of the Claude Code agent CLI, powered by a local OLLAMA instance instead of the Anthropic API. Single static binary, ~5–10 MB stripped.

Status

Feature-complete MVP. Built incrementally over 13 phases with a signed commit and ≥90% line/function/region coverage at every step.

Phase What landed
0 Project skeleton, rust-toolchain, CI, SSH-signed commits, coverage gate
1 clap + rustyline REPL with injectable LineReader
2 OllamaClient over reqwest (/api/chat, non-streaming)
3 Tool enum + read_file + write_file + SessionContext path-safety
4 bash tool with tokio::process + timeout
5 NDJSON streaming + incremental render
6 glob + grep (ripgrep engine, in-process)
7 Permission gate (Default / AutoAccept / Plan) with prompt abstraction
8 Conversation history with token-budgeted compaction
9 tracing instrumentation + RUST_LOG env filter
10 AgentRunner parallel tool dispatch via JoinSet + let chains
11 wiremock end-to-end integration tests + insta snapshots
12 edit tool, release profile + cross-compile docs

Requirements

  • Rust 1.95.0 stable (pinned via rust-toolchain.toml, edition 2024).
  • A running OLLAMA server reachable from this machine. On WSL the host's OLLAMA is reachable via http://host.docker.internal:11434.
  • A model with tool-calling support pulled locally — ollama pull llama3.2:3b (small, default) or ollama pull qwen2.5-coder:7b (recommended for real work).

Configuration

Flag Env var Default
--ollama-host OLLAMA_HOST http://host.docker.internal:11434
--ollama-model OLLAMA_MODEL llama3.2:3b
--log-filter RUST_LOG info
--no-banner — (off)

Build & run

cargo build --release
./target/release/agent-code --version
./target/release/agent-code             # REPL with banner
./target/release/agent-code --no-banner # REPL, quiet

Tests + coverage gate (≥90%)

cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
cargo llvm-cov --all-features \
    --ignore-filename-regex='src/main\.rs|src/tui/rustyline_reader\.rs' \
    --fail-under-lines 90 \
    --fail-under-functions 90 \
    --fail-under-regions 90

src/main.rs and src/tui/rustyline_reader.rs are excluded — both are thin wrappers around stdio/rustyline that can't be exercised from unit tests without a real TTY.

Updating insta snapshots

INSTA_UPDATE=always cargo test --all-features        # regenerate
git diff tests/snapshots/                            # review
git add tests/snapshots/                             # accept

Cross-compile

The project pins rust-toolchain.toml with x86_64-unknown-linux-musl, x86_64-pc-windows-gnu and aarch64-apple-darwin targets.

cargo install cross --locked
cross build --release --target x86_64-unknown-linux-musl   # static linux binary
cross build --release --target x86_64-pc-windows-gnu       # windows .exe
cross build --release --target aarch64-apple-darwin        # macOS arm64

Release profile ([profile.release] in Cargo.toml) sets strip = true, lto = "fat", codegen-units = 1, panic = "abort" so the binary is ~5–10 MB.

Project layout

src/
├─ main.rs                           # 3-line shim (excluded from coverage)
├─ lib.rs                            # banner + run_with_io entry point
├─ cli.rs                            # clap struct
├─ observability.rs                  # tracing setup
├─ agent/{mod.rs, history.rs, runner.rs}
├─ client/{mod.rs, ollama.rs, streaming.rs}
├─ tools/{mod.rs, read_file.rs, write_file.rs, edit.rs, bash.rs, glob_tool.rs, grep_tool.rs}
├─ permissions/{mod.rs, gate.rs}
├─ session/{mod.rs, context.rs}
└─ tui/{mod.rs, repl.rs, render.rs, rustyline_reader.rs}
resources/
├─ system_prompt.md
└─ default_settings.toml
tests/
├─ integration_repl.rs               # assert_cmd against the binary
├─ integration_agent.rs              # AgentRunner against wiremock OLLAMA
├─ common/mod.rs
└─ snapshots/                        # insta snapshots

Troubleshooting

OLLAMA isn't reachable from WSL. Confirm the Windows host is running ollama serve and the WSL nameserver (in /etc/resolv.conf) responds on port 11434:

NS=$(grep nameserver /etc/resolv.conf | awk '{print $2}')
curl -s "http://$NS:11434/api/tags"

Then export OLLAMA_HOST=http://$NS:11434 (or use --ollama-host).

Tool calls always come back empty / model never picks tools. The default llama3.2:3b is tiny; agent loops on it are flaky. Try a stronger model:

ollama pull qwen2.5-coder:7b
OLLAMA_MODEL=qwen2.5-coder:7b ./target/release/agent-code

Coverage gate fails locally but not on CI (or vice versa). Coverage threshold is configured per-attribute (lines, functions, regions ≥90% across the project, ignoring main.rs and rustyline_reader.rs). Run with --html and open the report to see which file dropped.

Commits not showing as signed. git config --global gpg.format ssh and pointing user.signingkey at a public key plus enabling commit.gpgsign=true is enough. Verify locally with git log --show-signature.

About

Rust port of the Claude Code agent CLI, backed by a local OLLAMA server. 15 SSH-signed commits, ~97% line/function/region coverage.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages