Concepts
The handful of rules that explain how Aibo behaves. Everything here is enforced by the API.
Tenancy
A tenant is your business. Every user, agent, chat and message belongs to exactly one tenant, and every request is filtered to the tenant of the authenticated principal — there is no way to read or address another tenant's data.
Agents
An agent has a name (≤ 24 chars), role (≤ 40), bio (≤ 240, what it helps with), a tone, an optional avatarSeed, and an optional systemPromptOverride. Its scope is decided by who creates it:
- Called as the tenant,
POST /v1/agentscreates atenantagent;GET /v1/agentslists tenant agents. - Called as a user,
POST /v1/agentscreates auseragent owned by that user;GET /v1/agentslists tenant agents plus the user's own agents. Filter with?scope=tenant|user. - Users may update or archive only their own agents.
DELETE /v1/agents/{id} archives the agent: it stops replying and leaves its chats, but its past messages are kept. Pass includeArchived=true when listing to see archived agents.
Handles and namespaces
Every agent has a handle used for @mentions (^[a-z0-9]{1,32}$). You don't choose it — it is derived from the name when the agent is created:
- Slug:
name.toLowerCase().replace(/[^a-z0-9]/g, ''), truncated to 32 characters. An empty slug falls back toaibo. - If that handle is taken, append the smallest integer ≥ 2 that is free (
money,money2,money3, …). - Renaming an agent later does not change its handle.
Handles live in namespaces:
| Namespace | Holds |
|---|---|
tenant |
All tenant agents, shared by the whole tenant |
user:{userId} |
One user's personal agents |
The uniqueness rules are:
- A user agent can't take a handle already used by any tenant agent or by another of that user's agents.
- A tenant agent can't take a handle that any agent in the tenant already holds (including every user's personal agents).
Because every chat contains one human, and its agents are only that user's agents plus tenant agents, a handle is always unique inside a chat — @handle is never ambiguous.
| Name given | Already taken | Resulting handle |
|---|---|---|
Money |
— | money |
Money |
money |
money2 |
Dr. Who? |
— | drwho |
🙂 |
— | aibo |
Chats
A chat belongs to exactly one human (its owner). Its other members are agents: tenant agents and/or that user's own agents.
- DM (
type: "dm"): exactly one agent. Creating a DM with an agent you already have a DM with returns the existing chat (200) instead of a new one (201). - Group (
type: "group"): 2–7 agents, so at most 8 members including the human. Groups may have aname(≤ 60 chars). GET /v1/chatslists the user's chats, most recent activity first; filter with?type=dm|group.- Multi-human chats are not supported.
Reply routing
After a user message is stored, the platform decides which agents reply. Precedence:
- Explicit mentions. Agents in the chat that are
@mentionedreply, in the order they were first mentioned. Mentions of handles that aren't members of the chat are ignored. - DM. Otherwise, in a DM, the one agent replies.
- Orchestrator. Otherwise, in a group, the orchestrator picks one agent by topic. If it can't decide, a deterministic fallback picks the first agent.
Replies are serial: when several agents respond, each finishes before the next starts. Agents don't mention or trigger each other — only the human's message drives routing.
"@billing @money was that double charge in my budget?" → billing, then money
"hey @MONEY" → money (mentions are case-insensitive)
"email me at dana@acme.test" → not a mention (orchestrator decides)
"Can you explain this invoice?" (group) → one agent chosen by topicThe non-streaming response (202) includes responders: the agent ids that will reply, in order.
Messages, history and memory
- Messages have a
sender(user,agentorsystem), akind(textorsystem) andcontent(user messages ≤ 8000 chars). GET /v1/chats/{chatId}/messagesreturns messages newest first; pass the returnednextCursorascursorto page backwards (limit1–100, default 50).- Agent memory is managed by the platform and scoped per agent and per user, so one user's conversations never inform another user's replies. There is no API for reading or editing memory in this version.
DELETE /v1/users/{externalId}permanently deletes the user along with their agents, chats and messages.DELETE /v1/chats/{chatId}deletes one chat.
Tone presets
tone is one of five presets that shape how the agent writes:
| Tone | Feels like |
|---|---|
warm |
Friendly and encouraging |
direct |
Brief, to the point, no filler |
playful |
Light, witty, informal |
gentle |
Calm, patient, reassuring |
sharp |
Precise, critical, challenges assumptions |
systemPromptOverride
By default the platform generates each agent's system prompt from its bio and tone (plus tenant context). Set systemPromptOverride (≤ 8000 chars) to replace that generated bio + tone prompt with your own. Send null in PATCH /v1/agents/{id} to go back to the generated prompt.
await server.agents.update(billingId, {
systemPromptOverride: 'You are Acme Billing. Only discuss invoices, refunds and payment methods. Never promise refunds; offer to open a ticket.',
});curl -sS -X PATCH "$AIBO_URL/v1/agents/agt_billing…" \
-H "Authorization: Bearer $AIBO_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"systemPromptOverride":null}'