Agents
An agent is a single AI worker — one Markdown file whose YAML frontmatter configures it and whose body becomes its system prompt.
What is an agent
An agent is the smallest unit of work in rupu: a narrow, single-purpose AI worker. Each agent lives in one Markdown file. The file has two parts — a block of YAML frontmatter that tells rupu how to run the agent (which provider, which model, which tools, what it is allowed to do), and a Markdown body that is sent verbatim to the model as its system prompt.
Good agents are narrow, explicit, and testable. A well-scoped agent answers six questions clearly: what job it owns, what tools it may use, what sequence it should follow, what counts as done, what it must not do, and what shape the final answer should take. When several specialists, review boundaries, or fix loops are involved, reach for a workflow instead of one giant prompt.
The agent file
An agent is a Markdown file with YAML frontmatter. The frontmatter (between the opening and closing
--- lines) tells rupu how to run the agent; everything after the closing
--- is the system prompt. rupu parses the frontmatter with
strict unknown-field rejection — a misspelled key fails fast rather than being silently ignored.
Agent files resolve from two locations:
~/.rupu/agents/<name>.md— global agents (personal utilities).<project>/.rupu/agents/<name>.md— project-local agents (checked into the repo).
Project-local agents shadow global agents by name:. Shadowing
is all-or-nothing — rupu does not merge frontmatter or prompts. rupu agent list
shows whether each agent comes from project or global scope.
Frontmatter fields
| Key | Type | Default | Meaning |
|---|---|---|---|
name | string | required | Agent identifier used by rupu run <name> and by workflows. |
description | string | none | Human-readable summary shown by rupu agent list. |
provider | string | anthropic | Which LLM provider to use: anthropic, openai, gemini, or copilot. |
auth | api-key | sso | resolver chooses | Optional auth-mode hint when a provider has both credentials. |
model | string | config default, else claude-sonnet-4-6 | Provider-specific model id. Not validated at parse time. |
tools | array<string> | built-in + discovered MCP tools | The agent's tool allowlist. Strongly recommended to declare explicitly. |
maxTurns | integer | 50 | Hard cap on model turns (not a token budget). |
permissionMode | ask | bypass | readonly | ask | Permission model for shell and write effects. CLI --mode overrides it. |
effort | string | provider default | Cross-provider reasoning level: auto, minimal, low, medium, high, max. |
contextWindow | string | model default | Cross-provider context tier: default or 1m. |
outputFormat | text | json | free-form text | Hint for structured output; describe the JSON shape in the prompt too. |
anthropicOauthPrefix | bool | provider default | Anthropic SSO only — enables/disables the OAuth system prefix. |
anthropicTaskBudget | integer | none | Anthropic-only soft output budget, separate from maxTurns. |
anthropicContextManagement | string | none | Anthropic-only server-side pruning of older tool blocks (tool_clearing). |
anthropicSpeed | string | none | Anthropic-only account-gated fast mode (fast). |
anthropic* fields unless
you specifically need them. For checked-in repo agents, set provider,
model, tools, and permissionMode
explicitly so behavior does not drift with a mutable global default.
A complete example
This is the code-reviewer agent that ships as a rupu template — a read-only
reviewer that can inspect a local file, a diff, or a pull request and return concise findings.
--- name: code-reviewer description: Read a file, diff, or PR and return concise textual findings. provider: anthropic model: claude-sonnet-4-6 tools: [read_file, grep, glob, scm.prs.get, scm.prs.diff] maxTurns: 12 permissionMode: readonly --- You are a code reviewer. If the prompt contains a PR reference, use the SCM tools to inspect the PR metadata and diff. If the prompt names local files or includes a diff, review that directly. Focus on: - correctness bugs - missing edge-case handling - unclear or brittle structure - missing tests where behavior changed Return either: - `no issues` - or a short bulleted list ordered by severity Do not edit code.
Note the shape: the frontmatter pins a provider and model, declares the smallest useful tool set, and
runs readonly so a reviewer can never mutate the thing it is reviewing.
The body gives the agent a role, a process, and an explicit output contract.
Tools & permissions
The tools: field is the agent's tool allowlist. If you omit it, the agent gets
the full built-in surface plus, when SCM / issue connectors are configured, any discovered MCP tools. For
reusable repo agents, an explicit list is far better than the implicit wide-open default.
The built-in tools are:
bash— run shell commandsread_file·write_file·edit_file— file I/Ogrep·glob— search and match
MCP-backed tool names are also valid — for example scm.prs.get,
scm.prs.diff, scm.prs.create,
issues.get, issues.comment. The allowlist supports
exact matches (scm.prs.get), prefix wildcards (scm.*),
and a global wildcard (*).
tools: gates the tool calls an agent may
make. It is not the same as a workflow's actions:, which gates the
action protocol emitted from agent output inside a workflow.
Permission modes
permissionMode controls what an agent may do without confirmation:
| Mode | Meaning |
|---|---|
ask | Prompt before shell and write effects. The safest default for agents that edit code. |
bypass | Execute allowed tools without confirmation. |
readonly | Allow reads, deny writes. |
readonly blocks the built-in writes (write_file,
edit_file, destructive shell work via bash) and MCP
write tools such as scm.prs.create, issues.comment,
issues.create, and scm.branches.create. Because
ask cannot proceed in a non-interactive context, pass
--mode bypass or --mode readonly explicitly there. The
CLI --mode flag always overrides the value in the file.
Providers & models
rupu supports four LLM providers, each with two authentication modes (API key or SSO):
| Provider | API key | SSO | Notes |
|---|---|---|---|
anthropic | yes | browser callback | Console API key or Claude.ai SSO. The most exercised provider. |
openai | yes | browser callback | Platform API key or ChatGPT SSO. |
gemini | yes | browser callback | API key via Google AI Studio; SSO via Vertex / CLI. |
copilot | yes | device code | API-key path uses a GitHub PAT; requires paid Copilot. |
An agent picks its provider with provider: and its model with
model:. Model ids are provider-specific and are not validated
at parse time — an invalid id fails at runtime when the provider is called. When an agent omits
model:, rupu falls back to the provider's
default_model from ~/.rupu/config.toml; there is no
global default, so the agent must either set model: or have one resolvable in config.
rupu run resolves a model id through three sources, in order: custom entries
under [[providers.<name>.models]] in config, the live cache
(~/.rupu/cache/models/<provider>.json, TTL 1h), then a baked-in list for
providers with limited listing endpoints. Inspect what is available with
rupu models list and refresh the caches with
rupu models refresh.
Authenticate a provider before running an agent against it:
# API key (or pipe the secret on stdin) rupu auth login --provider anthropic --mode api-key --key <secret> # SSO rupu auth login --provider anthropic --mode sso
Generate one from a description
Don’t want to hand-write the frontmatter? Describe the agent in plain language and let rupu draft it for you. create generates the .md with a model (running a validate → repair loop so the result actually parses) and opens it in your editor to refine.
# scaffold + AI-draft an agent from a one-line brief rupu agent create security-reviewer \ --describe "A read-only reviewer that audits a diff for OWASP Top 10 issues and returns JSON findings" # or scaffold an empty agent and edit it yourself (omit --describe) rupu agent create my-agent
The same generate-from-a-description flow is available in the control plane’s authoring UI.
Running an agent
List and inspect the agents rupu can see, then run one:
# list every resolvable agent (project + global scope) rupu agent list # show one agent's resolved frontmatter and prompt rupu agent show code-reviewer # run an agent with a prompt rupu run code-reviewer --prompt "Review the staged diff for correctness bugs"
Use --mode to override the file's permissionMode at
run time — for example --mode bypass or --mode readonly
in a non-interactive context. Every run is recorded as a JSONL transcript you can replay later:
# inspect a recorded run
rupu transcript