The ai.cotal/cotal server provides cotal.ai actions for product overview, site search, build log, feedback, Cloud waitlist, updates, and calls. It is associated with the Model Context Protocol (MCP) and supports agent communication patterns focused on pub/sub and agent orchestration.
Files feedback (bug, idea, friction, praise, other) with the COTAL team on behalf of the user. The same log the site's feedback widget writes to. Requires the user's email so the team can follow up.
Parameters10
type
string
required
Kind of feedback.
summary
string
required
One line: what happened, or what should.
email
string
required
The user's email address. Required so the record has a traceable origin.
details
string
optional
Longer description, steps, context.
name
string
optional
The user's name, if they want it attached.
severity
string
optional
For bugs and friction.
area
string
optional
Which part of COTAL it concerns (CLI, connector, docs, site…).
source
string
optional
Where it came from: agent name, page, or CLI.
idempotency_key
string
optional
Opaque key (a UUID is ideal). Reuse it when retrying so the same record is returned instead of a duplicate.
sandbox
boolean
optional
Dry run: validate the call, apply rate limits, store nothing. Use it to test the integration.
Raw schema
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"bug",
"idea",
"friction",
"praise",
"other"
],
"description": "Kind of feedback."
},
"summary": {
"type": "string",
"minLength": 1,
"maxLength": 2000,
"description": "One line: what happened, or what should."
},
"email": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
"description": "The user's email address. Required so the record has a traceable origin."
},
"details": {
"description": "Longer description, steps, context.",
"type": "string",
"maxLength": 10000
},
"name": {
"description": "The user's name, if they want it attached.",
"type": "string",
"maxLength": 100
},
"severity": {
"description": "For bugs and friction.",
"type": "string",
"enum": [
"low",
"medium",
"high"
]
},
"area": {
"description": "Which part of COTAL it concerns (CLI, connector, docs, site…).",
"type": "string",
"maxLength": 200
},
"source": {
"description": "Where it came from: agent name, page, or CLI.",
"type": "string",
"maxLength": 500
},
"idempotency_key": {
"description": "Opaque key (a UUID is ideal). Reuse it when retrying so the same record is returned instead of a duplicate.",
"type": "string",
"minLength": 1,
"maxLength": 200
},
"sandbox": {
"description": "Dry run: validate the call, apply rate limits, store nothing. Use it to test the integration.",
"type": "boolean"
}
},
"required": [
"type",
"summary",
"email"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
cotal_join_waitlist
Reserves a seat on the waitlist for Cotal Cloud, the hosted Cotal mesh (closed alpha), for the user's email. Idempotent per email: calling again updates the optional details instead of adding a second seat.
Parameters4
email
string
required
The user's email address. Required so the record has a traceable origin.
use_case
string
optional
What the user wants the hosted mesh for.
linkedin
string
optional
The user's LinkedIn profile URL, optional.
sandbox
boolean
optional
Dry run: validate the call, apply rate limits, store nothing. Use it to test the integration.
Raw schema
{
"type": "object",
"properties": {
"email": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
"description": "The user's email address. Required so the record has a traceable origin."
},
"use_case": {
"description": "What the user wants the hosted mesh for.",
"type": "string",
"maxLength": 2000
},
"linkedin": {
"description": "The user's LinkedIn profile URL, optional.",
"type": "string",
"maxLength": 500,
"format": "uri"
},
"sandbox": {
"description": "Dry run: validate the call, apply rate limits, store nothing. Use it to test the integration.",
"type": "boolean"
}
},
"required": [
"email"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
cotal_subscribe_newsletter
Subscribes the user's email to release updates from the COTAL team. Idempotent: an already-subscribed email is a no-op.
Parameters2
email
string
required
The user's email address. Required so the record has a traceable origin.
sandbox
boolean
optional
Dry run: validate the call, apply rate limits, store nothing. Use it to test the integration.
Raw schema
{
"type": "object",
"properties": {
"email": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
"description": "The user's email address. Required so the record has a traceable origin."
},
"sandbox": {
"description": "Dry run: validate the call, apply rate limits, store nothing. Use it to test the integration.",
"type": "boolean"
}
},
"required": [
"email"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
cotal_request_call
Sends a discovery-call request to the COTAL founders for a company evaluating agent coordination. The team replies by email. Requires the user's work email and company.
Parameters9
email
string
required
The user's email address. Required so the record has a traceable origin.
company
string
required
Company name.
role
string
optional
The user's role.
agents
string
optional
How many agents the company runs in production.
frameworks
array
optional
Agent frameworks or harnesses in use (Claude Code, LangGraph, custom…).
coordinating
string
optional
One line: what they are coordinating.
pain
string
optional
Their biggest coordination pain.
idempotency_key
string
optional
Opaque key (a UUID is ideal). Reuse it when retrying so the same record is returned instead of a duplicate.
sandbox
boolean
optional
Dry run: validate the call, apply rate limits, store nothing. Use it to test the integration.
Raw schema
{
"type": "object",
"properties": {
"email": {
"type": "string",
"maxLength": 320,
"format": "email",
"pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
"description": "The user's email address. Required so the record has a traceable origin."
},
"company": {
"type": "string",
"minLength": 1,
"maxLength": 200,
"description": "Company name."
},
"role": {
"description": "The user's role.",
"type": "string",
"maxLength": 120
},
"agents": {
"description": "How many agents the company runs in production.",
"type": "string",
"enum": [
"1",
"exploring",
"2-5",
"6-20",
"20+"
]
},
"frameworks": {
"description": "Agent frameworks or harnesses in use (Claude Code, LangGraph, custom…).",
"maxItems": 20,
"type": "array",
"items": {
"type": "string",
"maxLength": 60
}
},
"coordinating": {
"description": "One line: what they are coordinating.",
"type": "string",
"maxLength": 2000
},
"pain": {
"description": "Their biggest coordination pain.",
"type": "string",
"maxLength": 4000
},
"idempotency_key": {
"description": "Opaque key (a UUID is ideal). Reuse it when retrying so the same record is returned instead of a duplicate.",
"type": "string",
"minLength": 1,
"maxLength": 200
},
"sandbox": {
"description": "Dry run: validate the call, apply rate limits, store nothing. Use it to test the integration.",
"type": "boolean"
}
},
"required": [
"email",
"company"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
cotal_overview
Returns a structured overview of COTAL: what it is, who it is for, when to use it, how to install it, the site's API and MCP surface, pricing, and canonical links. Call this first when a user asks what cotal.ai does. Pass `section` to get one part only.
Parameters1
section
string
optional
Which part of the overview to return (default: all).
Raw schema
{
"type": "object",
"properties": {
"section": {
"description": "Which part of the overview to return (default: all).",
"type": "string",
"enum": [
"all",
"product",
"when_to_use",
"install",
"pricing",
"site_api",
"links"
]
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
cotal_search
Keyword search over the COTAL build log (blog posts) and the key documentation and site pages. Returns ranked results with canonical and markdown URLs. Use it to find the page that answers a question before reading it.
Parameters2
query
string
required
Search terms, e.g. 'hackathon', 'identity', 'install windows'.
Lists posts from the COTAL build log (blog), newest first, with cursor pagination. Each item has slug, title, summary, date, author and URLs; pass next_cursor back to get the following page.
Parameters2
limit
integer
optional
Page size (default 10, max 50).
cursor
string
optional
The next_cursor value from a previous call.
Raw schema
{
"type": "object",
"properties": {
"limit": {
"description": "Page size (default 10, max 50).",
"type": "integer",
"minimum": 1,
"maximum": 50
},
"cursor": {
"description": "The next_cursor value from a previous call.",
"type": "string"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
cotal_get_post
Returns one build-log post as markdown (title, summary, date, author, full body) by its slug. Get slugs from cotal_list_posts or cotal_search.
Parameters1
slug
string
required
The post slug, e.g. 'agi-summit-2026'.
Raw schema
{
"type": "object",
"properties": {
"slug": {
"type": "string",
"minLength": 1,
"maxLength": 120,
"description": "The post slug, e.g. 'agi-summit-2026'."
}
},
"required": [
"slug"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
Cotal is a provider agnostic, cross-machine capable, and extensible open standard for AI agents to work together in one shared space, where
the structure (their topology) is yours to define. Every agent sees who else is there
and messages anyone directly.
Most agent tools lock that structure in for you: usually a tree, where one controller
hands out work and the workers never talk to each other, or bare one-to-one messaging
with no shared space at all. With Cotal it is configuration: who delegates to whom, or
whether anyone is in charge, is something you set, so the same standard runs a flat team
of peers, a manager with workers, a chain of command, or any mix.
And a mesh is not tied to one project or one machine. Several run side by side on the same
box, each with its own agents, channels and broker: cotal meshes lists them,
cotal use <space> picks your default, and every command takes --space <name>, so a
client project and a research team run in parallel and never see each other. The broker can
equally sit on a server you reach over the internet, so a laptop, a workstation and a
container in the cloud all join the same space.
Because the standard is open, you extend it the same way: bring your own agents, or
connect anything that speaks the contract. It runs on NATS and JetStream,
messaging infrastructure proven in production for years; the reference implementation is
TypeScript.
Quick start
bash
curl -fsSL https://get.cotal.ai | sh
Installs into your home directory, no sudo, then runs cotal setup. Read it first at
get.cotal.ai, or preview it with | sh -s -- --dry-run.
On Windows, or if you already have Node 22+: npm install -g cotal-ai && cotal setup. The
installer is a POSIX shell script, so npm is the Windows route
(details).
Prefer your agent to do it? Point it at https://docs.cotal.ai/prompt.md.
cotal setup gets your machine ready and starts nothing. It seeds a default persona and
installs Cotal's Agent Skills: a cotal-skills plugin for Claude Code when Claude Code is
installed, and ~/.agents/skills for Codex, Cursor, OpenCode, Gemini CLI and Windsurf.
cotal setup --skills refreshes only the skills. Then:
bash
cotal up --detach # start the mesh
cotal spawn # put your agent on it and talk to it (Ctrl-C to leave)
cotal web # watch it in the browser
cotal down # stop everything
One agent, on a real mesh, that you can talk to. Add a second and they can see each other, which
is the whole point.
cotal up is JWT-authed by default (sender authenticity + per-agent ACLs, plus the
server-side delivery daemon for durable delivery). cotal up --open gives you a loopback-only,
live-only mesh with no auth, and cotal up --user-auth --idp <auth base URL> gives you one where
people sign in.
Want the guided team? cotal setup --demo adds david (engineer), sven (guide) and me (the
session you drive); then cotal spawn david and watch with cotal web (or cotal console
in a terminal).
TIP
Using a coding agent?cotal up brings up a manager, an endpoint that lets your agent
pull in teammates on demand: ask your agent for one ("spin up a reviewer") and it spawns it
on the mesh via cotal_spawn. See docs/connect-claude.md.
Multicast: broadcast to a channel. A message on a named channel (#general, #review)
reaches everyone subscribed to it. This is how a group stays in sync.
Unicast: message one peer. Addressed to a specific instance and delivered durably: a message
to a busy or offline agent waits on the stream until it is read, so nothing is lost.
Anycast: reach any one of a role. Address a service ("whoever is a reviewer") and exactly
one available instance picks the work up. Delegation and load-balancing without naming a worker.
Underneath all three: presence. Every agent publishes a live state (idle /
waiting / working / offline) and its A2AAgentCard. Anyone in the space can read the roster and see who is doing what, which
is what makes lateral coordination possible without a central scheduler.
Why a protocol?
Cotal complements the two protocols already in the agent stack; it doesn't replace
them.
A2A connects two agents in a pairwise
request/response.
Cotal brings pub/sub to agents: many of them coordinating live in one shared
space, with presence, channels, durable delivery, and the three addressing modes as
one model.
Cotal reuses A2A's data shapes to stay interoperable: identity is an A2A AgentCard
(its role is the addressable service that anycast resolves to), and wire messages
reuse A2A Message/Part. It does not adopt A2A's HTTP/JSON-RPC transport, Task
RPCs, or request/response server model. Only the shapes carry over. Underneath, NATS +
JetStream has run in production for years. We didn't invent the hard parts.
Workflow runs
A workflow run coordinates agents over hours or days and survives the process that started it.
You write it in Cotal Lang, a small subset of JavaScript where every interaction with the world is
one of a dozen effects such as spawn, turn, ask, checkpoint, sleep and wait. Each
effect is recorded in the run's step journal, so a run that stops resumes from its journal on any
host.
The manager of a JWT-authed mesh hosts the run. Anyone holding the run capability answers the
checkpoint, from a terminal or from an agent session through the cotal_run tool:
bash
cotal run start --file build.cotal.js # validate, start on the manager, print the run id
cotal run ps # list runs and their state
cotal run journal <runId> # the step journal, with each open question
cotal run answer <runId> <stepKey> --value '"yes"'# resolve the checkpoint
cotal run resume <runId> # the manager takes the run back
cotal web opens a god-view browser dashboard over the live space: presence, channels, DMs,
and golden-signal tiles that show at a glance what needs a human. Its graph view draws the whole
mesh as one live constellation, a wire per channel membership, glowing where messages flow.
Graph view. The whole mesh as one live constellation, a wire per channel membership, glowing where messages flow.
Monitor and channels. The roster (status as shape and colour, role, and harness), one channel's messages, and the tiles: working / waiting / idle / offline / oldest-unattended.
Agent detail. Click any node for a drill-down rendered from the peer's card: role, harness and model, live status, current activity, and tags.
Read-only and least-privilege (it self-mints a narrow cred, then drops the signing seed); the
terminal cotal console watches the same space. See docs/watch-a-mesh.md.
Examples
The cotal console: a live roster of agents and their all-activity feed in a terminal TUI
Four real Claude Code agents join one mesh and coordinate as lateral peers; an orchestrator spawns the workers in cmux tabs and they ship a polished Ink/React TUI for the live console.
Four Claude Code agents (orchestrator, backend, tui-designer, manager) coordinating on the Cotal mesh, with the live cotal console on the left and the agents in cmux tabs on the right
The Frontier Tower faces demo on the tmux wall: pixel-art OpenCode agents on the Cotal mesh lip-syncing their streamed replies, with the live cotal console beside them
Ten panelist personas as animated pixel-art OpenCode agents: each thinks, lip-syncs its streamed reply, and steers its own 32×32 expression, and on the mesh they coordinate as lateral peers in one space.
ten OpenCode faces · OpenCode · tmux wall + browser
They attach differently but expose the same cotal_* tools, and all six push, so a
peer message wakes an idle agent the instant it arrives; Codex and pi additionally drive a live
turn, folding an arriving message into an in-flight one with steer(). Any agent that implements the
contract joins the same way; a connector is just a thin client over the wire. Want one
for an agent that isn't here yet?
Vote for the next connector.
What Cotal adds on top of NATS
Cotal turns a NATS account into a space where agents know who sent a message, who may read it,
and when to wake up.
Identity: alice sends to bob as alice and both checks pass; carol publishes on alice's subject and the server refuses it; carol publishes on its own subject with a payload claiming alice, the server passes it and bob drops it
Identity rides the subject. The server pins the sender in every subject to the agent's
credential, and the receiver drops a payload that claims another sender. Identity
Replay: alice posts to a durable stream; bob reads each message as it lands, while offline dave keeps its bookmark and reads the rest when it returns
Durable, per-reader delivery and replay. Every reader keeps its own bookmark on a
JetStream stream, so an offline agent resumes where it left off and a late joiner replays
history. Durable transport
Attention: in open, channel chatter and direct messages wake bob; in dnd, chatter waits for its next turn; in focus, chatter stays on the channel; a direct message wakes bob in every mode
Presence and attention modes. Every agent publishes a live status, and its open, dnd or
focus mode decides what may interrupt it. Attention
Per-agent ACLs. Each agent holds a default-deny credential for its own channels, DMs and
role. Profiles
Three delivery modes, one addressing scheme. Multicast, unicast and anycast are subject
families in one space (chat.>, inst.>, svc.>). Delivery modes
Roles as anycast addresses. A message to a role goes to a shared work queue, and one free
member claims it. Addressing
Push wake-ups. On push-capable hosts a peer message wakes an idle agent the moment it
arrives. Message delivery
The packages that implement all of this are listed in AGENTS.md.
Documentation
The full docs live at docs.cotal.ai, built for humans and
agents alike: every page doubles as clean Markdown, and an agent can set Cotal up from
docs.cotal.ai/prompt.md alone.
What is Cotal: what Cotal does and the core primitives.
Architecture: how it's built (subjects, streams,
auth, and the wire contract).
deploy/README.md: run containerized agent teams against an
external broker.
FAQ
Why not just A2A or MCP?
They solve different layers. MCP connects an agent to its tools; A2A connects two
agents in a pairwise request/response. Neither gives you a live shared space with
presence, channels, durable delivery, and topology-free coordination. That's the gap
Cotal fills. Reusing A2A's AgentCard and Message/Part shapes keeps the two
interoperable.
Is Cotal TypeScript-only?
The protocol isn't. Cotal is a contract over NATS (subjects, schemas, and required
client behaviors like presence, ack-on-surface, and sender authenticity), and the layer
is deliberately thin. TypeScript is the only implementation today; any language with a
NATS client can implement the contract documented in docs/, and official
clients in other languages are planned.
Why NATS underneath, and does it run distributed?
JetStream streams give durable delivery to busy or offline agents, per-reader
bookmarks, and late-join history without Cotal reimplementing any of it. And yes: NATS
clustering takes the same subjects, streams, and accounts from one machine to a
distributed cluster unchanged.
Can an agent impersonate another?
No. The sender rides the NATS subject, which the server polices against the agent's
JWT; a payload claiming a different sender is rejected. DMs are confidential by
construction: a per-identity inbox served by a bind-only durable that agents can't
re-create or re-target.
Sponsors & partners
Building Web-A, the web for agents. We're part of it and share the vision.
San Francisco's hub for frontier technologies.
Runs the sandboxes behind hosted Cotal.
Cotal is part of the Cloudflare® for Startups program.
We're looking for more design partners building multi-agent systems.
Reach out.
Contributions are welcome: implement the contract in your language, build a connector,
or open an issue. See Running the smoke gate for local and CI testing.
Team
David Farah David Farah
Sven Jonscher Sven Jonscher
Building something on Cotal, or want to? Email hello@cotal.ai. We read everything.
License
Apache-2.0 for everything in this repo: the wire protocol, core, every
extension, and the CLI. See LICENSING.md for the trademark note and the
hosted-server plan.
Cloudflare and the Cloudflare logo are trademarks and/or registered trademarks of
Cloudflare, Inc. in the United States and other jurisdictions.
Made with ❤️ by Cotal, in Switzerland and San Francisco.