# Concepts

## The problem

A capable agent today has two of the three things it needs to act in the world. It
has a **mind** — a model that reasons. It has a **wallet** — it can hold and spend
value. What it does not have is a **body**: somewhere to be, something to be reached
at, a handle that is still there tomorrow.

Without one, every action it takes looks like it came from nowhere. Not because
anything is hidden, but because there is genuinely nothing there — no history, no
place, no continuity. Systems on the receiving end have no way to tell a persistent
counterparty from a stranger, so they treat everything as a stranger.

Incarna supplies the body and keeps it consistent.

## What a body is

Concretely, four things, fixed at creation and stable for the agent's lifetime:

**A place.** Residential network presence in a chosen country, sticky rather than
rotating. The agent comes from somewhere, and it is the same somewhere next week.

**A device.** A locked fingerprint — user agent, platform, TLS characteristics,
language. Generated once at creation and never regenerated. An identity that
presents as a different machine on every request is not one identity.

**A persona.** A handle, bio, backstory, interests and voice, generated from the
`direction` you give. Not decoration: it is what makes the agent's behaviour
coherent with its stated self.

**A wallet.** A server wallet the agent controls, on Base. Funds never live in
Incarna's process.

```
mind  ──┐
        ├──►  agent that can act, and be dealt with
wallet ─┤
        │     place  ·  device  ·  persona  ·  wallet
body  ──┘     └──────────── Incarna ────────────┘
```

## The four identity categories

Everything Incarna stores about an agent normalises into four kinds of record. This
matters because it is what lets a claim be *checked* rather than asserted.

| | | |
|---|---|---|
| **Anchor** | Something that proves the agent is reachable | an inbox that receives mail |
| **Channel** | A surface it acts through | an X account, a GitHub account |
| **Observation** | Something the network reported about it | an egress IP seen on a real probe |
| **Interaction** | Something it did | a post, an email sent |

An anchor and a channel can be the same underlying thing seen two ways — email is
both proof of reachability *and* a place to act from, so attaching an inbox writes
both records and links them.

The distinction that does the work is **observation vs. claim**. An observation is
what a third party reported; nothing about it is self-asserted. That is what
`GET /agents/{id}/identity` returns, and why its `coherent` field is worth more than
any field the agent could set about itself.

## Status lifecycle

```
                  persona + wallet both present
   provisioning ─────────────────────────────────► ready
        │                                            ▲
        │ a job exhausts its retries                 │
        ▼                                            │
    degraded ───────────────────────────────────────-┘
                  revive sweep re-runs the job
```

| Status | Meaning |
|---|---|
| `provisioning` | Created; persona and/or wallet still being generated. Body and fingerprint already exist. |
| `ready` | Persona and wallet both present. The agent can act. |
| `degraded` | A provisioning job ran out of retries. Recoverable, and recovers on its own. |

`degraded` is not terminal and does not require intervention. A background sweep
re-queues failed jobs after a delay, and any late success flips the agent to `ready`.
This exists because provider outages are measured in hours or days, and an agent
that degraded during one should not stay broken after it ends. Use
[`POST /agents/{id}/retry`](rest.md#retry-provisioning) to skip the wait.

There is no `deleted` status. Deletion is a soft delete that also zeroizes stored
credentials.

## Bring your own account

Incarna does not create accounts on platforms. `POST /agents/{id}/x`,
`/github` and `/reddit` **import an account the customer already owns**, verify it
through the agent's body, and store its credential encrypted at rest.

The verification step is not a formality — the credential is checked against the
platform before anything is written, and what comes back is recorded. For Reddit
that includes karma and account age, because those decide whether the account can
post anywhere at all; a fresh account being rejected by a subreddit is Reddit's
policy working, not a credential problem.

GitHub is the interesting case: attaching an account also holds its TOTP secret, so
the agent computes its own second-factor codes. That is why it needs no phone
number — the second factor lives with the body.

## Billing and metering

Two independent questions, deliberately not conflated:

- **Authentication** answers *may this identity act* — an API key scoped to an org.
- **Payment** answers *who pays for it* — an x402 settlement.

Paying does not grant access to someone else's agent. An x402 call still resolves a
principal; the payment is metering on top. See [x402](x402.md).

## Limits

- **120 requests per minute per organization.** Exceeding it returns `429`
  with code `rate_limited`.
- **Concurrent actions per agent** are bounded by design — a daily-cap row lock is
  held for the duration of an action, so actions on one agent serialise.
- Email inbox provisioning depends on upstream plan capacity; exhausting it returns
  `400` with the provider's message rather than silently storing a dead address.
