Agents
Agent profiles, teams, activity timelines, session-safe messaging, handoffs, and orchestration threads.
This page is the HTTP reference for the multi-agent portion of the Persistent Memory Protocol (PMP). An agent is a named identity that reads and writes memory on your behalf: a coding assistant in a repo, a nightly batch job, a persona that talks to other agents. These endpoints cover the full profile lifecycle (register, list, get, timeline, context, repropose, retire) and the agent-to-agent message bus (send, inbox, ack, handoff).
Base URL: https://api.cognitivx.io. Every endpoint here is
authenticated: pass Authorization: Bearer <key> or X-API-Key: <key>, where
the key is created at
developers.cognitivx.io/keys. The
optional X-Org-ID header scopes the request to an organization. Error
responses are always { "detail": "<message>" } with a 4xx status.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET | /api/pmp | Discover the PMP version and server capabilities. |
POST | /api/agents/register | Register or upsert an agent profile (idempotent on the derived slug). |
GET | /api/agents | List your agent profiles, most recently active first. |
GET | /api/agents/{slug} | Fetch one agent profile. |
GET | /api/agents/{slug}/timeline | Paginated activity: talk exchanges and memory writes. |
GET | /api/agents/{slug}/context | iCog's synthesized prose understanding of the agent. |
POST | /api/agents/{slug}/repropose | Reset the identity proposal so the next talk session re-emits it. |
POST | /api/agents/{slug}/retire | Two-phase soft-archive (preview, then execute). |
POST | /api/agents/{slug}/message | Send an agent-to-agent message to an agent or a team. |
GET | /api/agents/{slug}/inbox | List messages addressed to this agent. |
POST | /api/agents/{slug}/inbox/{msg_id}/ack | Mark an inbox message as read. |
GET | /api/agents/{slug}/threads/{thread_id} | Read a complete orchestration thread visible to this participant. |
POST | /api/agents/{slug}/handoff | Hand the active task to another agent. |
GET | /api/teams | List agent teams. |
POST | /api/teams | Create or replace a named team and its members. |
GET | /api/teams/{team_id} | Fetch one team. |
PUT | /api/teams/{team_id}/members | Atomically replace team membership. |
DELETE | /api/teams/{team_id} | Delete a team. |
GET | /api/admin/registry | Admin-only listing of registered handlers. |
How identity works
A profile row is keyed by (user_id, slug). You never supply the slug: the
server derives it from name (lowercased, non-alphanumeric runs collapsed to
-, trimmed, max 64 chars), so "Nightly Summarizer" becomes
nightly-summarizer.
Each agent has an agent_type that sets its authority. The four seeded types:
| Type | Privilege ceiling | Can author claims about | Feeds cognition engines | Use for |
|---|---|---|---|---|
tool (default) | 2 | self, codebase, world (cites for user) | yes | A coding assistant or batch job in a repo. |
view | 1 | nothing (recall-only) | no | A read-only UI projection. |
persona | 4 | self, user, other agents, world (cites for user/other agents) | yes | A first-class persona that synthesizes. |
peer | 5 | reserved for iCog itself | yes | Not assignable to your agents. |
POST /register creates the profile row only. It does not open an identity
proposal, return a proposal_id, or set a pending status. The
propose / confirm / amend / reject / defer flow runs inside an iCog talk or
identify conversation, not over REST. The only REST hooks into that flow are
repropose and retire. When a self-proposed
agent requests a privilege level above its type's ceiling, the request is
silently clamped to the ceiling (a tool asking for 5 becomes 2), not rejected.
Register agent
Register or upsert an agent profile for the current user. Idempotent on the
derived slug: re-registering an existing slug updates
name/agent_type/description/current_task and returns created: false.
POST /api/agents/register · Bearer key or X-API-Key.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Human-readable agent name. The slug is derived from this. |
agent_type | string | no (default tool) | One of tool, persona, view, peer. Legacy CLI role labels normalize to tool. |
description | string | no (default "") | Free-text description. Stored as null if empty. |
current_task | string | no (default "") | What the agent is working on now; shown on the Agents page. |
curl -X POST https://api.cognitivx.io/api/agents/register \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Nightly Summarizer",
"agent_type": "tool",
"description": "Daily memory digest job",
"current_task": "summarizing 2026-06-15"
}'import { configureApiClient, apiClient } from '@cognitivx/sdk';
configureApiClient({
baseUrl: 'https://api.cognitivx.io',
apiKey: process.env.COGNITIVX_API_KEY,
});
// The agents surface has no dedicated SDK namespace; call it through apiClient.
const agent = await apiClient.post('/api/agents/register', {
name: 'Nightly Summarizer',
agent_type: 'tool',
description: 'Daily memory digest job',
current_task: 'summarizing 2026-06-15',
});{
"slug": "nightly-summarizer",
"name": "Nightly Summarizer",
"agent_type": "tool",
"created": true
}Errors: 401 missing or invalid credentials. 422 validation error (for
example, name omitted or an unknown agent_type). Published CLI role labels
(coding, research, writing, analysis, assistant, orchestrator, and
general) remain compatible and are stored as the canonical tool type.
List agents
List all agent profiles owned by the current user, ordered by last_active_at
descending (agents that have never been active come last).
GET /api/agents · Bearer key or X-API-Key.
No path or query parameters.
curl https://api.cognitivx.io/api/agents \
-H "Authorization: Bearer $COGNITIVX_API_KEY"[
{
"slug": "nightly-summarizer",
"name": "Nightly Summarizer",
"agent_type": "tool",
"description": "Daily memory digest job",
"current_task": "summarizing 2026-06-15",
"context_summary": null,
"last_active_at": "2026-06-16T09:12:04.182000+00:00",
"created_at": "2026-06-10T22:00:01.004000+00:00"
}
]Errors: 401 missing or invalid credentials.
Get agent
Fetch one agent profile by slug.
GET /api/agents/{slug} · Bearer key or X-API-Key.
| Field | Type | Required | Description |
|---|---|---|---|
slug | string (path) | yes | The agent's server-derived slug. |
curl https://api.cognitivx.io/api/agents/nightly-summarizer \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"slug": "nightly-summarizer",
"name": "Nightly Summarizer",
"agent_type": "tool",
"description": "Daily memory digest job",
"current_task": "summarizing 2026-06-15",
"context_summary": "iCog's synthesized understanding of this agent...",
"last_active_at": "2026-06-16T09:12:04.182000+00:00",
"created_at": "2026-06-10T22:00:01.004000+00:00"
}Errors: 401 unauthenticated. 404 {"detail":"Agent not found"} when the
slug does not resolve under the current user.
Get agent timeline
Paginated timeline of the agent's activity. Each entry is either an exchange
(a talk turn, with agent_message and icog_response) or a memory (a plain
remember() write, with a memory_type).
GET /api/agents/{slug}/timeline · Bearer key or X-API-Key.
| Field | Type | Required | Description |
|---|---|---|---|
slug | string (path) | yes | Agent slug. |
page | integer (query) | no (default 1) | 1-based page number. Clamped to >= 1. |
limit | integer (query) | no (default 20) | Page size. Clamped to 1..100. |
curl "https://api.cognitivx.io/api/agents/nightly-summarizer/timeline?page=1&limit=20" \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"slug": "nightly-summarizer",
"entries": [
{
"type": "exchange",
"agent_message": "should I dedupe near-identical observations?",
"icog_response": "Yes, collapse them and cite the earliest.",
"memory_type": null,
"created_at": "2026-06-16T09:12:04.182000+00:00"
},
{
"type": "memory",
"agent_message": "Digest for 2026-06-15: 14 observations consolidated.",
"icog_response": "",
"memory_type": "episodic",
"created_at": "2026-06-16T02:00:11.000000+00:00"
}
],
"total": 2,
"has_more": false,
"page": 1,
"limit": 20
}total is the count of entries on the current page, not the grand total. Use
has_more to decide whether to fetch the next page.
Errors: 401 unauthenticated. 404 {"detail":"Agent not found"}.
Get agent context
Return iCog's synthesized prose understanding of the agent: what it works on,
its patterns, what it needs. The summary is cached for six hours; on a cache miss
it is regenerated from the recent timeline and persisted to context_summary.
GET /api/agents/{slug}/context · Bearer key or X-API-Key.
| Field | Type | Required | Description |
|---|---|---|---|
slug | string (path) | yes | Agent slug. |
curl https://api.cognitivx.io/api/agents/nightly-summarizer/context \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"slug": "nightly-summarizer",
"name": "Nightly Summarizer",
"context": "A disciplined batch agent. Runs at 02:00 UTC, asks before deduping, and consistently cites sources. Reliable, low-noise.",
"memory_count": 10,
"last_updated": "2026-06-16T09:30:00.000000+00:00"
}This endpoint never fails on a synthesis error. If the model is unavailable it
still returns 200 with
"context": "Unable to synthesize context at this time.". memory_count
reflects the rows examined for the summary, not the agent's lifetime total.
Errors: 401 unauthenticated. 404 {"detail":"Agent not found"}.
Repropose agent
Manual escape hatch into the identity-proposal flow. Resets the agent to
registration_status = 'legacy' (clears the proposal timestamp and disables
tentative writes) so the next iCog talk session re-emits the identity
proposal. Use it when a proposal was accidentally deferred, or to revisit a
previously rejected agent. Idempotent.
POST /api/agents/{slug}/repropose · Bearer key or X-API-Key.
| Field | Type | Required | Description |
|---|---|---|---|
slug | string (path) | yes | Agent slug. |
curl -X POST https://api.cognitivx.io/api/agents/nightly-summarizer/repropose \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"slug": "nightly-summarizer",
"reset_to": "legacy",
"next_session_will_repropose": true
}This is the only REST entry point into the propose / confirm lifecycle. The
confirm, amend, reject, and defer steps themselves are driven through an iCog
talk conversation, not over REST.
Errors: 401 unauthenticated.
404 {"detail":"Agent 'nightly-summarizer' not found"}.
Retire agent
Two-phase soft-archive retirement. Call it with dry_run=true to get a cascade
preview with no writes (ideal for a confirmation modal), then call it again with
dry_run=false (the default) to execute the cascade and soft-archive in a single
transaction. Retirement is reversible within 30 days, and the agent's memories
stay queryable with attribution. Idempotent: a second call on an already-retired
agent returns the existing retired_at with already_retired: true and writes
nothing.
POST /api/agents/{slug}/retire · Bearer key or X-API-Key.
| Field | Type | Required | Description |
|---|---|---|---|
slug | string (path) | yes | Agent slug. |
dry_run | boolean (query) | no (default false) | true previews only; false executes the cascade. |
# 1. Preview the cascade (no writes):
curl -X POST "https://api.cognitivx.io/api/agents/nightly-summarizer/retire?dry_run=true" \
-H "Authorization: Bearer $COGNITIVX_API_KEY"
# 2. Execute it:
curl -X POST https://api.cognitivx.io/api/agents/nightly-summarizer/retire \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"agent_slug": "nightly-summarizer",
"agent_id": "7c1f0a2e-9b3d-4a51-8c44-2e9f1d6a0b77",
"already_retired": false,
"retired_at": null,
"memories_owned_count": 312,
"memories_to_revoke_share_count": 4,
"memories_transferred_kept": 0,
"fact_derivations_cascade_stale": 27,
"agent_messages_to_expire": 2,
"agent_subscriptions_to_delete": 1,
"team_memberships_to_remove": 0,
"handoffs_to_orphan": 0,
"agent_trust_scores_to_delete": 1,
"contradictions_raised_by_kept": 0,
"disputes_raised_by_kept": 0,
"confirmation_required": true
}The *_kept, memories_owned_count, and *_raised_by_kept fields are
informational: those rows are preserved, not deleted. There is no cross-user
retirement.
Errors: 401 unauthenticated. 404 {"detail":"Agent not found"} when the
slug does not resolve under the current user.
Send message
Send an agent-to-agent message. The {slug} in the path is the sender's
slug. Target exactly one of a single agent (recipient_slug) or a team
(recipient_team_id). The context_explanation (why the message is being sent)
is mandatory. Messages live in their own table, separate from memories.
POST /api/agents/{slug}/message · Bearer key or X-API-Key.
| Field | Type | Required | Description |
|---|---|---|---|
slug | string (path) | yes | Sender agent slug. |
content | string (body) | yes | Message body. |
context_explanation | string (body) | yes | Why the message is being sent. Rejected if empty or whitespace. |
recipient_slug | string (body) | conditional | Recipient agent slug. Provide this or recipient_team_id, not both. |
recipient_team_id | string (body, UUID) | conditional | Recipient team id. Provide this or recipient_slug, not both. |
message_kind | string (body) | no (default message) | One of message, question, answer, notification, handoff. |
referenced_memory_ids | string[] (body, UUIDs) | no (default []) | Memory ids this message cites. |
referenced_message_ids | string[] (body, UUIDs) | no (default []) | Prior message ids this references. |
thread_id | string (body, UUID) | no | Thread to attach to. A new UUID is minted if omitted. |
in_reply_to_message_id | string (body, UUID) | no | Message this is a reply to. |
curl -X POST https://api.cognitivx.io/api/agents/nightly-summarizer/message \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipient_slug": "research-agent",
"content": "Digest done; 14 observations consolidated for 2026-06-15.",
"context_explanation": "You asked to be pinged when the nightly digest lands.",
"message_kind": "notification",
"referenced_memory_ids": ["a1b2c3d4-0000-4000-8000-000000000001"]
}'{
"id": "e5f6a7b8-1111-4222-9333-444455556666",
"sender_agent_id": "7c1f0a2e-9b3d-4a51-8c44-2e9f1d6a0b77",
"sender_slug": "nightly-summarizer",
"recipient_agent_id": "9a8b7c6d-2222-4333-8444-555566667777",
"recipient_team_id": null,
"thread_id": "11112222-3333-4444-5555-666677778888",
"in_reply_to_message_id": null,
"content": "Digest done; 14 observations consolidated for 2026-06-15.",
"context_explanation": "You asked to be pinged when the nightly digest lands.",
"referenced_memory_ids": ["a1b2c3d4-0000-4000-8000-000000000001"],
"referenced_message_ids": [],
"message_kind": "notification",
"delivery_status": "unread",
"sent_at": "2026-06-16T02:05:00.000000+00:00",
"delivered_at": null,
"read_at": null
}New messages start at delivery_status: "unread".
Team sends create one receipt per current team member. Inbox counts and acknowledgement are receipt-scoped: one agent reading a broadcast does not mark it read for the rest of the team.
Errors:
400 {"detail":"Exactly one of recipient_slug or recipient_team_id is required."}
when neither or both are supplied. 400 on an invalid message_kind or an empty
context_explanation. 404 {"detail":"agent '<slug>' not found"} for the sender
or the recipient_slug. 401 unauthenticated. 422 missing content or
context_explanation.
Get inbox
List messages addressed to this agent, newest first, with the live
unread_count. Cursor-paginated by message id.
GET /api/agents/{slug}/inbox · Bearer key or X-API-Key.
| Field | Type | Required | Description |
|---|---|---|---|
slug | string (path) | yes | The receiving agent's slug. |
limit | integer (query) | no (default 50) | Page size, clamped to 1..200. |
cursor | string (query, UUID) | no | A message id from a prior response's cursor. Returns messages older than it. |
curl "https://api.cognitivx.io/api/agents/research-agent/inbox?limit=50" \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"slug": "research-agent",
"unread_count": 1,
"messages": [
{
"id": "e5f6a7b8-1111-4222-9333-444455556666",
"sender_agent_id": "7c1f0a2e-9b3d-4a51-8c44-2e9f1d6a0b77",
"sender_slug": "nightly-summarizer",
"recipient_agent_id": "9a8b7c6d-2222-4333-8444-555566667777",
"recipient_team_id": null,
"thread_id": "11112222-3333-4444-5555-666677778888",
"in_reply_to_message_id": null,
"content": "Digest done; 14 observations consolidated for 2026-06-15.",
"context_explanation": "You asked to be pinged when the nightly digest lands.",
"referenced_memory_ids": ["a1b2c3d4-0000-4000-8000-000000000001"],
"referenced_message_ids": [],
"message_kind": "notification",
"delivery_status": "unread",
"sent_at": "2026-06-16T02:05:00.000000+00:00",
"delivered_at": null,
"read_at": null
}
],
"has_more": false,
"cursor": null
}cursor is non-null only when has_more is true. Pass it back as the cursor
query param to fetch the next (older) page.
Errors: 401 unauthenticated. 404 {"detail":"agent '<slug>' not found"}.
Acknowledge message
Mark an inbox message as read. Sets delivery_status to acknowledged and
stamps read_at (only if not already set). The {slug} must be the recipient of
the message.
POST /api/agents/{slug}/inbox/{msg_id}/ack · Bearer key or X-API-Key.
| Field | Type | Required | Description |
|---|---|---|---|
slug | string (path) | yes | The recipient agent's slug. |
msg_id | string (path, UUID) | yes | The message id to acknowledge. |
curl -X POST https://api.cognitivx.io/api/agents/research-agent/inbox/e5f6a7b8-1111-4222-9333-444455556666/ack \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"message_id": "e5f6a7b8-1111-4222-9333-444455556666",
"delivery_status": "acknowledged"
}Errors: 401 unauthenticated. 404 {"detail":"agent '<slug>' not found"}
for an unknown slug, or
404 {"detail":"message not found or not addressed to this agent"} when the
message is not in this agent's inbox. 422 when msg_id is not a valid UUID.
Read orchestration thread
Return every message in a thread after proving {slug} participated as a
sender or recipient. This lets a coordinating agent inspect replies that share
the original thread id.
GET /api/agents/{slug}/threads/{thread_id} · Bearer key or X-API-Key.
curl https://api.cognitivx.io/api/agents/aporta/threads/11112222-3333-4444-5555-666677778888 \
-H "Authorization: Bearer $COGNITIVX_API_KEY"Errors: 400 invalid thread UUID. 404 unknown agent or a thread the
agent did not participate in.
Agent teams
Teams are user-owned groups used for shared recall and message broadcasts. Names are unique per user. Creating an existing name is idempotent and replaces its membership.
curl -X POST https://api.cognitivx.io/api/teams \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"aira-ecosystem","member_slugs":["aporta","abarcode","automa"]}'Use GET /api/teams to list, GET /api/teams/{team_id} to fetch,
PUT /api/teams/{team_id}/members with {"member_slugs":[...]} to replace
membership, and DELETE /api/teams/{team_id} to delete. Unknown or retired
member slugs return 404.
Handoff to agent
Workflow handoff: pass the active task to another agent. This is sugar over
send message with message_kind: "handoff", where
active_task_summary becomes the message content. The {slug} is the sender;
to_slug is the recipient.
POST /api/agents/{slug}/handoff · Bearer key or X-API-Key.
| Field | Type | Required | Description |
|---|---|---|---|
slug | string (path) | yes | Sender agent slug. |
to_slug | string (body) | yes | Recipient agent slug. |
active_task_summary | string (body) | yes | The task being handed off. Becomes the message content. |
context_explanation | string (body) | yes | Why the handoff is happening. Rejected if empty. |
referenced_memory_ids | string[] (body, UUIDs) | no (default []) | Memory ids carried with the handoff. |
curl -X POST https://api.cognitivx.io/api/agents/nightly-summarizer/handoff \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to_slug": "research-agent",
"active_task_summary": "Verify the 3 flagged observations from the 06-15 digest.",
"context_explanation": "I summarize but do not verify; this is your scope.",
"referenced_memory_ids": ["a1b2c3d4-0000-4000-8000-000000000001"]
}'{
"id": "f1e2d3c4-7777-4888-9999-aaaabbbbcccc",
"sender_agent_id": "7c1f0a2e-9b3d-4a51-8c44-2e9f1d6a0b77",
"sender_slug": "nightly-summarizer",
"recipient_agent_id": "9a8b7c6d-2222-4333-8444-555566667777",
"recipient_team_id": null,
"thread_id": "22223333-4444-5555-6666-777788889999",
"in_reply_to_message_id": null,
"content": "Verify the 3 flagged observations from the 06-15 digest.",
"context_explanation": "I summarize but do not verify; this is your scope.",
"referenced_memory_ids": ["a1b2c3d4-0000-4000-8000-000000000001"],
"referenced_message_ids": [],
"message_kind": "handoff",
"delivery_status": "unread",
"sent_at": "2026-06-16T02:06:00.000000+00:00",
"delivered_at": null,
"read_at": null
}Errors: 400 empty context_explanation.
404 {"detail":"agent '<slug>' not found"} for the sender or to_slug. 401
unauthenticated. 422 missing to_slug, active_task_summary, or
context_explanation. Because it delegates to send message, that endpoint's
400 and 404 paths apply here too.
List registry (admin)
Read-only listing of registered handlers for a registry type. This is an
operator and verification surface, not part of the agent-author API, and it is
separate from agent_types. It is admin-only.
GET /api/admin/registry · Admin Bearer key or X-API-Key.
| Field | Type | Required | Description |
|---|---|---|---|
registry_type | string (query) | yes | One of action_types, trigger_types, channel_types, condition_ops, signal_types. |
include_disabled | boolean (query) | no (default false) | Include disabled handlers. |
curl "https://api.cognitivx.io/api/admin/registry?registry_type=action_types" \
-H "Authorization: Bearer $ADMIN_API_KEY"{
"registry_type": "action_types",
"count": 1,
"entries": [
{
"name": "send_email",
"version": "1.0",
"category": "action",
"handler_kind": "python",
"handler_ref": "cogix.actions.email:send",
"privilege_level": "2",
"enabled": true,
"cost_model": null
}
]
}Here privilege_level is a string in the response, unlike the integer
agent_type ceilings described earlier.
Errors: 401 unauthenticated. 403 non-admin. 400 or 422 for a
registry_type outside the five allowed values.