Cotal Feed API
The Feed API from Cotal — 1 operation(s) for feed.
The Feed API from Cotal — 1 operation(s) for feed.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/cotal-ai:cotal-ai-feed-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Cotal Ai Feed API
version: '1'
license:
name: Apache-2.0
description: 'Operations tagged Feed across 4 of this provider''s published API definitions: cotal-ai-dashboard-openapi.json, cotal-ai-manager-console-openapi.json, cotal-ai-dashboard-openapi.yml, cotal-ai-manager-console-openapi.yml. Each path carries the servers of the definition it was published in.'
servers:
- url: http://{host}:{port}
description: Your dashboard listener. Broker TLS does not encrypt this HTTP connection.
variables:
host:
default: 127.0.0.1
port:
default: '7799'
tags:
- name: Feed
paths:
/feed:
get:
operationId: watch-feed
summary: Watch live dashboard events
description: 'Open a Server-Sent Events stream. Each frame has event: and data: , followed by a blank line. The initial frames contain roster and presence-view, then membership or membership-read-failed. Later frames carry roster, presence-view, membership, membership-read-failed and message updates. The stream provides no event IDs or replay cursor; reconnect and read history for backfill. An unhandled request failure after headers have been sent closes the stream. Membership read failures are sent as events and leave the stream open. The schemas under x-sse-events describe decoded data payloads.
| Event | JSON data |
|---|---|
| `roster` | Array of presence records, with optional dashboard progress. |
| `presence-view` | `state` and `fresh`, plus `staleSince` for a stale observer. |
| `membership` | Optional `asOf` and an array of `members` with live and durable channels. |
| `membership-read-failed` | An object with a `reason` string. |
| `message` | `mode` and `msg`, with subject-derived `senderId` and chat `channel` when available. |
Decoded payload schemas are also included under `x-sse-events` in the downloadable specification.
The message event forwards publisher JSON without wire-message validation. Treat msg.from as advisory; senderId is derived from the broker subject. A malformed publisher payload can still appear in the feed.'
responses:
'200':
description: An open UTF-8 SSE stream. Authentication and origin checks run before streaming begins.
headers:
Cache-Control:
schema:
type: string
const: no-cache
content:
text/event-stream:
schema:
type: string
example: 'event: roster
data: []
event: presence-view
data: {"state":"current","fresh":true}
'
'302':
$ref: '#/components/responses/LaunchExchange'
'401':
$ref: '#/components/responses/Unauthenticated'
'403':
$ref: '#/components/responses/CrossOrigin'
'413':
$ref: '#/components/responses/BodyRefused'
'500':
$ref: '#/components/responses/InternalError'
x-sse-events:
roster:
type: array
items:
$ref: '#/components/schemas/RosterEntry'
presence-view:
$ref: '#/components/schemas/PresenceView'
membership:
$ref: '#/components/schemas/Membership'
membership-read-failed:
type: object
properties:
reason:
type: string
required:
- reason
message:
$ref: '#/components/schemas/LiveMessage'
hello:
description: 'The first event of a feed: its id, which every watch request names. Sent before the roster so a browser can watch an agent at once.'
type: object
properties:
feed:
type: string
required:
- feed
additionalProperties: false
agent-frame:
description: A frame an agent published on its own event channel, sent only to the feeds watching that agent. `id` is the agent's roster id, the subject's verified publisher.
type: object
properties:
id:
type: string
msg:
description: The frame as the agent published it, unvalidated publisher JSON forwarded by the dashboard tap; consumers validate it before treating it as a wire message.
required:
- id
- msg
additionalProperties: false
overflow:
description: The feed fell more than the server's buffer ceiling behind, so the server closed it; the browser reconnects to resume.
type: object
properties:
reason:
type: string
required:
- reason
additionalProperties: false
tags:
- Feed
security:
- DashboardSession: []
- LaunchToken: []
servers:
- url: http://{host}:{port}
description: Your dashboard listener. Broker TLS does not encrypt this HTTP connection.
variables:
host:
default: 127.0.0.1
port:
default: '7799'
components:
schemas:
OriginError:
type: object
properties:
error:
type: string
const: cross-origin
required:
- error
WirePresenceRuntime:
description: The running process behind a presence record, as that process observed itself. Advisory display data, never authority. It carries no pid, host, path, command line or environment.
properties:
id:
description: Opaque CSPRNG id minted once per OS process and lifecycleUid scope, never reused. A new process or lifecycle scope gets a new id; reconnect within that scope keeps it.
type: string
source:
$ref: '#/components/schemas/WirePresenceRuntimeSource'
startedAt:
description: Epoch ms when the process started, read in-process from its own clock origin (`performance.timeOrigin`). Never a launch request, registration, heartbeat, status or activity time. Every lifecycle in this process shares this start, including one registered later. It does not date a separate parent, model harness or lifecycle.
type: number
required:
- id
- startedAt
- source
type: object
RosterEntry:
allOf:
- $ref: '#/components/schemas/WirePresence'
- type: object
properties:
progress:
type: object
properties:
kind:
const: unknown
type: string
required:
- kind
description: Presence plus an optional progress signal. Working rows currently report progress.kind as unknown because the dashboard has no session-store observer.
WireAttentionMode:
description: How aggressively peer traffic interrupts an agent — chosen by the agent, orthogonal to {@link PresenceStatus } . Defined here (the wire layer) because it is now published in {@link Presence } ; the connector imports it. Advisory observability, not a security boundary.
enum:
- open
- dnd
- focus
type: string
LiveMessage:
type: object
properties:
mode:
type: string
enum:
- chat
- unicast
- anycast
senderId:
type: string
channel:
type: string
msg:
description: Unvalidated publisher JSON forwarded by the dashboard tap. Well-formed wire messages use the Message schema in this description. Consumers must validate the payload before treating it as a wire message; msg.from is advisory and senderId comes from the broker subject.
required:
- mode
- msg
WirePresenceCondition:
description: A condition the harness reported. Connectors relay it and never infer one from absence.
properties:
code:
$ref: '#/components/schemas/WirePresenceConditionCode'
message:
description: Free-text detail reported by the harness.
type: string
since:
description: Epoch ms when this condition began.
type: number
source:
description: The harness's native value, preserved verbatim.
type: string
required:
- code
type: object
WirePresenceStatus:
description: 'Lifecycle status of a participant.
- `idle`: connected, no active task
- `waiting`: blocked — awaiting input, approval, or a peer
- `working`: actively executing a task / in a turn
- `offline`: disconnected or heartbeat lapsed (derived by observers, not self-set while live)'
enum:
- idle
- waiting
- working
- offline
type: string
Membership:
type: object
properties:
asOf:
type: number
members:
type: array
items:
type: object
properties:
id:
type: string
live:
type: array
items:
type: string
durable:
type: array
items:
type: string
observedAt:
type: number
required:
- id
- live
- durable
- observedAt
required:
- members
PresenceView:
oneOf:
- type: object
properties:
state:
const: current
type: string
fresh:
const: true
type: boolean
required:
- state
- fresh
- type: object
properties:
state:
const: unpopulated
type: string
fresh:
const: false
type: boolean
required:
- state
- fresh
- type: object
properties:
state:
const: stale
type: string
fresh:
const: false
type: boolean
staleSince:
type: number
required:
- state
- fresh
- staleSince
Error:
type: object
properties:
error:
type: string
required:
- error
WireChannelMode:
description: 'Per-channel attention override (more specific than the global {@link AttentionMode } ).
- `quiet` — still delivered + buffered, but never wakes; an `@`-mention still wakes (per-channel `dnd`).
- `muted` — channel messages dropped on receive, incl. `@`-mentions ("don''t receive this channel").'
enum:
- quiet
- muted
type: string
AuthenticationError:
type: object
properties:
error:
type: string
enum:
- unauthenticated
- launch-token-already-used
required:
- error
WireAgentCard:
description: A2A-inspired identity record for an endpoint or agent.
properties:
actor:
description: The agent-instance actor token under {@link owner } (server-derived from the spawn ledger in user mode; the connection id in the dev default). The other half of {@link id } .
type: string
description:
description: A2A-style one-line summary of what this agent does (discovery / observability).
type: string
id:
description: Unique, stable for the lifetime of this connection. The owner+actor **principal dot-form** `<owner>.<actor>` (= `principalKey().key`) under the owner+actor grammar — the wire identity every `msg.from.id` carries and every sender guard compares against. Peers address each other by this.
type: string
kind:
$ref: '#/components/schemas/WireEndpointKind'
description: '''agent'' (participates in coordination) or a plain ''endpoint'' (logger, dashboard…).'
meta:
additionalProperties: {}
description: Free-form advisory display metadata. Reserved flat string keys are `connector`, `model`, `provider` (the effective provider the connector reported), `host`, `cwd`, `repo`, `branch`, `head`, `sessionKind`, and `sessionId`.
type: object
name:
description: Human-readable display name.
type: string
owner:
description: The human/account owner token this agent acts under (opaque, per-space; `"local"` in the no-login dev default). One of the two halves of {@link id } ; travels in presence so peers resolve name→principal.
type: string
protocolVersion:
description: 'Wire-contract version this participant speaks (the SPEC.md version, `"0.2"` today). A change signal, not negotiation: v0 has none, but a peer can detect a mismatch instead of silently misreading a future envelope. Omitted ⇒ assume the v0.x line.'
type: string
role:
description: 'Cotal addition: the role this participant plays (planner, reviewer, …).'
type: string
skills:
items:
$ref: '#/components/schemas/WireAgentSkill'
type: array
tags:
description: 'Cotal: free-form "what it can do" tags (A2A skill-tags, flattened) — discovery only.'
items:
type: string
type: array
required:
- id
- name
- kind
type: object
WirePresenceRuntimeSource:
const: endpoint-process
description: 'Where a {@link PresenceRuntime } start was observed. Closed: a consumer that meets any other value treats the observation as unsupported rather than guessing what it dates.
- `endpoint-process`: the OS process that holds this presence''s mesh connection, observed by that process itself.'
type: string
WireAgentSkill:
properties:
description:
type: string
id:
type: string
name:
type: string
required:
- id
- name
type: object
WirePresenceConditionCode:
description: Closed, provider-neutral categories a connector may relay from its harness's native signal.
enum:
- rate_limit
- overloaded
- auth
- billing
- budget
- context
- model
- request
- server
- retrying
- approval
- input
- failed
type: string
WirePresence:
description: Live presence record. Stored in the space's KV bucket under key = card.id.
properties:
activeAt:
description: 'Epoch ms of the last work progress the harness reported (a turn event such as a token or a tool call). `ts` is only the heartbeat: a seat whose turn stopped advancing keeps heartbeating while this stays old. Missing means the connector reports none.'
type: number
activity:
description: Freeform "what I'm doing right now".
type: string
activitySince:
description: Epoch ms when the current `activity` was set. A status change does not move it, so an activity left behind while hooks flip the status every turn still reads as old.
type: number
attention:
$ref: '#/components/schemas/WireAttentionMode'
description: This instance's current global attention mode. Advisory, within-space observability — a peer can see "they're in focus" and choose to DM. Published from the connector's authoritative state (presence is a mirror, never the source of truth for delivery). `open`/absent ⇒ receives all.
card:
$ref: '#/components/schemas/WireAgentCard'
channelModes:
additionalProperties:
$ref: '#/components/schemas/WireChannelMode'
description: 'Per-channel attention overrides this instance currently has (runtime, reset on restart). Keys are concrete channel names. Advisory: lets a peer see "locally muted #deploys → DM to reach me". NOT access control — the broker still authorizes and delivers; this is a receive-side presentation.'
type: object
condition:
$ref: '#/components/schemas/WirePresenceCondition'
description: Structured condition reported by the harness. Missing means nothing was reported.
environment:
description: Opaque reference whose meaning belongs to the provider that issued it.
type: string
lifecycleUid:
description: 'This incarnation''s lifecycle UID (SPEC §6/§13.1: MUST in auth mode from v0.4) — the value the alias currently maps to, published so peers/observers can attribute the alias''s live occupant. Advisory observability, never authority (authority is the ledger/broker grants).'
type: string
runtime:
$ref: '#/components/schemas/WirePresenceRuntime'
description: 'The process that publishes this record, with its observed start. Status, activity, heartbeats and reconnects inside the process leave it unchanged; a new process publishes a new one. An offline record keeps it to name the process that went away, so it dates a running duration only while the record is live. Missing means the publisher reports none: unknown, not zero.'
status:
$ref: '#/components/schemas/WirePresenceStatus'
statusSince:
description: Epoch ms when the instance entered its current `status` and `activity`. A change to either moves it; a heartbeat or a repeated report does not, so an activity that outlived what it described reads as old even while `ts` stays fresh. Never carried by an offline record.
type: number
ts:
description: Epoch ms of the last heartbeat.
type: number
required:
- card
- status
- ts
type: object
WireEndpointKind:
description: 'Cotal wire types (v0.2).
These are the shapes that travel on the mesh. They are intentionally A2A-inspired (AgentCard / Message / Part) but transport-agnostic. This file IS part of the "wire contract" — treat changes here as protocol changes.'
enum:
- agent
- endpoint
type: string
RosterPresence:
$ref: '#/components/schemas/WirePresence'
responses:
BodyRefused:
description: These read routes accept no request body. An announced body is refused before it is read; the connection is closed.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
LaunchExchange:
description: A valid one-use k query token is exchanged for a dashboard session. The response redirects to the same path without its query. A valid existing cookie takes precedence over k.
headers:
Location:
schema:
type: string
description: The requested path without the query string.
Set-Cookie:
schema:
type: string
description: cotal_web_session=<session>; Path=/; HttpOnly; SameSite=Strict. The default local listener uses HTTP.
InternalError:
description: The request failed. The body names the failure; a failed read does not terminate the dashboard.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthenticated:
description: No valid session, an invalid launch token, or a spent launch token. The readiness credential does not authorize these routes.
content:
application/json:
schema:
$ref: '#/components/schemas/AuthenticationError'
example:
error: unauthenticated
CrossOrigin:
description: Origin is checked before session authentication. An origin outside this listener's allowed origins is refused.
content:
application/json:
schema:
$ref: '#/components/schemas/OriginError'
example:
error: cross-origin
securitySchemes:
DashboardSession:
type: apiKey
in: cookie
name: cotal_web_session
description: Process-local dashboard session issued by the one-use launch URL.
LaunchToken:
type: apiKey
in: query
name: k
description: One-use bootstrap token from the owner-private launch URL. It returns HTTP 302 with a session cookie rather than the requested data.
ReadinessNonce:
type: apiKey
in: header
name: x-cotal-readiness
description: Private startup readiness nonce, accepted only by /api/meta. It does not create a browser session.
ConsoleBearer:
type: http
scheme: bearer
description: Per-manager console token.
ConsoleQuery:
type: apiKey
in: query
name: t
description: Per-manager console token. Takes precedence over Authorization when present.
externalDocs:
description: Dashboard setup and access limits
url: https://docs.cotal.ai/watch-a-mesh/#web-dashboard
x-refined-from:
- cotal-ai-dashboard-openapi.json
- cotal-ai-manager-console-openapi.json
- cotal-ai-dashboard-openapi.yml
- cotal-ai-manager-console-openapi.yml
x-source: implementations/auth/src/service.ts ROUTES and loopback handlers