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.

YAML frontmatter provider · model · tools · permissions system prompt the Markdown body an agent rupu run <name>
Config plus a system prompt is everything an agent is.

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:

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

KeyTypeDefaultMeaning
namestringrequiredAgent identifier used by rupu run <name> and by workflows.
descriptionstringnoneHuman-readable summary shown by rupu agent list.
providerstringanthropicWhich LLM provider to use: anthropic, openai, gemini, or copilot.
authapi-key | ssoresolver choosesOptional auth-mode hint when a provider has both credentials.
modelstringconfig default, else claude-sonnet-4-6Provider-specific model id. Not validated at parse time.
toolsarray<string>built-in + discovered MCP toolsThe agent's tool allowlist. Strongly recommended to declare explicitly.
maxTurnsinteger50Hard cap on model turns (not a token budget).
permissionModeask | bypass | readonlyaskPermission model for shell and write effects. CLI --mode overrides it.
effortstringprovider defaultCross-provider reasoning level: auto, minimal, low, medium, high, max.
contextWindowstringmodel defaultCross-provider context tier: default or 1m.
outputFormattext | jsonfree-form textHint for structured output; describe the JSON shape in the prompt too.
anthropicOauthPrefixboolprovider defaultAnthropic SSO only — enables/disables the OAuth system prefix.
anthropicTaskBudgetintegernoneAnthropic-only soft output budget, separate from maxTurns.
anthropicContextManagementstringnoneAnthropic-only server-side pruning of older tool blocks (tool_clearing).
anthropicSpeedstringnoneAnthropic-only account-gated fast mode (fast).
Note. Keep agents portable by avoiding the 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:

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 vs. actions. 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:

ModeMeaning
askPrompt before shell and write effects. The safest default for agents that edit code.
bypassExecute allowed tools without confirmation.
readonlyAllow 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):

ProviderAPI keySSONotes
anthropicyesbrowser callbackConsole API key or Claude.ai SSO. The most exercised provider.
openaiyesbrowser callbackPlatform API key or ChatGPT SSO.
geminiyesbrowser callbackAPI key via Google AI Studio; SSO via Vertex / CLI.
copilotyesdevice codeAPI-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
Next. When a job needs multiple specialists, review boundaries, fan-out, or fix loops, compose agents into a workflow rather than growing one agent prompt.