Changelog
Concepts

Entities & addressing

Every running agent is an entity with one URL-shaped id, and that single string identifies it everywhere.

Every running agent is an entity with a stable, URL-shaped id — and that one string identifies it everywhere: in the API, in every event it writes, in the stream URLs your UI reads.

Anatomy of an entity URL

/t/default/a/researcher/01j9z8k3q7v2m8f4t6d1c5b0aa
 │    │    │     │        │
 │    │    │     │        └─ instance id (a sortable ULID by default)
 │    │    │     └─────────── agent type (your defineAgent type name)
 │    │    └───────────────── entity marker, always the literal "a"
 └────┴────────────────────── tenant — one per deployment, "default" unless configured

The tenant segment is a deployment-wide constant: one running stack is one tenant, so in practice it always reads /t/default/… (or whatever your deployment names itself). You never juggle tenants day to day — the segment exists so identifiers stay unambiguous if deployments ever merge or migrate.

Segments are lowercase alphanumerics plus - and _. Uppercase, dots, and slashes inside a segment are rejected.

The short form

The API and the CLI accept a tenant-less short form, /a/<type>/<id>, and expand it to the canonical URL for you:

teaspill send /a/researcher/01j9z8k3q7v2m8f4t6d1c5b0aa '{"note":"also check oolong"}'

Canonical URLs are accepted everywhere the short form is; the short form is purely ergonomic. What gets stored is always the canonical form.

Instance ids

By default an id is a generated lowercase ULID — 26 characters, sortable by creation time, so sorting by id approximates sorting by age.

You can also supply your own id at spawn. That makes the spawn deterministic: spawning the same (type, id) twice reaches the same entity instead of creating a duplicate. A parent that keys each child's id off the subtask it handles can retry a spawn safely — the retry reattaches. Multi-agent patterns shows where this shines.

One id, everywhere

The same string follows the entity through the whole system:

WhereWhat you see
The catalogThe row's primary key is the entity URL
Every timeline eventThe entityId field is the entity URL
Stream URLs/streams/t/default/agents/researcher/<id>/timeline derives from it
CLI & API/a/researcher/<id> short form, expanded on arrival

There is no separate internal id to map back and forth — if you hold the URL, you can find everything the entity has ever done.

The full grammar — length limits, stream-path derivation, workspace keys, and the helper functions in @teaspill/schema — lives in the Addressing reference.