𓂀 rust-native agent · sun god, illuminating tools
A Rust-native coding agent. Implements the Agent Client Protocol (ACP) end-to-end, speaks the Agent2Agent (A2A) protocol bidirectionally, loads Model Context Protocol (MCP) servers as tools, persists trajectories in ATIF (Harbor RFC-0001), and emits observability events in ATOF (NeMo Relay).
The name has two readings:
- Ra — the Egyptian sun god; every turn re-illuminates the context, broadcast events radiate outward like rays.
- Ra — Rust-native agent.
The eye watching from the banner is 𓂀 (U+13080).
For the principles behind Ra's autonomous, spec-first workflow, see
docs/philosophy.md.
- One binary, four personalities.
ra runfor one-shot prompts,ra acpto serve as an ACP agent over stdio for editors (Zed, Neovim ACP, …),ra serveto expose itself as an A2A agent over HTTP/JSON-RPC + REST + gRPC, andra tuifor an interactive terminal chat (requires--features tui, which pulls in opentui_rust and needs nightly Rust). - Built-in tool set.
read,write,edit,bash, native CLI helpers, structured search,jq, and web documentation tools. Usebashfor project scripts and one-off pipelines; prefer narrower tools when structured parameters and bounded JSON output are useful. ACP hosts also getfs/read_text_file,fs/write_text_file, andterminal/*reverse-call routing automatically. - Multi-backend LLM layer. Anthropic, OpenAI, Google, DeepSeek, Ollama, Groq, xAI — and any OpenAI-compatible Responses-API endpoint — via the graniet/llm crate.
- Skills + prompts + AGENTS.md. Claude Code-compatible
agentskills.io
SKILL.mdfiles (YAML frontmatter, progressive disclosure, optionalname/description,disable-model-invocation,user-invocable, and/skill-namedirect invocation), user-defined slash-command prompt templates, and agents.md auto-discovery, all unified through a single resource bundle that becomes the agent's system prompt. Ships native skills.sh support:npx skills add <repo> -a universallands SKILL.md files in./.agents/skills/and Ra picks them up automatically. Claude Code project/personal skills in./.claude/skills/and~/.claude/skills/are discovered automatically too. - Native OpenSpec. Auto-discovers a project's
OpenSpec
openspec/directory (walking cwd → git root, like AGENTS.md) and folds a catalog of its capability specs and active changes — with requirement counts and task progress — into the system prompt via progressive disclosure. By default it also folds in an agent-own spec-driven playbook: how to drive theopenspecCLI non-interactively (init --tools,new change, thestatus/instructions --jsonstate machine,validate --strict,archive -y) with no human in the loop — and on a repo with noopenspec/yet, a bootstrap hint so the agent can adopt the convention itself ([openspec] agent_own = falsefor catalog only). Ra consumes the convention; it doesn't reimplement theopenspecCLI. - Agent-owned Graphify support. Auto-discovers or targets
Graphify
graphify-out/graph.json, folds an R2A graph workflow into the system prompt, and exposesgraphify_ensure,graphify_impact, andgraphify_updatealongside native query/path/explain tools. Ra can detect missing or stale graphs, guide or run a low-cost AST refresh, and use the graph for requirement intake, planning, verification, and artifact traceability without requiring the user to run Graphify first. - HCP-flavored TOML config. Single
ra.toml(or~/.ra.toml) configures models, tools, skills, prompts, hooks, MCP servers, A2A serve/auth, remote A2A agents, observability backend, … - Lifecycle hooks. Wire-compatible with the
Claude Code hooks spec:
PreToolUse/PostToolUse/UserPromptSubmit/Stopevents with the standarddecision: "block"/permissionDecision: "deny"/additionalContext/continue: falsedecision schema, plus exit-code-2 handling. - MCP client. rmcp 1.7 with stdio + Streamable HTTP transports; remote tools surface as Ra tools the LLM can call.
- Native RTK (Rust Token Killer) support.
When
rtkis on PATH,bashcommands are routed throughrtk rewritebefore execution, swapping verbosegit status/cargo test/kubectloutput for RTK's token-compressed equivalents (60–90% savings). Configurable via[rtk] mode = "auto" | "on" | "off". - A2A everywhere. Serve as an A2A agent (with optional Bearer auth on JSON-RPC/REST/gRPC) and consume remote A2A agents as local tools.
- Trajectories on disk. Every session is persisted as ATIF v1.7
JSONL trees under
RA_HOME/sessions/<cwd-hash>/. - Observability. Wired through NeMo Relay so every prompt, tool call, and turn produces ATOF events; pipe them to stderr / a file / an OTLP endpoint.
# Create a project-local config and skills directory
cargo run -- init
# Mock model (no API key — uses the bash:/read:/write:/edit: prefixes)
cargo run -- "bash:echo hello && uname -sr"
# Real model — Anthropic
ANTHROPIC_API_KEY=sk-ant-... cargo run -- "Use bash to grep for every TODO."
# Real model — OpenAI
OPENAI_API_KEY=sk-... cargo run -- "Read Cargo.toml and explain it."
# Real model — pi (Responses API endpoint)
PI_API_KEY=sk-... \
PI_BASE_URL=https://pi-api-us.macaron.xin/v1/ \
PI_MODEL=gpt-5.5 \
cargo run -- "Use bash to print the date, then summarize."ra init writes a minimal ra.toml and creates .ra/skills/.
Existing files are left untouched; pass --force to replace generated
files, or --example-skill to add .ra/skills/example/SKILL.md.
To serve as an editor agent over ACP:
cargo run -- acp
# (your editor connects to Ra over stdio JSON-RPC 2.0)To serve as a remote A2A agent on the network:
cargo run -- serve --http-port 3000 --grpc-port 50051
# agent card: http://localhost:3000/.well-known/agent-card.json
# JSON-RPC: http://localhost:3000/jsonrpc
# REST: http://localhost:3000/rest
# gRPC: localhost:50051To pick up a saved trajectory and continue the conversation:
ra sessions # list saved sessions in this cwd's bucket
ra resume <id> "follow-up prompt"To launch the interactive terminal UI (requires nightly Rust + the
tui feature, since opentui_rust uses edition 2024):
rustup toolchain install nightly
cargo +nightly run --features tui --bin ra -- tui
# Type a prompt, Enter submits. Ctrl-C cancels a running prompt;
# press Ctrl-D or Ctrl-C twice to quit. Trajectory is saved on exit
# under the same bucket `ra resume` reads from.A2A clients reconnecting with a known task_id are auto-resumed —
the server hydrates the message log from disk before processing the
new turn, so editors / agent-team teammates can pick up exactly where
they left off across ra serve restarts.
A minimal ra.toml:
version = 1
[model]
default = "anthropic"
[[models]]
name = "anthropic"
backend = "anthropic"
model_id = "claude-opus-4-5"
api_key_env = "ANTHROPIC_API_KEY"For the full annotated example covering every section
([run], [obs], [tools], [skills], [prompts], [agents_md],
[openspec], [graphify], [resources], [a2a.serve] + auth,
[[a2a.remote_agents]], [[mcp.servers]],
[[hooks.PreToolUse]], …) see
spec/ra.toml.example. The schema is in
spec/ra-config.schema.json.
Resolution order: --config <path> → $RA_CONFIG → ./ra.toml →
~/.ra.toml. Env vars still take precedence over file values.
| Tool | Notes |
|---|---|
read |
Reads a file; routes through ACP fs/read_text_file when an editor is connected, else local fs. |
write |
Writes a file in full; ACP fs/write_text_file when available. Auto-creates parent dirs locally. |
edit |
Claude-Code-shaped: {path, old_string, new_string, replace_all}. Refuses ambiguous matches by default. |
bash |
Runs a shell command; ACP terminal/* (with permission gating) when available, else /bin/sh -c. |
ast_grep |
Read-only structural code search via ast-grep / sg; returns JSON matches. |
git |
Runs native git with argv-safe arguments; ACP hosts use the terminal reverse-call with shell quoting. This path does not use RTK. |
gh |
Runs native GitHub CLI (gh) with argv-safe arguments; ACP hosts use the terminal reverse-call with shell quoting. This path does not use RTK. |
jq |
Runs jq filters against inline JSON or a JSON file with argv-safe stdin and a bounded JSON envelope. |
mergiraf |
Runs mergiraf merge, solve, and languages actions with argv-safe arguments and bounded JSON output. |
sd |
Runs sd regex/literal find-replace across explicit file paths with argv-safe arguments and bounded JSON output. |
comby |
Runs comby structural check, diff, and rewrite actions with argv-safe arguments and bounded JSON output. |
mise |
Runs mise tasks/tests with argv-safe arguments and bounded JSON output. |
just |
Runs just recipes with argv-safe arguments and bounded JSON output. |
wrkflw |
Runs wrkflw local GitHub Actions validation/execution with argv-safe arguments and bounded JSON output. |
grep |
Structured text search; skips hidden/gitignored/build directories by default and returns JSON matches. |
glob |
Structured file discovery with glob semantics and bounded JSON output. |
ls |
Structured directory listing; non-recursive by default, recursive with depth/limit controls. |
fuzzy |
Non-interactive fuzzy candidate filtering/ranking. |
apply_patch |
Controlled git apply wrapper that checks patches before applying and uses file approval when present. |
webfetch_fetch |
Fetches one web page as Markdown through webfetch-cli, writes .md/, and returns bounded JSON. |
webfetch_crawl |
Crawls a bounded documentation subtree through webfetch-cli, mirrors .md/, and returns bounded JSON. |
openspec |
Drives the agent-own OpenSpec SDD loop through the openspec CLI as structured actions (status, list, show, instructions, validate, init, update, new_change, archive, workflow_state); non-interactive, with bounded JSON output. |
tmux_run |
Starts or reuses a Ra-owned tmux session/window and runs a command, blocking or non-blocking. |
tmux_send |
Sends literal input or tmux key names to a target pane. |
tmux_capture |
Captures visible pane content or scrollback from a target pane. |
tmux_kill |
Kills a Ra-owned tmux session/window/pane, or all ra__* sessions. |
tmux_listen |
Polls a pane until output changes or an optional substring/regex appears. |
tmux_wait |
Blocks until a tmux event, hook expression, program result, or sleep timeout resolves. |
graphify_ensure / graphify_impact / graphify_update / graphify_query / graphify_path / graphify_explain |
Added when [graphify] is enabled; maintains and uses Graphify as Ra's R2A project graph. |
Toggle the catalog via [tools] builtin = […]; an empty allow-list
ships every built-in tool. Basic tools (read, write, edit,
bash) provide the minimal local-work loop; native and extended tools cover
high-frequency structured operations where narrower parameters and
bounded output are better than composing shell strings. ast_grep is
native because it is structured code search rather than a plain shell
command. bash remains the fallback for project scripts, tests, and
one-off command pipelines.
Native git / gh / jq / mergiraf / sd / comby prioritize argv safety over RTK rewriting. If a
high-volume native CLI command needs RTK output compression, run it
through bash instead so the existing RTK rewrite path can apply.
jq requires the system jq binary on PATH; missing jq returns
structured install guidance instead of an opaque spawn error.
mergiraf, sd, and comby require their system binaries on PATH;
missing binaries return structured install guidance. Native mise / just /
wrkflw are intended for test-first task and workflow loops such as
mise run test, just test, and local GitHub Actions validation. They
run local binaries with argv-safe arguments, optional cwd/timeout
controls, bounded JSON output, and structured missing-binary guidance.
These tools spawn locally even when an ACP host is attached, so ACP
terminal permission prompts do not wrap them; use [tools].builtin and
PreToolUse/PostToolUse hooks to govern availability.
webfetch_fetch and webfetch_crawl run
npm exec --yes --package=github:trotsky1997/webfetch-cli -- webfetch-cli
under the hood; if npm is missing, the tools return structured install
guidance instead of an opaque spawn error.
The openspec tool wraps the upstream openspec CLI as structured
lifecycle actions; it always runs non-interactively (closed stdin, no
interactive prompts), forces --strict validation and explicit
confirm_archive for the destructive archive path, and returns
error.kind:"missing_openspec" with install guidance when the CLI is
absent. Ra consumes the OpenSpec convention; it does not reimplement the CLI.
tmux_run, tmux_send, tmux_capture, tmux_kill, tmux_listen, and
tmux_wait operate on Ra-owned tmux sessions named ra__{session}.
tmux_listen and tmux_wait share event expression semantics for
event, pattern, regex, and hook; tmux_wait always requires
timeout_ms. If tmux is missing, they return structured install
guidance instead of an opaque spawn error.
Authoritative schemas live in spec/ — see
spec/README.md for the index.
| Surface | Spec | Status |
|---|---|---|
| ACP | spec/acp-v1.json (+ unstable) |
full v1 implementation |
| A2A | spec/a2a.proto, spec/a2a-v1.json |
client + server (HTTP/REST/gRPC) |
| ATIF | spec/atif-v1.7.json |
written on every session |
| ATOF | spec/atof-v0.1.json |
emitted via NeMo Relay |
| HCP-flavored config | spec/ra-config.schema.json |
live JSON Schema |
| Skills | Claude Code skills / agentskills.io | YAML frontmatter, progressive disclosure, direct /skill-name invocation |
| AGENTS.md | agents.md | nearest-file-wins discovery |
| OpenSpec | Fission-AI/OpenSpec | openspec/ discovery, progressive disclosure |
| MCP | rmcp 1.7 (stdio + streamable HTTP) | client only |
| Hooks | Claude Code hooks | wire-compatible subset |
src/
├── lib.rs re-exports
├── main.rs CLI: run / acp / serve
├── config.rs ra.toml loader (HCP-flavored)
├── model.rs Model trait + MockModel
├── llm_model.rs graniet/llm bridge → multi-backend
├── session.rs turn loop + tool execution + hook gates
├── session_runner.rs streaming runner over Session
├── events.rs Event / ToolCall / ToolResult
├── tools/ built-in tool catalog
│ ├── core.rs Tool trait, Read, Bash
│ └── fs.rs Write, Edit
├── tool_ctx.rs ToolCtx + ClientHandle (ACP reverse calls)
├── acp_server.rs serve as ACP agent over stdio
├── a2a_server.rs serve as A2A agent (HTTP + gRPC, optional Bearer)
├── a2a_tool.rs consume remote A2A agents as local tools
├── mcp.rs rmcp client → Ra tools
├── skills.rs Skill / Prompt / AGENTS.md / ResourceBundle
├── openspec.rs OpenSpec project discovery → system-prompt catalog
├── hooks.rs Claude-Code-spec hook engine
├── store.rs ATIF trajectory persistence
├── atif_codec.rs in-memory ↔ ATIF JSON
└── nemo_obs.rs NeMo Relay observability scopes
What's done, what's next, and the anti-roadmap (deliberate non-goals) all live in ROADMAP.md. Contributors and AI coding agents working on this repo should also read CLAUDE.md for build commands, project conventions, and the load-bearing invariants of the hot files.