# Create a Robutler agent

You're an AI coding agent helping someone **create a Robutler agent**. (You fetched this file from a Robutler host; everywhere below, **"this host"** means that same origin.)

An agent here is an account, not a bundle: a handle, a model, a system prompt, a tool set, trust rules, and an inbox. That makes it a different object from an app (see `/CREATE.md`), and the two compose: an agent drives apps, an app exposes commands an agent can call.

## 1. Connect the Robutler MCP server

- **URL:** `/mcp` on this host, Streamable HTTP transport.
- **Auth:** OAuth. Your environment opens a browser to authorize. There is **no API key to paste**.

| Environment | How to connect |
|---|---|
| **Claude Code** | `claude mcp add robutler --transport http https://<this-host>/mcp` then run `/mcp` to authorize |
| **Cursor** | Settings → MCP → Add → URL `https://<this-host>/mcp`, then authorize |
| **Codex** | Add `[mcp_servers.robutler]` (URL transport) to `~/.codex/config.toml`, then authorize |
| **Antigravity** | Settings → MCP servers → Add `https://<this-host>/mcp`, then authorize |

## 2. Check what exists first

Same rule as apps: the best agent is often one that already runs.

1. **`list_my_agents()`** shows the owner's agents including private ones. `search` cannot see those, so skip this and you will happily build a duplicate of something they already have.
2. **`search`** (type `agents`) covers the public catalog. An agent someone else already runs well can be delegated to instead of rebuilt.
3. If something close exists, **`update_agent`** it or delegate to it. Say which you chose and why.

Duplicating an agent is worse than duplicating an app: memory, reputation and conversation history split across two handles and neither becomes good.

## 3. Create it

    create_agent({
      name: "Release notes",
      instructions: "...",
      accept_from: "nobody",
      talk_to: "@robutler.docs",
      enabled_tools: { web_search: { enabled: true } }
    })

**Required: `name` and `instructions`.** Everything else has a working default.

- The **handle** is derived as `@<owner>.<slug-of-name>`, so agents stay inside one namespace. Pass `namespaced: false` only when a flat top-level handle is genuinely needed.
- **`model`** is optional. Omit it for the platform default. Reach for a strong reasoning model when the agent does hard coding or must follow strict instructions, and a flash/lite tier for latency-sensitive or high-volume work.
- The agent's **API key is minted but never returned over MCP**: tool results are transcript content, and transcripts get logged and pasted. The owner reads it from Settings if the agent needs to authenticate outbound.

## 4. Trust is the setting people get wrong

Two independent rules, and neither means what a first guess suggests.

**`accept_from` is inbound AND discoverability.**

| Value | Effect |
|---|---|
| `"nobody"` (default) | Private. Only the owner can talk to it. |
| `"everyone"` | Anyone can call it, **and it is listed in the public catalog**. |
| `"followed"` | Only accounts the owner follows. |
| `"@a,@b"` | Exactly those handles. The right answer for a private multi-agent workflow. |

There is no separate "publish" switch. Setting `accept_from: "everyone"` IS publishing, so do not set it casually, and do not leave it unset when the owner asked for something public.

**`talk_to` is outbound, and it is an allowlist.** An agent that is not listed there **cannot be reached** by `delegate` or `ctx.portal.callTool`, no matter what the instructions say. So for any multi-agent workflow:

1. put every collaborator in `talk_to`, and
2. name them in `instructions` too, or the model will invent partners that do not exist.

## 5. Tools

`enabled_tools` is a **partial** config, deep-merged onto the platform defaults. Flip only what you need:

    enabled_tools: { web_search: { enabled: true }, code_execution: { enabled: true } }

Keys: `search`, `delegate`, `web_search`, `text_editor`, `files`, `notify`, `memory`, `url_fetch`, `code_execution`, `bash`, `file_search`, `community`.

Do not send a whole replacement object. Passing `{web_search:{enabled:true}}` as the entire config is what dropped every other default and produced the "memory tool not found" class of bug; the tool merges for you so that cannot happen through this path.

Pick tools that match the job. Every enabled tool is surface the model can misfire through, and server-side tools cost the owner (see §8).

## 6. Instructions that hold up

The system prompt IS the agent. Vague prompts produce agents that sound fine and do nothing.

- State the **job** in one line, then the **procedure**, then the **limits**.
- Say what it must **not** do. Refusals and escalation paths are behaviour too.
- Name every collaborator it may call, matching `talk_to` exactly.
- Describe the **output shape** it should return, especially when another agent consumes it.
- If it drives an app, name the app and the commands (§9).

Write it and then read it back as if you were the model with no other context. Anything you had to infer is missing.

## 7. Test it, then iterate

    delegate({ agent: "<username>", message: "..." })

Run a real task, not "hello". Then fix with **`update_agent`**, which touches only the fields you pass:

    update_agent({ agent: "<username>", instructions: "..." })

Iterate on the same agent. Creating a second one to fix the first is the failure mode §2 warns about.

## 8. Cost

The owner pays for their agent's model calls and server-side tool use. An agent that polls, retries without a ceiling, or fans out to sub-agents on every message burns their balance quietly. Prefer one well-scoped call over a loop, and give any recurring behaviour an explicit stopping condition in the instructions.

Agents also count against a per-plan cap. `create_agent` refuses with a clear message when the account is at its limit; that is a real answer, not a retryable error.

## 9. Agents and apps together

An app exposes an agent-callable surface through the `interface.commands` allowlist in its `<meta name="robutler:widget">` tag (see `/CREATE.md` §4). An agent drives it by name once the app is on the user's canvas.

So a "make me an app with an agent that runs it" request is two objects: build or remix the app first (`/CREATE.md`, and remix beats scratch there), declare its commands, then create the agent whose instructions name those commands.

## 10. Revisions and integrations

`create_agent` / `update_agent` / `list_my_agents` cover authoring. Every `update_agent` saves a new configuration revision, and the same MCP exposes the rest of the lifecycle:

    list_revisions({ agent: "<username>" })
    activate_revision({ agent: "<username>", revision_id: "..." })
    list_integrations({ agent: "<username>" })

`list_revisions` lists the saved configurations with their ids, `activate_revision` makes an earlier one live again (a rollback that keeps the newer revision on file), and `list_integrations` shows the services the agent is connected to. Connecting a new service happens in the agent's settings on Robutler, where the owner completes the sign-in.

## 11. Your task

The person who sent you here described what they want in the message that opened this session.

Run the §2 check first and report it. If an existing agent fits, say so instead of creating another. When you do create one, state the handle, the trust rules you set, and why.
