- Rust 99.6%
- Nix 0.4%
| docs | ||
| src | ||
| .envrc | ||
| .gitignore | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CLAUDE.md | ||
| flake.lock | ||
| flake.nix | ||
| QUICKSTART.md | ||
| README.md | ||
harness-rs
Native Rust CLI/runtime for terminal-first agent harness workflows.
harness-rs combines:
- a Ratatui/Crossterm chat TUI over typed session events
- OpenAI and OpenAI-compatible provider integration
- local-first libSQL/Turso session storage
- JSON-RPC stdio tools for editor and agent integration
- safe read-only workspace and host-inspection tools
- microVM-first execution contracts for mutating or shell-driven work
- reproducible Nix development and package outputs
Project Status
harness-rs is early foundation software. The CLI, TUI, local persistence,
OpenAI-compatible streaming, read-only tools, stdio server, and execution policy
contracts are usable. The Firecracker microVM runner is intentionally fail-closed
until kernel/rootfs images and the guest runner are implemented.
For current handoff notes, remaining work, and the Linear project link, see
docs/handoff.md.
Use the read-only tools today for repository and local file inspection. Treat mutating execution and arbitrary shell work as roadmap items unless you are working on the execution backend itself.
Quick Start
If you are setting up another system, start with QUICKSTART.md.
git clone https://forgejo.kennysheridan.io/kennysheridan/harness-rs.git
cd harness-rs
nix develop
cargo run -- init
cargo run -- config
cargo run -- chat
Without an OpenAI key, provider = auto falls back to the local mock adapter so
the CLI, TUI, and persistence path remain testable.
To use OpenAI or an OpenAI-compatible endpoint:
export OPENAI_API_KEY="<token>"
export OPENAI_MODEL="gpt-4o-mini" # optional
cargo run -- run "summarize this repository"
Common commands:
cargo run -- --help
cargo run -- init
cargo run -- config
cargo run -- doctor execution
cargo run -- run "hello"
cargo run -- chat
cargo run -- serve --stdio
cargo run -- skills list
Setup
Requirements
- Linux or macOS for development; Linux is the primary target for execution isolation.
- Nix with flakes enabled for the recommended reproducible setup.
- Git to clone the repository.
- OpenAI API key only if you want real provider calls.
- Rust stable if you are not using Nix.
Recommended Nix Setup
nix develop
cargo fmt
cargo clippy --all-targets --all-features
cargo test --all-targets --all-features
The flake provides stable Rust with rustfmt, clippy, and rust-src, plus
native dependency tooling such as pkg-config, openssl, clang, cmake,
sqlite, ripgrep, jq, and contributor tools.
You can also run or build directly from the flake:
nix run
nix build
nix flake check
Non-Nix Setup
Use this only when Nix is not available:
rustup toolchain install stable
rustup component add rustfmt clippy rust-src
cargo build
cargo test --all-targets --all-features
cargo run -- --help
Install native dependencies through your platform package manager if Cargo build
scripts report missing OpenSSL, libclang, SQLite, CMake, or pkg-config.
Configuration
harness-rs init creates .harness-rs/config.toml if it does not already
exist:
[provider]
name = "auto"
[provider.openai]
base_url = "https://api.openai.com/v1"
model = "gpt-4o-mini"
api_key_env = "OPENAI_API_KEY"
[storage]
# Existing local databases continue to use libSQL by default.
local_backend = "libsql-local"
[tools.web]
# Explicit host-side HTTPS fetch capability; disabled by default.
enabled = false
timeout_seconds = 15
max_response_bytes = 1048576
[tools.todo]
# Optional explicit Markdown root. Disabled when omitted.
# root = "/absolute/path/to/Obsidian/Harness-RS"
[execution]
backend = "microvm"
[execution.microvm]
provider = "firecracker"
network_enabled = false
workspace_writable_overlay = false
timeout_seconds = 120
memory_mib = 2048
vcpus = 2
Environment variables override TOML provider values for one-off runs:
export HARNESS_RS_PROVIDER=openai
export OPENAI_BASE_URL="https://api.openai.com/v1"
export OPENAI_MODEL="gpt-4o-mini"
export OPENAI_API_KEY="<token>"
harness-rs config reports the selected provider, model, endpoint, store, and
execution policy without printing secret values.
Obsidian todos
Set [tools.todo].root to one explicit Markdown directory to enable the
read-only todo index. The scanner does not search home directories, follows no
symlinks, ignores hidden app metadata and non-Markdown files, and applies fixed
depth, file, task, file-size, and line-size limits. It recognizes - [ ],
- [/], and - [x] tasks. The compact TUI sidebar prioritizes in-progress and
current-focus work, reports pending and in-progress counts, and Ctrl-R refreshes it; the
stdio tool/todo_list tool is advertised only while this root is configured.
It returns source-relative path, line number, opaque task ID, normalized text,
and status only. The model may use todo_update only in the interactive TUI,
with this indexed reference and pending, in_progress, or completed.
Every update is revalidated against a fresh bounded index and requires Allow
once or Allow always (this project). The latter persists only the
todo_update permission in .harness-rs/permissions.json. Stdio rejects this
write tool because it cannot approve concurrently.
Remote Session Store
Local state defaults to .harness-rs/harness.db. To use remote Turso/libSQL,
set both variables before init, chat, run, or serve --stdio:
export LIBSQL_URL="libsql://<database>.turso.io"
export LIBSQL_AUTH_TOKEN="<token>"
cargo run -- init
LIBSQL_AUTH_TOKEN is required when LIBSQL_URL is set and is never printed by
harness-rs config.
Local Turso preview and compatibility canary
[storage].local_backend explicitly selects the local engine. It defaults to
libsql-local; turso-local is an opt-in S1/S2 preview that supports init
and schema migrations only. Session writes continue to require libsql-local
until the adapter is promoted. Remote LIBSQL_URL storage always uses libSQL;
combining it with turso-local, or supplying only one remote environment
variable, is rejected. turso-local refuses an existing unmarked file; a fresh
file receives a sibling .turso-local marker so switching config cannot open a
libSQL file in place.
Do not point both engines at one database file. Before trying Turso with a copied, stopped and checkpointed local libSQL database, run:
cargo run -- storage canary --source .harness-rs/harness.db \
--destination .harness-rs/harness.turso-canary.db
The command refuses to overwrite a destination, reads the source only through
libSQL, copies it, then opens only the copy with Turso. Its JSON report includes
integrity checks, schema/index comparison, table counts, and migration
idempotency. Preserve the original file and rollback by setting
local_backend = "libsql-local"; never convert or migrate an active file in
place.
Skills
Local skills live under .harness-rs/skills and are not committed by default.
Import OpenCode-compatible skills from another machine with:
cargo run -- skills import ~/.config/opencode/skills
cargo run -- skills list
Verifying Installation
Run these checks on a fresh system:
cargo run -- --help
cargo run -- init
cargo run -- config
cargo run -- run "hello from harness-rs"
cargo run -- skills list
With an OpenAI key configured, verify provider streaming and tools:
cargo run -- run "List the top-level files in this repository."
cargo run -- chat
Inside the TUI, try:
/mcp
/models
/files
/largest ~/Downloads 10
/copy last
TUI Usage
cargo run -- chat starts the Ratatui/Crossterm interface.
Key bindings:
Entersubmits the prompt.Shift-Enterinserts a newline when supported by the terminal.Ctrl-Eedits the prompt in$VISUAL,$EDITOR, ornvim.Ctrl-Popens the command palette.Ctrl-Bselects a sidebar category;EnterorSpaceexpands or collapses it.Ctrl-Texpands or collapses the safe Activity sidebar category.Ctrl-Shift-Tswitches Activity between compact and bounded sanitized detail views.Ctrl-Yyanks the selected or latest message via OSC52.EscorCtrl-Cexits.
Useful slash commands:
/modelsor/modelopens the searchable model picker./model <id>switches directly to an OpenAI-compatible model id./session [id|name],/sessions,/new [name],/rename <name>, and/resetmanage sessions./tokensand/compactshow context usage and compact long transcripts./theme [opencode|midnight|solarized|mono]shows or switches transcript themes./copy [message-number|last|assistant|user|system|activity|all]yanks transcript content./mouse [on|off]chooses normal terminal selection or mouse-driven select/right-click yanking./skillsbrowses imported local skills./mcpshows runtime metadata, workspace tools, Linux tool availability, and execution policy./files [path],/read <path>, and/search <text>inspect the workspace safely./largest [path] [limit]lists the largest regular files under approved user directories.
Tools And Execution
Built-in model tools include:
runtime_infofor provider, model, cwd, OS/arch, and execution policy metadata.workspace_filesfor bounded file listing under the configured workspace.workspace_readfor bounded reads of workspace files.workspace_searchfor literal text search with line numbers.linux_execfor argv-only allowlisted read-only commands such asuname,date,pwd,id, selectedgitinspection commands, and--versionchecks.host_largest_filesfor bounded read-only metadata scans under approved user directories such as~,HOME,$HOME, or~/Downloads.web_fetchfor bounded text fetches from public HTTPS hosts, only when[tools.web].enabled = true.
Workspace paths are confined to --cwd; absolute paths and .. traversal are
rejected. Listing and search skip .git, .harness-rs, .agentbrain,
.direnv, target, result, and result-*.
Secure Execution
harness-rs treats model-driven execution as a security boundary. Read-only
context tools run in-process only when they are path-confined and output-bounded.
Read-only Linux inspection runs without a shell through a strict argv allowlist.
Web access is a separate, explicit host capability: it is disabled by default and
does not depend on or change microVM networking. When enabled, web_fetch allows
one HTTPS URL, rejects credentials, localhost, literal IPs, and non-public DNS
answers, and manually follows up to four redirects after revalidating and pinning
each target. It returns bounded final-URL text without response headers.
Mutating tools, arbitrary shell execution, package installs, tests, generated
code execution, and networked execution route through the execution policy. The
default backend is microvm, oriented around Firecracker, with network disabled
and workspace writes disabled by default. The runner fails closed until images
are configured.
See docs/security-execution.md for the detailed
architecture and rollout plan.
Use cargo run -- doctor execution and
docs/microvm-sandboxing.md when bringing up the
Firecracker sandbox on a new host.
Stdio Integration
harness-rs serve --stdio exposes newline-delimited JSON-RPC over stdin/stdout.
Example request:
{"jsonrpc":"2.0","id":1,"method":"runtime/status","params":{}}
Available methods include runtime/config/status methods, tools/list,
tool/runtime_info, tool/workspace_files, tool/workspace_read,
tool/workspace_search, tool/linux_exec, tool/host_largest_files, and
tool/web_fetch, and session/prompt. tools/list reports whether web fetch is
enabled; calls fail closed while it is disabled.
Project Layout
The project is currently a single Cargo package with explicit module seams:
| Module | Purpose |
|---|---|
app |
application orchestration and command dispatch |
cli |
command-line parsing |
commands |
slash-command metadata and parser |
config |
configuration discovery, defaults, and validation |
execution |
microVM-first execution contracts and policy types |
llm |
OpenAI-compatible provider and tool-call adapter |
protocol |
typed session and JSON-RPC protocol models |
runtime_tools |
bounded host/runtime inspection tools |
session |
session lifecycle and event streams |
skills |
local skill discovery and import |
stdio |
JSON-RPC stdio server |
store |
async libSQL/Turso persistence |
tools |
path-confined workspace tools |
tui |
Ratatui/Crossterm chat UI |
These boundaries can split into workspace crates once the codebase is large enough to justify it.
Documentation
QUICKSTART.mdgives a clean-machine bootstrap path.docs/setup.mdprovides fuller install, configuration, and verification instructions.docs/microvm-sandboxing.mddescribes Firecracker sandbox bring-up.docs/security-execution.mddocuments the execution security model.docs/linear-project.mdtracks the roadmap.
Development
nix develop
cargo fmt
cargo clippy --all-targets --all-features
cargo test --all-targets --all-features
cargo run -- --help
With direnv:
direnv allow
Release-impacting commits should use release-please-compatible Conventional
Commits, for example feat(tui): add message copy affordances or
fix(runtime): preserve stdio request ids.
Design References
harness-rs borrows Rust systems-design lessons from projects like
cuda-oxide: clear boundaries, typed low-level contracts, fail-closed runtime
checks, reproducible tooling, and direct verification commands. It does not take
a CUDA dependency unless a future GPU-specific harness tool requires one.