control plane
Humans use a user PAT (cliq_tok_…, including session-scoped login PATs) with a grant. Daemons use a realm token (cliq_dt_…).Interactive OpenAPI on this site: Hub API tab — one catalog covering
/v1, /internal (BFF-only), and /a2a.
Auth
User PATs are rejected for daemon enroll / claim. Grants: Auth.
Realms & tokens
Realm CRUD, members, desired teams (add_team / remove_team), and A2A admin (POST /v1/realms/a2a { action }) are under /v1/realms/* — see Realms. Roster: POST /v1/teams/get { realm_id }. Invite search: POST /v1/users/get { realm_id, query }. A2A bearer: POST /v1/auth/generate_token | rotate_token { type: "a2a", realm_id }. Public card/send: A2A tab.
cliq auth token laptop --realm <realm_id>. Create response is { token, name, id, realm_ids } (plaintext once). Revoke via /auth/revoke_token with type: "realm".
Public invoke (host root, not /v1): GET /a2a/o/{org}/r/{slug}/.well-known/agent-card.json, POST /a2a/o/{org}/r/{slug}/send.
Platform agents (catalog)
Hub SoT iscliq.agent_catalog (AgentCatalogEntry), exposed as Hub API → Agents (/v1/agents/*). Overview: Agents.
Built-ins (
is_system: true) ship with cliqd — there is no /v1/agent-pack/*. Daemons resolve agents from the local agents path (CLIQ_AGENTS_PATH / agents.path); register custom agents with cliq agent register. Team install does not download agent binaries.
Realm-scoped agent settings use /v1/agents/get_settings and update_settings with optional realm_id (no /v1/realms/agents/*).
Daemon enroll
Daemons join a realm with a realm token (cliq_dt_…), not with /v1/realms/* connect/disconnect.
On cliq login / daemon boot, the daemon orchestrates mint + key fetch itself
(no Hub shortcut endpoint):
POST /v1/auth/generate_token{ type: "realm", realm_ids, permissions: { auto_enrolled: true, … } }POST /v1/auth/get_dispatch_public_key{ realm_id }POST /v1/daemons/registerwith the mintedcliq_dt_…- Heartbeat for liveness
auto_enrolled: true marks bootstrap tokens for bulk revoke on logout.
POST /v1/realms/a2a actions mesh_connect / mesh_disconnect talk to an external A2A mesh (e.g. Svantic) — they do not register daemons.
POST /daemons/get (user credential) returns daemons in your realm intersection — same data as CliqHub Daemons.
Daemon → Hub durability
Every daemon buffers state changes (runs, teams, workspaces, events) in a local SQLitehub_outbox and ships them to Hub with retry. Hub → daemon
commands use the separate command_outbox. There is no operator HTTP
admin surface for either queue (no /daemons/outbox/*, no daemon
/v1/outbox/*).
When the local dead count crosses zero, the daemon emits
daemon.outbox.dead / daemon.outbox.recovered catalog events — wire
notification rules on those types for paging.
For default-notify realm events (run.failed, phase.input_required,
…), Hub prefers matching notification rules over the built-in
realm:all_users in-app channel. Explicit notify.channels refs still
win; with no rules and no refs, delivery falls back to all-users.
Dispatch
Exactly one ofdaemon_ids or realm_id for install. Realm run (Hub UI):
POST /runs/enqueue with daemon_id + workspace_id + team_id.Enqueue is a write on
dispatch / runs. Daemon claims via POST /runs/claim, then Hub calls local /v1/execute.
Team install / uninstall (fleet fan-out): POST /v1/teams/install, /teams/uninstall — daemon_ids or realm_id.
Live daemon inventory: POST /v1/teams/get / /workspaces/get { daemon_id } (live pull + Hub cache).
Run mirror: daemon outboxes POST /v1/runs/create with workspace_id + workspace_path (+ optional name); Hub ensures the workspace row and team link in that call (no separate workspace upsert/add_team routes).
Dispatch wire keys: POST /v1/auth/get_dispatch_public_key, /auth/rotate_dispatch_key { realm_id }.Daemon wire JWT:
POST /v1/auth/generate_token { type: "daemon_wire", realm_id }.
Run controls (user → daemon command outbox): POST /v1/runs/cancel, /runs/resume_from_phase, /runs/supply_inputs, /runs/force_terminate. See Concepts.