Agents
Plugin for Butterbase.ai
npx -y skills add butterbase-ai/butterbase-skills --skill agentsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Use when designing, deploying, or debugging a Butterbase Agent (declarative LLM/tool graph), registering an MCP server for tool use, or wiring access controls and rate limits. Agents are first-class app resources defined by a `graph_spec` and invoked over `/v1/<app_id>/agents/<name>/runs`.
SKILL.md
7.0 KB, as published. Nobody here has run it
Butterbase Agents
A Butterbase agent is a declarative graph of LLM and tool nodes — not a free-running chat loop. The runtime traverses the graph, calls tools (builtin / MCP / function), and resolves the end node's output_template. State, rate limits, and budgets are enforced by the control plane.
When to use
- The user wants to add a workflow that combines an LLM with tool calls (DB writes, storage reads, MCP servers, app functions).
- The user wants to expose an agent endpoint to end users (
visibility: publicorauthenticated). - Debugging a failing agent run (look at
list_agent_runs, thenget_agent_run). - Registering an external MCP server for the agent to use.
Don't use for plain LLM chat completions — use the ai skill (manage_ai / /v1/ai/chat). Agents are for stateful, multi-step, tool-using workflows.
Concepts
graph_spec (validated by validate_agent_spec before anything is persisted)
| Field | Required | Notes |
|---|---|---|
spec_version | yes | Literal "1". |
entry | yes | ID of the first node. |
nodes | yes | Record { id → node }. |
edges | yes | [{ from, to }]. Both endpoints must exist in nodes. |
tools | yes | { builtin: [], mcp_servers: [], functions: [] } — declares what nodes can call. |
limits | yes | max_steps (1–200), max_tool_calls (0–500), max_parallel_tools (1–16), timeout_seconds (5–3600), human_timeout_seconds (60–7×24×3600). |
Node types:
llm—model,system_prompt,input_template,output_key,tools: [toolRef], optionaltemperature(0–2),max_tokens.tool—tool_ref,args_template(record),output_key.end—output_template(string; can interpolate{{output_key}}values).
toolRef is a discriminated union by source:
{ source: 'builtin', name }{ source: 'mcp', server_id, name }{ source: 'function', name }
Each may carry mode_override (read_only | read_write) and exposed_to_override (developer_only | end_user).
Builtin tools (always available, no setup)
| Name | Purpose | Args |
|---|---|---|
query_table | Select rows (RLS enforced) | table, filter, limit (≤200) |
insert_row | Insert | table, values |
update_row | Update by id | table, id, patch |
delete_row | Delete by id | table, id |
read_storage | Get object (≤5 MB) | key |
write_storage | Put object (≤1 MB b64) | key, content_base64, content_type? |
auth_user_lookup | Find a user | email OR id |
All builtins respect role: end_user runs as butterbase_user with their user id (RLS applies); developer_only runs as butterbase_service.
MCP servers
Register before referencing in graph_spec.tools.mcp_servers. Transports: sse, http, streamable_http. The control plane probes on register (calls listTools()), stores status='healthy'|'unhealthy'. Re-probe with the same endpoint after a server URL change.
Access & limits
| Field | Default | Notes |
|---|---|---|
visibility | private | private (owner only), authenticated (any app user), public (anyone, with rate limits). |
max_runs_per_user_per_hour | null | null = unlimited. |
max_runs_per_ip_per_hour | null | Primary public-agent throttle. |
max_runs_per_app_per_hour | null | App-wide cap. |
daily_budget_usd | null | Hard kill once exceeded. |
max_concurrent_runs | null | |
safety_acknowledged | false | Required true if visibility ≠ private AND any node calls a write tool (insert_row, update_row, delete_row, write_storage, or a write-mode MCP/function tool). |
Procedure
Designing a new agent
- Sketch the graph in prose first. "User asks X → LLM rephrases → query_table for context → LLM answers → end." Concrete node IDs.
- Write the spec as a JSON file in the repo (e.g.
agents/<name>.json) — versioning it in git makes templates portable and letsbutterbase repo pushcarry it to clones. - Validate without persisting — call
validate_agent_spec(MCP) or pass the file to avalidate_agent_speccall. Surface any Zod issues to the user with field paths. - Register MCP servers if used:
agent_mcp_serverstable (MCP-tool wrapper TBD; use the dashboard or POST/v1/<app_id>/agent-mcp-serversdirectly). Wait forstatus: healthy. - Create —
create_agentwith name, graph_spec, default_model, access fields. Ifvisibility ≠ 'private'and any write tool is reachable, require the user to explicitly say "yes, I acknowledge" and setsafety_acknowledged: true. - Smoke —
invoke_agentwith a small input. Pollget_agent_rununtil terminal. Show the user the run timeline (steps, tool calls, final output).
Editing
update_agentis a PATCH. Pass only changed fields. Bumpinggraph_specrevalidates; runs in flight against the old spec finish unmolested.- Disabling an agent:
update_agent { status: 'disabled' }— new runs return 403, existing runs keep going.
Debugging a failing run
list_agent_runsfiltered by agent name, thenget_agent_run(run_id)for the event timeline.- Check
error.code:validation_failed(spec issue),tool_error(named tool, named arg),budget_exceeded,rate_limited,timeout. - For tool errors, re-run the same
args_templatewith the underlying tool directly (select_rows,invoke_function, etc.) to confirm the issue is in the tool's surface, not the agent runtime. - For
human_input_requiredcheckpoints, resume withresume_agent_run(run_id, user_input).
CLI
butterbase agents list/get <name>/create -f spec.json/update <name> -f patch.json/delete <name>— read/write specs from files. Useful for version-controlling agents alongside app code.
Anti-patterns
- ❌ Skipping
validate_agent_spec. Zod issues are clearer than the runtime errors you get from a bad spec at first invocation. - ❌ Setting
visibility: publicwith write tools and no rate limits. The control plane will refuse withoutsafety_acknowledged: true, but you should also set per-IP limits and a daily budget. - ❌ Putting secrets in
system_promptorargs_template. Read them fromctx.envinside a function tool instead — agent specs are visible to anyone who can read the agent. - ❌ Letting an LLM node call itself recursively without a
max_stepsceiling. Always cap. - ❌ Forgetting that builtin DB tools respect RLS. If
query_tablereturns empty, the calling role probably can't see the rows — checkexposed_to. - ❌ Treating agents as part of clone replay. Agent records are not copied when an app is cloned — bundle the spec JSON in the repo (
agents/*.json) and document recreation in the README.