# MCP Integration
Source: https://docs.reasonos.com/agents/mcp
rbs speaks the Model Context Protocol in both directions: serve rbs tools to any MCP client, and connect external MCP servers to the rbs agent.
rbs integrates with the [Model Context Protocol](https://modelcontextprotocol.io) in both directions:
* **As a server** — `rbs mcp serve` exposes the agent's tool surface (graph queries, build/test, search, skills) to any MCP client: Claude Desktop, Claude Code, ChatGPT, or your own tooling.
* **As a client** — MCP servers declared in your workspace give the rbs agent extra tools (a browser, a database, an internal API) for its sessions and for `ai_task` targets.
## Serving rbs as an MCP server
```bash theme={null}
# stdio mode — for Claude Desktop, Claude Code, and similar clients
rbs mcp serve
# HTTP mode — a streamable HTTP server
rbs mcp serve --http :3001
```
In stdio mode the server speaks MCP on stdin/stdout. In HTTP mode, point your client at `http://localhost:3001/mcp`.
A Claude Desktop configuration looks like:
```json theme={null}
{
"mcpServers": {
"rbs": {
"command": "rbs",
"args": ["mcp", "serve"]
}
}
}
```
Run it from (or configure the client to start it in) your workspace directory — the server loads the workspace so graph and authoring tools answer from your real target graph.
### The curated tool surface
By default the server exposes a **curated** subset of the agent's tools: file reading, search, the graph and knowledge-graph queries, build/test, dependency inspection, and skills. Several tool categories are excluded on purpose:
* **Interactive tools** that block waiting on the rbs UI (they would hang your client)
* **Agent-loop internals** (todo management, plan mode) that only make sense inside the rbs agent's own loop
* **Agent-spawning tools** (delegation, background agents) that would issue LLM calls from inside the server
* **Write tools** that mutate the workspace or run commands — excluded unless you opt in
Adjust the surface with flags shared by `serve` and `list`:
```bash theme={null}
# Include mutating tools (write_file, str_replace, delete_file,
# run_command, rbs_run, task/lesson writers) in the curated surface
rbs mcp serve --allow-write
# Expose every runtime tool
rbs mcp serve --tools full
# Drop specific tools by name (applies in both modes)
rbs mcp serve --exclude-tools rbs_run,delete_file
```
`--allow-write` and `--tools full` let a connected client edit files and execute commands in your workspace. Only enable them for clients you trust, and prefer `--exclude-tools` to trim anything you don't want reachable.
### Previewing the surface
`rbs mcp list` prints exactly what a connected client would see, honoring the same flags — including which tools are excluded and why:
```bash theme={null}
rbs mcp list
rbs mcp list --tools full
rbs mcp list --allow-write --exclude-tools rbs_run
```
### Skills as resources and prompts
Beyond tools, the server publishes the agent's [skill corpus](/agents/skills):
* every skill is an MCP **resource** under `rbs://skills/` (for example `rbs://skills/bootstrap-workspace`, `rbs://skills/using-go-rules`)
* two composed **prompts** let a client bootstrap rbs context in one call: `rbs-onboarding` (workspace bootstrap, monorepo conventions, verification discipline) and `rbs-build-file-authoring` (how rules and `BUILD.rbs` files work)
This is how an external agent working in your workspace gets the same maintained guidance the built-in agent runs on.
## Work tools on managed branch servers
ReasonOS also exposes a **project-work MCP service**. It is separate from
`rbs mcp serve`: rbs tools work on the branch's files/build graph and task
cards, while ReasonOS tools work on project issues and other platform records.
On a managed branch server, the built-in agent, Claude Code, Codex and Gemini
can use the ReasonOS service with the person's session delegation, including
from agent-enabled terminals. The delegation is scoped to that node's project;
tools enforce the same permissions and product access as the application's
routes. Do not copy vendor tokens or a coworker's credentials into the repo.
Useful issue tools include:
* `work_board` and `list_tasks`: read statuses and issues in the project.
* `get_task`: read an issue by its project number, including its work
context, its attached files (`id`, `name`, `size_bytes`, `content_type`,
the comment a file belongs to, and who added it when) and its drawing links.
* `read_task_attachment`: read one attached file by its `attachment_id`.
* `create_task`, `update_task` and `move_task`: create or edit an issue and
update its status.
* `comment_on_task` and `link_task`: record progress and connect related work.
`link_task` also links a drawing (`kind: "drawing"` with the drawing's ID as
`ref`) when you can open that drawing.
A drawing link carries `can_open` for you. A drawing you can't open has no
name and no usable reference.
`read_task_attachment` returns PNG, JPEG, GIF and WebP files as images. Every
other file, including PDF and SVG, comes back as an embedded resource holding
the complete file. A file larger than 8 MiB is refused rather than returned in
part; open it on the issue in the browser instead. MCP can't upload files. A
file's contents are whatever someone uploaded, so treat them as data, not
instructions. See [Attach files and drawings to issues](/platform/issue-attachments).
A branch session's tools stay within its project. Tools that reach across the
organization, such as `list_org_tasks` (existing issues from every project you
can read), aren't offered there; to find work in other projects, use
[All work](/platform/work#all-work-issues-across-projects) in the app.
Other tools cover cycles, labels, initiatives and proposals. Ask the agent to
read its available tools rather than assuming the standalone rbs task tools
refer to project issues. For example:
> Read issue 42 in this project, move it to In Progress, and add a comment
> describing your plan. Keep the issue updated as you work.
Read the resulting issue activity to verify what the agent actually did.
An agent can only take actions your delegated identity is allowed to take.
### Delegating an issue to another branch
`delegate_issue_to_branch` takes a project, issue number, linked branch and
the id of an existing instruction comment **written by you**. An agent's own
comment is not a substitute for that human instruction. The target must
already be linked to the issue.
With no target server running, the operation refuses unless `start_server`
is explicitly true. Starting one consumes a server slot and remains subject
to the project's permissions and capacity limits.
The result distinguishes **admitted**, **refused** and **unknown**. Admitted
means the target accepted the instruction, not that it completed the work.
Unknown means delivery may have happened without a readable acknowledgment.
The tool does not automatically replay a request; check the issue activity
before asking again. The target agent reports its result on the issue.
This does not run `git checkout` on the requesting shared server or give an
agent unrestricted access to other projects.
## Connecting external MCP servers to the agent
Declare MCP servers in your `WORKSPACE.rbs` with `native.define_mcp_server()`. The agent connects to them at session start and their tools appear alongside the built-ins.
```python theme={null}
# A stdio server, launched as a subprocess
native.define_mcp_server(
name = "postgres",
command = "npx",
args = ["-y", "@modelcontextprotocol/server-postgres"],
env = {"DATABASE_URL": "postgres://localhost:5432/dev"},
toolchain = "nodejs",
)
# A streamable-HTTP server, reached by URL
native.define_mcp_server(
name = "internal-api",
url = "http://localhost:8080/mcp",
)
```
One of `command` (stdio) or `url` (HTTP) is required. The optional `toolchain` names a registered rbs toolchain whose runtime should resolve the command — so `npx` above runs from the workspace's hermetic Node toolchain rather than whatever is on `PATH`.
Skip connecting for a session with `rbs agent --no-mcp`.
### The Chrome DevTools server
For browser automation, rbs bundles a helper that registers a Chrome DevTools MCP server — this is what powers `ai_qa_test` browser tests:
```python theme={null}
load("@rbs//agent/mcp/chrome/mcp.rbs", "chrome_mcp_server")
chrome_mcp_server(
name = "chrome",
headless = True,
# Set install_chrome = True to download Chrome for Testing via the
# toolchain system — useful in CI where no browser is installed.
)
```
### MCP in `ai_task` targets
Headless [agent tasks](/agents/using-the-agent#headless-agent-tasks-in-the-build-graph) name the servers they need with the `mcp` attribute; only those servers are connected for the run:
```python theme={null}
native.ai_task(
name = "qa_checkout",
todos = ["open the store", "add an item to the cart", "verify the total"],
mcp = ["chrome"],
run_targets = [":dev"],
)
```
## MCP and the external engines
When a session runs on an [external engine](/agents/overview#engines), rbs
configures the agent with the workspace's declared MCP servers and rbs's own
tools. Managed branch sessions also receive the scoped ReasonOS Work service
described above. These services have different permissions and purposes;
enabling a standalone rbs MCP server alone does not connect it to ReasonOS
project issues.
# Coding Agent Overview
Source: https://docs.reasonos.com/agents/overview
The ReasonOS coding agent is built into rbs — it works from your workspace's dependency graph and builds, tests, and runs code through the build system itself.
ReasonOS ships a coding agent as part of `rbs`. It is not an editor plugin bolted onto a build tool — the agent, the build system, and the editor share one workspace model, so the agent reasons about your code the same way `rbs` does: as a graph of targets.
## What makes it different
### Graph-first
Most coding agents explore a repository by searching text. The ReasonOS agent starts from the workspace dependency graph instead. It has first-class tools to:
* list and inspect **targets** (`rbs_targets`), their dependencies (`rbs_deps`) and reverse dependencies (`rbs_rdeps`)
* find which target **owns** a source file (`rbs_owners`)
* compute the **affected** set for a change (`rbs_affected`)
* navigate the workspace knowledge graph — symbols, communities, impact analysis, and path-finding between code entities (the `atlas_*` tools)
That means "what breaks if I change this?" is a graph query, not a guess.
### Build-system-native
The agent builds and tests through `rbs`, with the same caching and hermeticity you get on the command line:
* `rbs_build` and `rbs_test` run real targets and stream real output
* `rbs_run` / `rbs_start` / `rbs_stop` execute and manage long-running targets (dev servers, services) in the background
* `rbs_rules` and `rbs_validate` let it author and check `BUILD.rbs` files against the actual rule catalog before writing them
* external dependency tools let it inspect resolved packages rather than guessing at APIs
When the agent says a change builds and its tests pass, it verified that through the build system — not by eyeballing the diff.
## Engines
The agent runtime supports several software choices, called **agents** in the
UI and **engines** in configuration. The model and its account or API key are
separate choices. Each engine integrates with the workspace tools.
The in-house, multi-provider engine, also called native. On managed branches,
available models come from the accounts and keys configured for you and the
project. This is also the engine behind `rbs agent` on the command line.
Drives Anthropic's Claude Code CLI as the session's engine. It uses Claude Code's own authentication and receives the rbs tool surface (graph queries, build/test, skills) over MCP, plus a generated `CLAUDE.md` block describing the workspace conventions. Available when the `claude` binary is installed on the branch node.
The same arrangement for OpenAI's Codex CLI: its own authentication, the rbs tool surface over MCP, and workspace conventions delivered via `AGENTS.md`. Available when the `codex` binary is installed on the branch node.
Runs Google's Gemini CLI with the workspace tools. Available when the
`gemini` binary is installed on the branch server and the account has access.
**Selecting an agent:** use the **Agent** and **AI model** choices in
[AI Work](/platform/ai-work), or the editor's chat controls. A resumed
conversation retains its existing agent and model. The `rbs agent` CLI uses
the built-in engine.
**Defaults have a scope:** Project settings → **Default agent** selects the
starting agent for new branch servers; it does not replace settings on
already-running servers. Organization Settings → **Agent installation**
controls installed CLIs. Your account → **Personal AI accounts** connects your
credentials. See [AI accounts and keys](/platform/ai-accounts-and-keys) for
branch defaults, browser-local preferences and optional overrides.
## Where it runs
* **Terminal** — `rbs agent` starts an interactive session in your shell: a plain REPL by default, or a full-screen interface with `--tui`. See [Using the agent](/agents/using-the-agent).
* **The ReasonOS editor** — the editor connects to your branch node's server, which hosts agent sessions alongside the language servers and file watchers. Sessions are multi-client: teammates on the same branch see the same node.
* **Across the managed application** — [AI Work](/platform/ai-work) opens the
agent alongside project pages, cycles and proposals without opening the
editor. It still runs on a branch server, with your project permissions.
* **Headless** — `rbs agent "your prompt"` runs a single turn and exits, and `ai_task` targets put agent-driven work (including browser QA tests) directly into the build graph, runnable with `rbs run` and `rbs test`.
## Sessions, memory, and checkpoints
**Sessions.** A session is one conversation with the agent — its transcript, permission mode, todo list, and background subagents. Editor sessions persist; CLI chats can be saved. Saved chats live in the committed `.reasonos/ai/chats/` tree, so they travel with the branch through git rather than living on any one machine.
**Memory.** The agent keeps two durable stores per branch, both committed under `.reasonos/ai/`:
* **Lessons** — observations about what worked and what failed in this repository, recorded as it works. Recent lessons are injected into every new session's context.
* **Taste** — style preferences for how this codebase likes its code written.
Because both are committed, an agent joining a branch inherits what previous sessions learned there. Long conversations are compacted automatically so a session never runs out of context mid-task.
**Checkpoints.** In the editor, the agent snapshots the workspace's file state before it starts modifying files. Every checkpoint records exactly what changed, and you can diff against or revert to any checkpoint — so letting the agent work is never a one-way door. See [Checkpoints](/workflow/checkpoints) for the full workflow.
## Learn more
CLI invocations, models and providers, permission modes, and headless tasks.
The agent's loadable expertise: built-in skills and how to add your own.
Serve rbs tools to external agents, and connect external tools to the rbs agent.
# Agent Skills
Source: https://docs.reasonos.com/agents/skills
Skills are loadable units of expertise — how to work in your repository. The agent ships a built-in corpus and learns new skills from your workspace.
A **skill** is a named, loadable set of instructions for doing a particular kind of work: how to use a rule family, how to verify a change, how to bootstrap an empty workspace. The agent sees every skill's name and description up front, and loads the full body only when it decides it needs it — so fifty skills cost almost nothing until one becomes relevant.
## How skills get invoked
* **By the agent itself** — the session context lists every available skill with its description; the agent calls its `skill` tool to load one before doing matching work (using a rule family for the first time, authoring `.rbs` build files, finishing a change).
* **By you** — in the TUI, `/skills` lists the corpus, `/skill ` shows a skill's body, and every skill is offered as its own slash command: `/verification` asks the agent to load and apply that skill.
* **Over MCP** — every skill is also published as an MCP resource when you run `rbs mcp serve`, so external agents can read the same corpus. See [MCP integration](/agents/mcp).
## Built-in skills
The built-in corpus has two halves: workflow skills that apply everywhere, and one usage guide per rule family. A rule family's skill ships in the same module as its rules — load the Go rules and "how to use the Go rules" is right there, and it cannot drift from the implementation.
| Skill | What it teaches |
| - | - |
| `bootstrap-workspace` | Turning an empty workspace (graph shows 0 targets) into a building project — verified starting files, in build order. |
| `monorepo-conventions` | Target naming, scaffolding, and layout conventions that make CI and affected-target selection work with zero setup. |
| `rbs-rule-authoring` | Authoring a new build rule when no existing rule expresses how something builds — read before writing any `define_rule`. |
| `verification` | How to verify work before reporting it done: build, test, and actually run it. |
| `writing-tests` | Writing tests that catch real regressions: the right layer, the real environment, pinned to defects. |
| `concise-code` | Writing the smallest correct diff: find what already exists, extend live code, delete dead code, match the local idiom. |
| `reliability` | Making a component production-reliable: atomic writes, content validation over existence checks, fail-closed semantics, bounded resources. |
| `delegation` | Using the delegation and background-agent tools: when to fan out, how to brief a subagent, how to integrate results. |
| `sql-migrations` | Writing and running SQL migrations with `rbs migrate` so every schema change stays safe for the previous and next application version. |
| `env-schema` | Declaring and consuming workspace environment with `.env` files and the composable `.env.schema`. |
| `pr-and-stacks` | Creating change requests and working in stacked diffs with `rbs stack`. |
One `using--rules` skill per built-in rule family:
| Skill | Covers |
| - | - |
| `using-go-rules` | Go binaries, tests, coverage gating, cross-compiling, proto codegen. |
| `using-python-rules` | Python binaries/libraries/tests, pip dependencies, the hermetic toolchain, linting. |
| `using-nodejs-rules` | Node.js services and tools, npm dependencies, test runners, linters. |
| `using-typescript-rules` | TypeScript language support and how tsconfig resolution is owned by generated config. |
| `using-web-vite-rules` | Web micro-frontends: module federation hosts/remotes, shared libraries, vitest coverage gates, SSR. |
| `using-java-rules` | Java binaries/libraries/tests, Maven dependencies, the hermetic JDK toolchain. |
| `using-kotlin-rules` | Kotlin/JVM targets mirroring the Java rules, shared Maven ecosystem. |
| `using-c-rules` | C targets, the hermetic C toolchain, automatic `compile_commands.json`. |
| `using-cxx-rules` | C++ targets and the hermetic C++ toolchain. |
| `using-dotnet-rules` | C#/.NET builds driven by `dotnet publish`, pinned SDK toolchains. |
| `using-proto-rules` | Protobuf/gRPC codegen: protoc toolchains and per-language proto libraries. |
| `using-oci-rules` | Container images: building, tarballs, and pushing via `rbs run`. |
| `using-k8s-rules` | Kubernetes deploys with rendered manifests and deploy-time image resolution. |
| `using-infra-rules` | Cloud infrastructure declared in `.rbs` files, multicloud providers, `rbs infra plan/apply`. |
| `using-migration-rules` | SQL migration targets driven by `rbs migrate`. |
| `using-job-rules` | Batch and ML compute job targets and the job scheduler CLI. |
| `using-agent-rules` | Extending the agent itself from the build language: custom tools, skills, subagents, QA tests, MCP servers. |
## Custom skills
You can add skills in two formats, and both share the same surface as the built-ins.
### RBS language: `native.define_skill`
Declare a skill in any `.rbs` module — typically next to the thing it teaches. A `skills.rbs` under your workspace's `rules/` directory is discovered automatically, without anything loading it:
```python theme={null}
native.define_skill(
name = "using-my-rule",
description = "When and how to use my_rule targets",
usage = "optional one-line usage hint",
prompt = """# Using my_rule
...usage guidance, a worked example, common mistakes...
""",
)
```
If you author a custom build rule, ship its skill in the same module — every workspace that loads your rules also teaches its agents how to use them.
### Claude Code format: `SKILL.md`
The agent also reads skills in Claude Code's format, from the same places Claude Code looks: `.claude/skills//SKILL.md` in the workspace, then in your home directory. An existing skill library carries over without being copied:
```markdown theme={null}
---
name: release-notes
description: How we write release notes for this repo
---
The full instructions go here...
```
### Precedence
When the same name exists in several places, the first source wins, in this order:
1. Skills registered by `.rbs` modules the workspace actually loads
2. `.claude/skills/` in the workspace, then your home directory
3. Skills declared in the workspace's `rules/` tree
4. Skills from fetched external rule packages
5. The embedded built-ins
So a workspace can override any built-in skill by shadowing its name.
# Using the Agent
Source: https://docs.reasonos.com/agents/using-the-agent
Run the coding agent from the terminal: interactive sessions, one-shot prompts, model selection, permission modes, and headless agent tasks.
## Starting a session
Run `rbs agent` from anywhere inside a workspace:
```bash theme={null}
# Interactive session (plain REPL)
rbs agent
# Full-screen terminal interface
rbs agent --tui
# One-shot: run a single turn and exit
rbs agent "why is //api:server_test failing?"
```
Without arguments, the agent starts an interactive session with inline permission prompts. With a prompt argument it runs one turn headless and exits — nothing prompts, and mutations are denied unless you pass a `--mode` that allows them.
On startup the agent loads the workspace — `WORKSPACE.rbs` and every `BUILD.rbs` — so its graph tools answer from your real target graph, and connects any MCP servers declared in the workspace.
## Providers and API keys
The native engine discovers model providers from your environment:
| Environment variable | Provider |
| - | - |
| `ANTHROPIC_API_KEY` | Anthropic (Claude models) |
| `OPENAI_API_KEY` | OpenAI (GPT models) |
| `GOOGLE_API_KEY` or `GEMINI_API_KEY` | Google (Gemini models) |
| `XAI_API_KEY` | xAI (Grok models) |
| `REASONOS_LLM_URL` + `REASONOS_TOKEN` | ReasonOS hosted service |
Keys come from the environment on purpose — workspace files are committed, and an API key in a committed file is a leaked key. When the hosted service is configured, it also acts as a fallback for models no local provider serves.
## Choosing a model
Pass `--model` with a model ID, a short alias, or a `provider/model` reference:
```bash theme={null}
rbs agent --model claude-opus-5 # full model ID (the default)
rbs agent --model sonnet # alias
rbs agent --model fast # alias (Claude Haiku)
rbs agent --model hosted/fast # provider/model reference
rbs agent --model gpt-5 "review the diff on this branch"
```
Inside a session, `/models` lists every model your configured providers can serve. Useful aliases include `opus`, `sonnet`, `fable`, `haiku`, `fast`, `gpt5`, `gemini`, and `grok`.
For models with controllable reasoning, `--effort low|medium|high|max` sets how hard the model thinks per step.
## Permission modes
The agent asks before doing anything destructive. The session's **mode** sets its default posture toward mutating tools:
| Mode | Behavior |
| - | - |
| `manual` | Ask before anything that edits files or executes commands. The default. |
| `accept_edits` | Allow file edits without asking; still ask before executing commands. |
| `auto` | Allow everything. Never a default — you must choose it. |
| `plan` | Deny every mutation. Investigation only. |
```bash theme={null}
rbs agent --mode accept_edits
```
In an interactive session, permission requests appear inline: answer with a numbered option or a bare `y`/`n`. You can allow a tool "for the rest of the session" so you are not asked repeatedly — that consent does not carry over if you later switch to a more permissive mode. Switch modes mid-session with `/mode`:
```
› /mode accept_edits
```
Headless runs (`rbs agent "prompt"`) have no one to ask, so anything that needs consent is **denied**, not silently allowed. Pass `--mode auto` only when you intend a fully autonomous run.
## Flags
| Flag | Effect |
| - | - |
| `--model ` | Model ID, alias, or `provider/model` reference |
| `--mode ` | Permission mode: `manual`, `accept_edits`, `auto`, `plan` |
| `--effort ` | Reasoning effort: `low`, `medium`, `high`, `max` |
| `--max-steps ` | Cap model calls per turn |
| `--worktree ` | Isolate the session's edits in a git worktree |
| `--tui` | Full-screen terminal interface (interactive only) |
| `--no-graph` | Skip loading the build graph |
| `--no-mcp` | Skip connecting workspace MCP servers |
| `--print-prompt` | Print the assembled system prompt and tool definitions with sizes, then exit |
The global `rbs` flags also apply — notably `-e`/`--env` to select the workspace environment and `--workspace-root` to point at a workspace explicitly.
## Slash commands
In the plain REPL:
```
/mode [m] show or set the permission mode
/todos show the session task list
/agents list background subagents
/processes list background processes the agent started
/models list available models
/help show commands
/quit exit
```
The `--tui` interface supports those plus `/clear`, `/model`, `/tools`, `/skills`, `/skill `, `/status`, `/session`, `/save`, and `/history`. Every loadable [skill](/agents/skills) is also offered as its own slash command — typing `/verification`, for example, asks the agent to load and apply that skill.
## Isolating edits with a worktree
On a branch node several people (and several agents) can share one checkout. To keep an agent's edits out of the shared tree, give the session its own git worktree:
```bash theme={null}
rbs agent --worktree fix-flaky-test
```
The agent edits files in an isolated worktree on its own session branch; merging its work back is an explicit, reviewable step rather than an accident of interleaving.
## Saving and reviewing sessions
In the TUI, `/save` writes the current chat to the committed `.reasonos/ai/chats/` tree and `/history` lists recent saved chats. Because chats are committed, they travel with the branch — a teammate pulling the branch can read what the agent did and why.
The CLI does not resume a saved chat into a live session — each `rbs agent` run starts fresh (with the branch's [lessons and taste memory](/agents/overview#sessions-memory-and-checkpoints) already loaded). Editor sessions on the branch node persist across reconnects.
## Delegation and background agents
The agent can fan work out rather than doing everything in one context:
* **`delegate` / `delegate_parallel`** — hand scoped tasks to subagents and wait for their conclusions. Good for large searches and self-contained investigations.
* **Background agents** — `start_agent` launches a named agent that keeps working while the conversation continues; `/agents` lists them, and the session can read from, message, or stop them.
You can define reusable subagent presets in the build language — a name, system prompt, and restricted tool set — with `native.define_subagent(...)` in any loaded `.rbs` module, then request them by name when delegating.
## Headless agent tasks in the build graph
`ai_task` targets make agent-driven work a first-class part of the graph. Declared with `kind = "test"` (the default) they are discoverable by `rbs test`; they can start services first, connect MCP servers, and run the agent through an ordered list of steps in `auto` mode.
The most common form is a browser QA test, using the bundled `ai_qa_test` wrapper — it wires up a Chrome DevTools MCP server so the agent can drive a real browser:
```python theme={null}
load("@rbs//agent/ai_task.rbs", "ai_qa_test")
ai_qa_test(
name = "qa_login",
run_targets = [":dev"], # start the dev server first
todos = [
"go to the login page",
"sign in with the seeded test user",
"verify the user id is shown in the header",
],
headless = True, # set False to watch the browser
timeout = 300,
)
```
```bash theme={null}
rbs test //web/app:qa_login
```
Under the hood this is the `ai_task` rule, which you can use directly for non-browser tasks:
```python theme={null}
native.ai_task(
name = "smoke",
kind = "test", # "test" targets run under `rbs test`
todos = ["build //api:server", "run its unit tests", "report PASS or FAIL"],
run_targets = [], # targets to start in the background
mcp = [], # MCP server names to connect
model = "", # optional model override
timeout = 300, # seconds
)
```
The task passes when the agent completes its steps and reports success; otherwise the target fails like any other test.
# Adopt an existing repo
Source: https://docs.reasonos.com/build/adopt
Run rbs in any repo with zero config — run/build/test detect the project type automatically, and rbs adopt materializes the same config as editable files
rbs works in a repository that has never heard of it. In a directory with
no `WORKSPACE.rbs`, the everyday commands detect the project type
themselves and run against a synthesized workspace — and `rbs adopt`
materializes that same config as real files when you want to start editing
it.
## Zero config: just run it
```bash theme={null}
cd my-existing-service # a plain Go / Node / Python repo
rbs run # ⚡ detects the stack, builds, runs the app
rbs build # builds everything it synthesized
rbs test # runs the detected test targets
```
Detection fingerprints the project (a `go.mod`, a `package.json`, a
`requirements.txt`, …) and generates config under `.rbs/zero-config/` —
rbs-owned state, never your checkout; rbs even adds `.rbs/` to
`.git/info/exclude` so `git status` stays clean. Bare `rbs run` runs the
detected default target. Run the commands from a subdirectory and rbs
detects at the enclosing git root. `rbs query` and `rbs graph` show the
synthesized targets too, and agents running on the branch server see the
same graph.
Opening a non-rbs repo in the ReasonOS editor shows the same thing as a
slim banner: *"Zero-config: detected go — build, run and test already
work."* Its **Adopt** button writes the exact config zero-config has been
executing into the repo — the same files `rbs adopt` produces.
## Adopt: materialize the config
`rbs adopt` writes the `WORKSPACE.rbs` and `BUILD.rbs` a person familiar
with rbs would have written by hand — toolchain pinned from your version
files, dependencies declared from your manifest, a runnable binary target,
test targets when tests exist. It is byte-identical to what zero-config
mode was executing, so nothing changes behavior — the config just becomes
yours to edit.
```bash theme={null}
cd my-existing-service
rbs adopt
# then it's a normal rbs workspace:
rbs build :all
rbs run //:my_service
rbs test
```
The generated files are yours: they carry a "review and edit" header, and
`rbs adopt` never rewrites them afterwards. There is no hidden
configuration layer — what adopt generates is exactly the config you edit
as the project grows.
## Command forms
```bash theme={null}
rbs adopt # adopt the current directory
rbs adopt path/to/repo # adopt another directory
rbs adopt --list # show every matching converter, ranked
rbs adopt --dry-run # print the generated files without writing
rbs adopt --converter python # override detection ranking
rbs adopt --force # overwrite previously generated files
```
Adopt refuses a directory that already contains a `WORKSPACE.rbs`, and
refuses to nest a workspace inside an existing one — add a `BUILD.rbs`
package to the enclosing workspace instead.
## What gets detected
| Converter | Fingerprints | Generated config |
| - | - | - |
| **go** | `go.mod`, `go.work`, `main.go` | `go_toolchain` matched to the `go.mod` directive; `go_binary` for the root package or one per `cmd/*`; `go_test` over `./...` when `*_test.go` exist; an `oci_image` so `rbs build //:image` produces a container image |
| **java** | `pom.xml`, `build.gradle`, `build.gradle.kts`, `gradlew` | `java_toolchain` from `java.version`/`maven.compiler.*`/`sourceCompatibility` (any JDK major works); `java_repository` per declared Maven/Gradle dependency; `java_library` + `java_binary` (main class auto-detected, `@SpringBootApplication` preferred); `java_test` with JUnit auto-included when `src/test/java` exists |
| **python** | `pyproject.toml`, `requirements.txt`, `Pipfile`, `manage.py`, `main.py`/`app.py`/… | `python_toolchain` from `.python-version` or `runtime.txt`; `py_repository` per pinned requirement; `py_binary` (Django gets `manage.py runserver`); `py_test` when tests exist |
| **kotlin** | `*.kt` sources (usually Gradle) | `java_toolchain` + `kotlin_toolchain`; `kotlin_repository` per Gradle dependency; `kotlin_binary` with the detected top-level main; `kotlin_test` |
| **node** | `package.json` | `nodejs_toolchain` (an exact `engines.node` pin is honored); `nodejs_repository` per production dependency; `nodejs_binary` from `scripts.start`, the `main` field, or `server`/`index`/`app` in `.js` or `.ts`; `vitest_test` when vitest and test files are present |
| **vite** | `vite.config.*` | `nodejs_toolchain`; `nodejs_repository` deps; `vite_app` for the detected `src/main.*` entry; `vitest_test` — takes precedence over plain node for Vite apps |
| **dotnet** | `*.csproj` | `dotnet_toolchain` (SDK from ``); `dotnet_binary` with sources plus the project file |
| **c / c++** | `*.c` / `*.cpp` sources | hermetic zig-based `c_toolchain`/`cxx_toolchain`; `c_binary`/`cxx_binary` (CMake/meson/Makefile definitions are reported, not parsed) |
## Container image out of the box
For Go projects the generated config includes a container image: a
cross-compiled linux binary on a minimal `scratch` base. Building it needs
no Docker daemon — rbs assembles the image itself:
```bash theme={null}
rbs build //:image
docker load < .rbs/bin//image/image.tar
docker run :latest
```
The generated file explains how to switch the base image (for CA
certificates or a shell) and how to upgrade to a multi-arch image index.
Node and Python images aren't generated yet — they need a linux-native
runtime inside the image; the converter tells you so during adopt.
When a repo matches several converters, ranking follows language priority
first (a Go service with a docs `package.json` adopts as Go), then
detection confidence. Anything a converter can't translate — an unpinned
requirement, a `file:` dependency, TypeScript builds — is reported as a
note during adopt, never silently dropped.
## Extending detection
Converters are Starlark, not compiled-in logic. Rule authors register one
with `native.define_project_converter(name, detect, convert, priority)`,
and detection is extensible without rebuilding rbs — point at an external
converter pack:
```bash theme={null}
rbs adopt --rules https://git.example/acme-converters@v1.0.0
# or, for every adopt and zero-config run on this machine/node:
export RBS_CONVERTER_RULES=https://git.example/acme-converters@v1.0.0
```
A pack is a git repo (fetched pinned to the ref, same as `rbs ext`) or a
local directory whose `convert.rbs` modules register converters. A pack
converter that re-declares an embedded name overrides it. See
[Custom rules](/reference/custom-rules) for the rule-authoring surface.
# Caching
Source: https://docs.reasonos.com/build/caching
How the shared content-addressed cache speeds up builds, and how to inspect and manage it with rbs cache.
rbs has exactly one build cache: a **user-global, content-addressed store** shared by
every workspace on your machine. Build a target in one workspace, and any other
workspace that produces the same action gets a cache hit — no per-project cache
directories to warm up or clean out.
## Where the cache lives
By default the store lives under `~/.cache/rbs` (the content store itself sits in a
versioned subdirectory, e.g. `~/.cache/rbs/v1`). To relocate it — for example onto a
larger volume — set `RBS_CACHE_DIR`:
```bash theme={null}
export RBS_CACHE_DIR=/mnt/bigdisk/rbs-cache
```
Your workspace's `.rbs/` directory is **not** a cache. It holds only materialized
state — build outputs, toolchain links, resolved external dependencies — all of which
rbs recreates on demand. Deleting `.rbs/` forces a rebuild but loses nothing durable.
The cache is **user-global**. Every workspace on the machine reads from and writes to
the same store, so cache management commands affect all of your projects at once —
never just the one you happen to be standing in.
## What gets cached
The store holds two kinds of entries:
* **Content blobs** — the files actions produce (and consume), addressed by their
content hash. Identical content is stored once, no matter how many targets or
workspaces reference it.
* **Action results** — a record that a given action (command + inputs + environment)
already ran, pointing at the blobs it produced. When you rebuild, rbs looks up each
action here and restores its outputs instead of re-executing it.
Alongside the content store, rbs keeps other user-global caches that the `rbs cache`
commands manage with the same age bounds:
* **OCI images** — container images pulled for image-based rules
* **Toolchains** — downloaded language toolchains (see [Toolchains](/build/toolchains))
* **External deps** — resolved third-party packages (see
[External dependencies](/build/external-dependencies))
* **Terraform providers** — provider plugins downloaded for infra targets
## Inspecting the cache
```bash theme={null}
rbs cache stats
```
This reports the store location and the size of each cache:
```text theme={null}
📊 Cache Statistics
===================
Store: /Users/you/.cache/rbs/v1
(shared across every workspace for this user)
📦 Content blobs: 12841 (3120.44 MB)
🎯 Action results: 1904 (12.10 MB)
🐳 OCI images: 812.30 MB
🔧 Toolchains: 1450.02 MB
📚 External deps: 640.88 MB
🧩 Terraform providers: 210.55 MB
📊 Total: 6246.29 MB
```
Run inside a workspace, `stats` also breaks down that workspace's materialized
`.rbs/` state, one line per top-level directory — useful for seeing where local disk
usage actually is:
```text theme={null}
🗂 Workspace state: /Users/you/myproject/.rbs
gocache 2140.11 MB
out 890.45 MB
toolchains 0.02 MB
total 3030.58 MB
(materialized from the store and sources; deleting it forces a rebuild but loses nothing durable)
```
## Bounding the cache: `rbs cache gc`
Garbage collection is the recommended way to keep the cache in check. It sweeps
entries by age first, then evicts the least-recently-used content until the store is
under its size budget:
```bash theme={null}
# Defaults: drop anything not accessed in 30 days, keep the store under 20 GiB
rbs cache gc
# Custom bounds
rbs cache gc --max-age 14d --max-gb 10
```
| Flag | Default | Meaning |
| - | - | - |
| `--max-age` | `30d` | Collect anything not accessed within this window |
| `--max-gb` | `20` | Size budget in GiB; least-recently-used blobs beyond it are collected |
Age values support weeks and days on top of the usual units: `2w`, `7d`, `24h`,
`30m`, `90s`.
The same pass also ages out the OCI image cache, the toolchain store, the
external-deps store, and Terraform providers. Anything swept is rebuilt or
re-downloaded automatically the next time it's needed.
You rarely need to run `gc` by hand — rbs runs a bounded GC pass automatically at
most once per day after builds. Run it manually when you want space back right now.
## Removing entries: `rbs cache clean`
`clean` removes store entries outright:
```bash theme={null}
# Remove entries older than 7 days
rbs cache clean --max-age 7d
# Remove everything (every workspace's next build goes cold)
rbs cache clean --all
```
Bare `rbs cache clean` — with no flags — is **refused**:
```text theme={null}
refusing to empty the shared store at /Users/you/.cache/rbs/v1 — it is used by every workspace for this user
rbs cache gc bound it by age and size (recommended)
rbs cache clean --max-age 7d remove entries older than 7 days
rbs cache clean --all remove everything (rebuildable, but every build goes cold)
```
Because the store is shared, "clean this project" is never what emptying it would do.
Make the intent explicit with `--max-age` or `--all`. Everything `clean` removes is
rebuildable — but after `--all`, every build on the machine starts from scratch.
# Everyday commands
Source: https://docs.reasonos.com/build/commands
Build, test, run, query, graph, and coverage — the rbs commands you use all day
Six commands cover the day-to-day loop. They all accept the same
[labels and target patterns](/build/packages-and-targets#target-patterns), and they all
share three global flags:
| Flag | Purpose |
| - | - |
| `-e, --env ` | Select an [environment](/build/environments) declared in `.env.schema` (also `RBS_ENV`) |
| `--platforms ` | Target platform to build for (e.g. `linux-amd64`) |
| `--workspace-root ` | Explicit workspace root (also `RBS_WORKSPACE_ROOT`) |
## rbs build
Builds one or more targets, resolving the full dependency closure, executing in
dependency order, and running independent targets in parallel. Results come from the
shared cache when nothing relevant changed.
```bash theme={null}
rbs build :hello # one target in the current package
rbs build //services/api:server # one target by full label
rbs build //... # everything in the workspace
rbs build :all # everything in the current package (the default)
rbs build services/api server migrate # several targets in one package
```
Key flags:
| Flag | Purpose |
| - | - |
| `-j, --jobs ` | Cap parallel jobs (`0` = unlimited, the default) |
| `--no-cache` | Re-run every action for this build instead of using cached results |
| `--cache-mode ` | `auto` (default), `force-miss`, or `force-hit` |
| `-w, --watch` | Rebuild automatically when source files change |
| `--remote ` | Use a remote cache (defaults to `$RBS_REMOTE` when set) |
| `--remote-exec` | Execute cache misses on the remote cluster's workers |
```bash theme={null}
rbs build //app:lib --watch # auto-rebuild on change
rbs build //... --remote cache.internal:8980 # share results with your team
```
Before executing, rbs prints the execution plan — every target in the closure and what
it depends on — so you can see exactly what a build will do.
## rbs test
Builds the requested targets and runs the ones that are tests. Test targets are the
ones declared with a test rule (`go_test`, `py_test`, `vitest_test`, and so on — any
rule whose kind ends in `_test` or is registered as a test).
```bash theme={null}
rbs test :all # all tests in the current package (the default)
rbs test //... # every test in the workspace
rbs test //services/api:api_test # one test target
rbs test :api_test --watch # TDD: re-run on every file change
```
Test output is captured under `.rbs/testlogs////test.log`, so
a noisy suite doesn't scroll your terminal history away.
`rbs test` does **not** enforce coverage thresholds. If a test target declares
`min_line_coverage` (or branch/function thresholds), `rbs test` runs it and prints a
reminder — the gate only fires under `rbs coverage`.
## rbs run
Builds a target (and its dependencies), then executes it.
```bash theme={null}
rbs run :server # build and run 'server' in the current package
rbs run //tools:migrate # full label
rbs run services/api server # natural syntax
```
### Multiple targets in parallel
Pass several targets — or `-p/--parallel` — and rbs builds them all first, then runs
them simultaneously. `Ctrl+C` stops every process. This is the standard way to bring up
a local stack:
```bash theme={null}
rbs run //services/api:server //web/shell:dev --parallel
rbs run shell:shell remote:counter # two or more targets imply parallel mode
```
### Watch mode
`--watch` rebuilds and restarts the process whenever source files change:
```bash theme={null}
rbs run :server --watch
```
### Side-effect targets
Building stays pure — nothing a build does touches the outside world. Rules whose whole
point is a side effect (pushing an image, applying manifests) perform it at **run**
time instead:
```bash theme={null}
rbs run //services/api:push # push the built image to its registry
rbs run //services/api:deploy # apply the rendered Kubernetes manifests
```
## rbs query
Lists targets matching a pattern without building anything. Useful for exploring a
workspace and for scripting.
```bash theme={null}
rbs query # every target in the workspace (//...)
rbs query //services/... # everything under services/
rbs query //services/api:all # one package
rbs query :dev # one target in the current package
```
| Flag | Purpose |
| - | - |
| `-o, --output ` | `label` (default, one label per line), `kind` (`