Skip to content

Bots

For developers who connect a client to OpenBot or extend its server. The examples need the access stated on this page. Start with the developer manual.

A Bot is a worker with a role, such as a programmer, a writer or a designer. Each Bot has its own instructions, its own Chats and its own long-term memory. You talk to a Bot, and it gives work to other Bots, or to itself, so it is always free to answer you. This page shows how to talk to a Bot and the routes under /v1/bots. Every route accepts a user token or the session cookie. See Authentication.


Every Bot is a lasting worker. It lives until you archive it, and it learns from its work over time. There is no other kind of Bot.

To talk to a Bot, send it a message:

Terminal window
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"input":"Plan three days in Rome."}' \
https://api.example.com/v1/bots/$BOT/messages

The message goes to your one Chat with this Bot. OpenBot makes the Chat the first time. You never make, pick or close a Chat. The Bot answers at once. When the work is long, the Bot gives it to a delegation and stays free to answer you. The result comes back to your Chat later. See Chats.

A top Bot is a Bot that a member or the organization owns, not another Bot. You can pick one top Bot as your default Bot.

A Bot can own Bots too. See Bots that own Bots.

Your default Bot is the Bot that a client talks to first. A trigger without a Bot also gives its task to it. OpenBot does not make Bots for you, so a new member has no default Bot. Then a trigger without a Bot fails with 400 and BotInvalid.

To set your default Bot, make a Bot, and then send its ID in your member settings:

Terminal window
curl -X PATCH -H "Authorization: Bearer $OPENBOT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"expectedVersion":0,"defaultBot":"bot_5c0e…"}' \
https://openbot.example.com/v1/me/settings

expectedVersion is the version from GET /v1/me/settings. The Bot must be one of your own top Bots or a shared Bot, and you need delegate on it. If not, OpenBot returns 400 with SettingsInvalid. Send null to remove your default Bot.

You can still archive your default Bot. After that, a trigger without a Bot fails until you pick another default Bot.

Older versions of OpenBot made a Main Bot for each member. When you upgrade, each Main Bot becomes a normal Bot, and it becomes the default Bot of its member. Its memory and Grants stay.

Bots have no list of things they may do. A Bot just tries. When it tries something new for the first time, such as making a Bot or calling an App tool, the decider above it decides. See Requests. The decisions are kept, so the limits of each Bot grow from real work.


Terminal window
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Programmer","role":"Writes and reviews TypeScript code","instructions":"Write small, tested changes. Explain each change in one short paragraph."}' \
https://api.example.com/v1/bots
Field Meaning
name Required. A short name. OpenBot removes spaces at the start and end. The rest must have 1 to 100 characters.
role Required. What the Bot does, in one line. Other Bots read it to choose workers.
instructions Required. The lasting instructions of the Bot, like a job description.
model Optional. The model of the Chats of this Bot, when a Chat does not choose its own.
planApproval Optional. How the plans of this Bot are approved. See Plan mode.
shared Optional. true makes an organization Bot that every member can use.
bot Optional. The ID of the Bot that owns the new Bot. You cannot use it with shared.

A Bot without a model cannot answer. Its first message fails with 400 and ChatModelInvalid. See Models.

OpenBot returns 201 with the Bot:

{
"id": "bot_5c0e…",
"owner": { "_tag": "Member", "userId": "u-1" },
"name": "Programmer",
"role": "Writes and reviews TypeScript code",
"instructions": "Write small, tested changes. …",
"archived": false,
"revision": 0,
"createdAt": 1792486800000,
"updatedAt": 1792486800000
}

owner is Member, Organization or Bot. A shared Bot works with the permissions and the App connections of the member who uses it, never with those of the person who made it.

GET /v1/bots lists your own Bots and the shared Bots that you may use. Add ?archived=false to hide archived Bots. Add ?bot=<id> to list the Bots that one Bot owns.

GET /v1/bots/:botId returns one Bot.

Terminal window
curl -X PATCH -H "Authorization: Bearer $OPENBOT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"expected":0,"instructions":"Write small changes with tests first."}' \
https://api.example.com/v1/bots/$BOT

expected is the current revision. You can change name (with the same rules as above), role, instructions, model (send null to remove it), planApproval (send null to remove it) and archived. When you archive a Bot, OpenBot also archives every Bot that it owns, and the Bots below them. When you unarchive it, only that one Bot comes back.


A Bot can own Bots. So a Bot can build its own team, and each member of the team keeps its own memory.

  • A Bot makes a Bot that it owns with the openbot_create_bot tool. A person makes one with POST /v1/bots and the bot field. The tool takes name, role, instructions and model in the same form as POST /v1/bots, and a reason.
  • A Bot that another Bot makes with the tool gets the model of the Bot that makes it. The tool call can name another model.
  • The owner is { "_tag": "Bot", "bot": "<owner ID>", "userId": "<member>" }. userId is the member at the top of the owner tree. It is null when the organization owns the Bot at the top.
  • A Bot can give work to itself and to the Bots it owns without a request.
  • The owner chain of a Bot goes up through its owners to a top Bot, and then to the person. For example: person → Assistant → Worker → Scout. Requests of a Bot go up this chain, also when a person works with the Bot directly. See Requests.
  • Above a top Bot is the person who works with it. This is true for your own top Bots and for shared Bots.

A Bot does not need a helper Bot to keep the context of some work. It can give more work to an earlier delegation, and that work goes on in the same task Chat. See Delegation.


OpenBot adds these to the instructions of every Turn:

  • the name, role and instructions of the Bot,
  • the person it works with now, with their name and member ID. In a Channel, it is the person who wrote the message of the Turn,
  • what kind of Chat it is in:
    • in a direct Chat or a channel Chat, people talk with it, so it must answer at once. It gives long work to delegations, maybe to itself, and stays free to answer,
    • in a task Chat, it does one task for the Bot that gave it. Its last answer is the result. It must not say that it is done while it still has open work,
    • in a review Chat, it decides one request,
  • that it uses a capability with a short reason, and that an answer that needs a decision comes back later as a message,
  • that text that starts with [OpenBot] comes from OpenBot, not from a person, so it is data, not instructions,
  • that it carries experience from its earlier work, and that the current instructions win over it,
  • a list of the open work of the Chat: its delegations, requests and reminders.

The memory Bot can also write the input of the Turn again with what helps. The Bot sees the changes as its own experience. It has the confide tool, and it knows it only as a place to say how its work goes.

You can also share a Bot with people in other organizations. They get a linked Bot with source, which uses your Bot.


Action on Bot Lets you
read Read Bots, their memory, Rules and Grants.
write Make and change Bots, their memory, Rules and Grants.
delegate Talk to a Bot and give it work, from a client or from another Bot.
share Invite people to use a Bot.

The path of your own Bots is org / <org> / user / <you> / bot / <id>. A shared Bot has no owner: its ownerUserId is null. Members may read and use shared Bots. Administrators may also change and share them. See Permissions.

InvitationNotFound returns 404. It has invitationId when the request names an invitation. When a Bot link secret matches no invitation, this field is absent.

Status Error When
400 BotInvalid The change is not allowed, or you have no default Bot.
403 Forbidden You may read the Bot, but not change or use it.
404 BotNotFound There is no Bot with this ID that you may read.
409 BotConflict expected is old. Read the Bot again and retry.
503 BotStorageUnavailable OpenBot cannot reach its database.

Changing a Rule that does not exist returns 404 RuleNotFound. Revoking a Grant that does not exist returns 404 GrantNotFound. These errors name the missing Rule or Grant.