Agents

An agent acts for your organization with its own identity — never your login. It can only do what you grant it, and everything it does is recorded against its name. This page covers the three places an agent can run, how an outside agent connects, and the one case where you still need a mailbox API key.

Where an agent runs

Every agent is the same underneath — the same powers, the same approval rules, the same record of what it did. What differs is whose hardware it runs on, and that decides how it connects.

AnnexOrbis Cloud

Runs on a model we host. Nothing to install and no key to hand out — create it and grant it powers.

Outsourced

Runs on someone else's servers — your own box, or a hosted assistant. It reaches Annex Orbis over HTTP with one API key.

AnnexOrbis Local

Runs on a machine you authorize, paired with a one-time connect code. Not available to create yet.

Connecting an outsourced agent

Sign in as an owner or admin, open Organization → Agents, and create an agent with the host set to Outsourced. Grant it powers on its Powers tab, then open Connection and create its API key.

One key, shown once

The key looks like clo_agt_…. It identifies this agent, and the agent already belongs to your organization — so there is nothing else to configure. We store only a digest, which means the key cannot be shown to you again: copy it when it appears, and rotate if it is lost.

Give the key to the outside agent and point it at two endpoints. The first tells it what it may do; the second does it.

# What am I allowed to do?
curl https://agent-runtime.annexorbis.com/v1/outsourced/capabilities \
  -H "Authorization: Bearer clo_agt_..."

# Do one of them
curl -X POST https://agent-runtime.annexorbis.com/v1/outsourced/capabilities/invoke \
  -H "Authorization: Bearer clo_agt_..." \
  -H "content-type: application/json" \
  -d '{"capability":"crm_contact_create","dry_run":false,"arguments":{ }}'

The first call is worth making before anything else: it returns each power the agent holds, the arguments that power takes, whether it needs a human approval, and whether anything is missing — so the agent never has to guess.

Powers: what an agent may do

A capability is something the platform can do — send an email, create a contact, place a call. A power is a capability you have granted to a particular agent. Nothing is on by default: a new agent has no powers until you give it some.

Some powers also need a resource before they work — which mailbox, which phone number, which SMS number. A power granted without one is reported as unusable rather than failing later, so you find out when you grant it and not when the agent tries.

An agent can always ask what it holds, and the answer comes from the same place the rules are enforced — so what it is told and what it is allowed can never drift apart.

Rehearsals and approvals

Two things stand between an agent and the outside world, and both are on by default.

Calls rehearse by default

Every call is a rehearsal unless it explicitly sends "dry_run": false. An agent exploring what it can do changes nothing.

A person approves anything outbound

At Ask first, mail, SMS and calls come back 202 requires_approval with an approval id, and wait. Reading and internal work run normally.

How far an agent gets without a person is its autonomy, set on the Connection tab. There are three levels, and an agent can always read its own from /v1/outsourced/capabilities.

Read only

It can look at anything it has been granted and change nothing. A write is refused outright with 403 — approving will not help, because the refusal is the level itself, not a pending decision.

Ask first

It changes things inside the organization on its own. Anything that leaves — mail, SMS, a call — returns 202 with an approval id and waits for a person. This is the default.

Full autonomy

Nothing waits. Its granted powers and resource bindings still apply; the level never widens them.

The two refusals mean different things and an agent should treat them differently. A 202 is not an error — the work is queued for a human, so wait and re-send with the approval id rather than retrying. A 403 at Read only will never succeed no matter how often it is tried.

Capabilities by app

These are the capabilities available to grant. Powers are granted per agent on its Powers tab. Native apps are built into Annex Orbis; Integrations are third-party services you connect per org. Capabilities marked are external communication and are approval-gated: the agent prepares the action but a human approves before anything leaves the organization.

Mail

  • ·List emails
  • ·Read email
  • ·Mark spam
  • ·Create draft
  • ·Send draft †
  • ·List / create / apply labels
  • ·Send †
  • ·Reply / reply-all †
  • ·Forward †

Text (SMS)

  • ·Send SMS †
  • ·Read SMS thread

Phone

  • ·Place outbound call †
  • ·AI (Bland) call †
  • ·Hold
  • ·Unhold
  • ·Transfer

Team chat

  • ·Search messages
  • ·Read conversation
  • ·Post message

Tasks

  • ·List tasks
  • ·Create task
  • ·Update task

CRM

  • ·Look up contact (phone / email)
  • ·List contacts

HR

  • ·Search employees
  • ·Upcoming birthdays
  • ·Read time-off

Mail tools use a per-mailbox API key (below); the rest run over the org connection. Endpoint-level detail for the mail tools is in the API Keys reference.

Sending vs. reading mail

An agent acts on a mailbox with a per-mailbox API key. You generate a cl_live_…key for a mailbox (Mail → Settings → Domain → Mailbox → API Keys) and attach it to the agent in its Access tab, along with the mailbox address. The agent uses the key server-side — it is never exposed to the model. One key covers the whole mail surface for that mailbox; the key's scope decides how much:

Send / drafts / labels / spam

A full_access key lets the agent send, reply-all, forward (with attachments), save and send drafts, create and apply labels, and mark spam. Sending is approval-gated — it waits for a human before anything leaves the mailbox.

Reading

A read_only (or full_access) key lets the agent list and read messages — but only on open-tier mailboxes (see below).

Full endpoint reference: API Keys.

The open-tier restriction

API keys only work on open-tier mailboxes.

If you try to create a key on an end-to-end encrypted mailbox, you will see:

{ "error": "api_keys_open_tier_only" }

This is not a policy we can relax. On an end-to-end encrypted mailbox the server stores ciphertext only — it has no key and cannot read the contents. There is nothing for an API key to unlock, so an agent can never read that mailbox no matter how it is configured.

Open tier

Server-readable. Supports API keys, agent reads, fast header lists, and search. Treat contents as org-confidential.

E2EE tiers

Zero-access. No API keys, no agent reads. Choose this when a mailbox must never be machine-readable — and note that agents cannot triage it.

Full detail in the encryption tiers guide. Choose the tier when you create a mailbox — changing it later means re-creating the mailbox.

Adding a read key

  1. In the mail app, open Settings → API keys for the mailbox you want the agent to read.
  2. Create a key with read_only scope unless the agent also needs to manage the mailbox.
  3. Copy the cl_live_… value — it is shown once.
  4. In the agent's Access → Mailboxes section, choose the mailbox and paste the key.

The agent stores the key server-side and never returns it to a browser afterwards — only the last four characters, so you can tell which key is in place. Full API reference in the API keys guide.

Who did what

Every change is recorded with what kind of thing made it — a person, an agent, or an automation — along with which one, and what it was called at the time. An agent's own name is stored alongside the record, so the trail stays readable even after the agent is renamed or removed. Where an agent acted because a person asked, both are kept.