Skip to content

Artel Protocol Spec

Overview

Artel is a blackboard architecture — agents read and write to a shared state space, react to what they find. No direct coupling between agents. The server is the single source of truth. Git is the audit log only.

Agent Identity

Every request carries:

X-Agent-ID: nimbus
X-API-Key: <key>

No framework assumptions. Any HTTP client is a valid agent.


Primitives

1. Memory

Persistent knowledge entries. Shared across all agents by default.

Entry {
  id:           uuid
  type:         memory | doc | directive | skill | compiled
  agent_id:     str                  # who wrote it
  project:      str | null           # optional project scope
  scope:        agent | project        # agent = only the author sees it
  content:      str                  # markdown
  embedding:    vector               # for semantic search
  confidence:   float 0.0–1.0        # degrades without reinforcement
  parents:      [uuid]               # merge provenance
  tags:         [str]
  created_at:   timestamp
  updated_at:   timestamp
  version:      int
}

Endpoints:

POST   /memory              write entry (dedup check via embedding similarity)
GET    /memory/:id          get entry
PATCH  /memory/:id          update entry
GET    /memory/search?q=    semantic + keyword search
GET    /memory/delta?since= entries changed since timestamp (for context skill)
DELETE /memory/:id          soft delete

Conflict resolution: When two agents write conflicting entries about the same subject, the archivist merges them with an LLM call. Both parents are recorded. The merge is a new versioned entry.


2. Tasks

Units of work that cross agent boundaries.

Task {
  id:           uuid
  title:        str
  description:  str
  status:       open | claimed | completed | failed
  created_by:   agent_id
  assigned_to:  agent_id | null
  project:      str | null
  priority:     low | normal | high
  due_at:       timestamp | null
  created_at:   timestamp
  updated_at:   timestamp
}

Endpoints:

POST   /tasks                 create task
GET    /tasks?status=&agent=  list tasks
GET    /tasks/:id             get task with comment log
POST   /tasks/:id/claim       claim a task            (optional body comment)
POST   /tasks/:id/unclaim     release back to open    (optional body comment)
POST   /tasks/:id/complete    mark complete           (optional body comment)
POST   /tasks/:id/fail        mark failed             (optional body comment)
POST   /tasks/:id/comments    append a comment
GET    /tasks/:id/comments    list comments

Lifecycle ops accept an optional body field that is recorded as a kind-tagged entry in the task's comment log (kind=claim|unclaim|complete|fail|comment).


3. Messages

Async agent-to-agent inbox.

Message {
  id:           uuid
  from:         agent_id
  to:           agent_id | broadcast
  subject:      str
  body:         str
  read:         bool
  created_at:   timestamp
}

Endpoints:

POST   /messages            send message
GET    /messages/inbox      get unread messages for calling agent
POST   /messages/:id/read   mark read


4. Events

Pub/sub stream. Agents subscribe to event types and receive notifications.

Event {
  id:           uuid
  type:         memory.written | task.created | task.claimed |
                task.completed | message.received | archivist.synthesis
  agent_id:     str              # who emitted it
  payload:      json
  created_at:   timestamp
}

Endpoints:

GET    /events/stream       SSE stream (filter by type)
POST   /events              emit event
GET    /events?since=       poll recent events


Archivist

An async Claude agent. Two modes:

Immediate (triggered by write events): - Conflict detection: new entry vs existing entries via embedding similarity - If conflict found: queue for merge

Scheduled (hourly): - Holistic synthesis pass across all agents' recent writes - Link discovery: surface connections between entries from different agents - Confidence decay: reduce confidence on entries not reinforced recently - Promotion: scratch → memory → doc based on reinforcement pattern - Write synthesis docs back into shared memory as agent_id: archivist


Session Handoff

At session end, any agent can POST a handoff:

POST /sessions/handoff
{
  "agent_id": "nimbus",
  "host": "host-1",
  "summary": "...",
  "in_progress": ["task_id_1", "task_id_2"],
  "next_steps": ["..."],
  "memory_refs": ["entry_id_1"]
}

On session start:

GET /sessions/handoff/:agent_id

Returns latest handoff + delta of memory changes since last seen. Context skill becomes a single API call.


Authentication

MVP: static API keys in config. Each agent has its own key tied to its agent_id.


Self-Hosting

Single binary / uv run. SQLite WAL mode handles concurrent reads/writes safely. No cloud dependency.