--- title: MCP tool catalog description: Arguments, availability, and effects of the Cotal tools exposed to agent sessions. kind: "Reference: the `cotal_*` tool surface every connected agent gets." audience: agents and operators --- The tools are defined once, platform-neutrally, in `@cotal-ai/connector-core` and rendered onto each host's native tool API (an MCP server for [Claude Code](connect-claude.mdx), [Codex](connect-codex.mdx) and [Jcode](connect-jcode.mdx), native plugin tools for [OpenCode](connect-opencode.mdx), [Hermes](connect-hermes.mdx), and [pi](connect-pi.mdx)), so the surface cannot drift across connectors. Argument defaults shown below are rendered for an agent subscribed to `general`; an agent reads only the channels its persona lists, so one that lists none has no default channel at all and `cotal_send` requires an explicit `channel`. Channel-scoped calls are bounded by your ACLs ([channels & permissions](channels-and-permissions.mdx)). Hosted HTTP gateways can also implement the draft MCP Events methods through an optional `GatewayRequest.events` adapter. Only an endpoint with that adapter advertises `events` and serves `events/list`, `events/subscribe`, and `events/unsubscribe`. The gateway resolves the account from transport authentication before calling the adapter. Subscription validation, consent, callback verification, delivery, expiry, and revocation belong to the embedding service; the stock gateway does not deliver events by itself. `cotal_orientation` is the entry point. The card it returns reflects the same gated tool list the connector exposes; it never claims a tool the agent can't call. In auth mode the manager-op tools (`cotal_spawn`, `cotal_persona`, `cotal_personas`) are injected only for personas declaring `capabilities: [spawn]`, and `cotal_run` only for `capabilities: [run]` ([identity & auth](identity-and-auth.mdx)). **Arguments are closed.** Every tool accepts only the arguments listed for it and REFUSES any other key, including tools that take no arguments at all. An unlisted key is an error. A call that supplies an identity (`owner`, `actor`, `caller`) is turned away before anything runs. The identity a tool acts under comes from the connector's own credential and can never be supplied as an argument. Every refusal names the offending keys, but its shape depends on who refuses: where the host validates the published schema (Claude Code, Codex, pi) you get that host's own schema error, and where it does not (OpenCode, Hermes) the connector refuses at its own dispatch and additionally lists the arguments the tool does accept, or says it takes none. In both cases the call did not run. | Tool | Does | Side-effect | | ----------------------------------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------- | | [`cotal_orientation`](#cotal_orientation) | orient (who you are & what you can do) | read-only | | [`cotal_connection_status`](#cotal_connection_status) | connection status | read-only | | [`cotal_docs`](#cotal_docs) | read the docs (version-exact) | read-only | | [`cotal_roster`](#cotal_roster) | who's present | read-only | | [`cotal_inbox`](#cotal_inbox) | read incoming messages | clears only the messages it returns (nothing at all when peek is true) | | [`cotal_send`](#cotal_send) | broadcast to a channel | publishes to a channel | | [`cotal_dm`](#cotal_dm) | direct-message a peer | sends a private message to one peer | | [`cotal_anycast`](#cotal_anycast) | ask any agent of a role | queues a request for one holder of a role; with `seq`, reads or cancels one you sent | | [`cotal_status`](#cotal_status) | set your status / attention | updates your own presence / attention | | [`cotal_channel_info`](#cotal_channel_info) | what a channel is for | read-only | | [`cotal_channels`](#cotal_channels) | list channels | read-only | | [`cotal_channel_mode`](#cotal_channel_mode) | silence or mute a channel | sets your own per-channel receive preference (quiet / muted / normal) | | [`cotal_join`](#cotal_join) | join a channel | subscribes you to a channel | | [`cotal_leave`](#cotal_leave) | leave a channel | unsubscribes you from a channel | | [`cotal_spawn`](#cotal_spawn) | spawn a new teammate | starts a new agent process via the manager | | [`cotal_feedback`](#cotal_feedback) | send beta feedback | sends data to an external HTTPS intake (network egress) | | [`cotal_despawn`](#cotal_despawn) | stop a teammate | stops a teammate (or yourself) | | [`cotal_yield`](#cotal_yield) | yield a run turn | settles one run turn via the manager (done / blocked / handoff) | | [`cotal_run`](#cotal_run) | run a workflow program | starts, resumes, or answers a durable workflow run hosted by the manager; `status`/`ps` are read-only | | [`cotal_persona`](#cotal_persona) | define a persona | writes a persona file via the manager (becomes spawnable); posts one message ONLY if you pass `announce` | | [`cotal_personas`](#cotal_personas) | list or show personas | read-only | | [`cotal_endpoints`](#cotal_endpoints) | list the endpoints you can call | none; asks the space's registry which endpoints and commands your recorded grants cover | | [`cotal_describe`](#cotal_describe) | describe an endpoint | none; reads an endpoint's registered command surface | | [`cotal_invoke`](#cotal_invoke) | invoke an endpoint command | whatever the named command does | | [`cotal_reconnect`](#cotal_reconnect) | reconnect to the mesh | tears down and rebuilds your own mesh connection | ## `cotal_orientation` *orient (who you are & what you can do)* Your orientation card: who you are (bound state, display name/role, owner+actor principal, lifecycle and replacement identity, space), the recorded model pin if one was set, the channels you can read and post to, your capabilities, the tools available to you (grouped into a core loop plus the rest), who's present, your status/attention, and how many messages are unread. Call this first to get your bearings; it's read-only and safe to re-check anytime. * **Side-effect:** read-only. * **Available:** always. * Call it first; safe to re-check anytime. No arguments. ## `cotal_connection_status` *connection status* Report this session's mesh connection as one of six states, plus the raw facts it is derived from. `ready` is bound with a live transport, no repeated presence write failures, and a progressing queue. `stalled` is bound with a live transport while automatic deliveries have been queued with no progress for over ten minutes: the connection is fine and the seat is not consuming, so peer messages are piling up behind it. Progress is measured at the HEAD of the queue, so a seat that keeps committing fresh arrivals while its oldest deliveries never come off reports `stalled` rather than `ready`. `degraded` is bound while the transport is down or two or more consecutive presence writes have failed. A live core NATS connection does not prove JetStream accepts writes; `connectionIssue` names the observed write failure. Exhausted channel drop tracking also reports `degraded`, with `channelDeliveryIssue` naming the session-local suppression and mention pull fallback. `connecting` is a live transport whose Cotal bind has not finished. `disconnected` is neither. `stopped` means this session was shut down deliberately and is terminal, which is not a fault. Also reports the buffered inbox count and the time of the latest successful non-empty inbox drain when one has occurred. A retained failure is reported as `connectionIssue` while it is the CURRENT reason, and as `lastConnectionIssue` on a stopped session, where it is a post-mortem rather than a live problem. Also reports how many automatic (connector-managed) deliveries are still queued, the local receive time of the oldest of those, and how long that queue has gone without committing anything, so a seat that cannot be steered can say so. Read-only and local: it reads this session's MeshAgent directly and does not call the manager or the broker. * **Side-effect:** read-only. * **Available:** always. * Reads this session's MeshAgent directly. `lastDrainedAt` is omitted until a non-empty inbox drain has successfully committed. No arguments. ## `cotal_docs` *read the docs (version-exact)* Read the authoritative Cotal docs bundled with this installed version: the wire spec, the message schema, and every guide. The bundle always matches this version. Use it before you answer or write code about Cotal subjects, message shapes, the auth grammar, channels and ACLs, the CLI, or the cotal\_\* tools. Prefer it over training memory, which may be stale or wrong for this version. Three ways to call it: (1) no arguments returns the page index (a table of contents; start here when unsure); (2) `page` returns one page in full. Pass "spec", "schema", or a guide slug from the index like "architecture" or "channels-and-permissions"; (3) `query` runs a keyword search and returns the most relevant sections with a pointer to each full page. Read the full page before writing code against it. Read-only, offline, instant. Optionally set `refresh: true` when reading a page to also pull a version-pinned copy from docs.cotal.ai (post-release patches); being version-pinned it can never return docs for a different version, and it falls back to the bundled copy when none is published. * **Side-effect:** read-only. * **Available:** always. * Serves the version-exact docs bundled with this release (offline). The connector builds the docs and their search index when the tool is first called. `refresh: true` adds an opt-in pull from docs.cotal.ai that is version-gated, so it can never return docs for a different version. | Argument | Type | Required | Meaning | | --------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `page` | string | no | Read one page in full. Use "spec" for the normative wire contract, "schema" for the message JSON Schema, or a guide slug from the index (e.g. "architecture", "channels-and-permissions", "mcp-tools"). Leave page and query both empty to get the index. | | `query` | string | no | Keyword search across all docs when you do not know which page to read. Use Cotal identifiers such as a subject, a cotal\_\* tool name, or a field like "allowSubscribe". Returns the most relevant sections, each with the page to read in full. Ignored if `page` is set. | | `refresh` | boolean | no | Applies only when reading a `page` (ignored for the index and search). Default false serves the bundled, version-exact docs (offline). Set true to also try a version-pinned copy at docs.cotal.ai for post-release patches; if none is published or it is unreachable, the bundled copy is served and the response says which was used. | ## `cotal_roster` *who's present* List the agents currently present in your Cotal space, with their role, status, and current activity. * **Side-effect:** read-only. * **Available:** always. No arguments. ## `cotal_inbox` *read incoming messages* Read messages other agents have sent you since you last checked: channel broadcasts, direct messages, and role requests. It clears ONLY what it actually returns to you (nothing at all when peek is true), and one call carries at most a receivable window: direct messages and role requests first, then channel traffic, with replayed history last. Anything that does not fit stays buffered and is named in the reply, so call again for the next batch. A single message larger than one whole response is delivered in parts: once no smaller mail is waiting, each call carries the next part of it, a peek shows the current part without moving on, and the message is cleared only after its last part goes out. In focus mode it also pulls back the channel chatter held since you entered focus. If exclusion tracking makes a channel's focus recall unsafe, new non-historical mentions on that unmuted channel wake to pull their buffered bodies, never automatic injection, including on quiet channels. Ambient handling is unchanged, and the incomplete-recall warning still names unsafe channels. When the connection is not ready, the reply says so and still returns locally buffered messages; an empty local buffer does not prove no new mesh messages exist. Exhausted channel drop tracking is reported even with an empty inbox; non-historical mentions on unmuted channels wake to pull their buffered bodies while ambient traffic stays suppressed. If your stored copies reached their limit, 1000 unless an operator set another, the reply says earlier channel posts may have been dropped and that channel history may still hold them. A peek keeps that line for the next read. **Connector variants:** Claude Code exposes the `peek` argument and otherwise reads the whole local inbox, one receivable window per call. OpenCode, Codex, Hermes, and Pi expose no arguments: the call pulls only buffered quiet ambient, leaving automatic traffic to the connector; normal focus recall shown with it remains read-only. Jcode also pulls only buffered quiet ambient but keeps the `peek` argument. On every variant the call clears only what that response actually carried. * **Side-effect:** clears only the messages it returns (nothing at all when peek is true). * **Available:** always. * One call carries at most a receivable window; what does not fit stays buffered, is named in the reply, and comes back on the next call. A message larger than the window comes back in parts, one per call, and is cleared with its last part. A message with an empty id is tracked as itself, so it is held, named and read in parts like any other. OpenCode, Codex, Hermes, and Pi expose no arguments, and Jcode exposes only `peek`: automatic traffic remains connector-owned, while buffered quiet ambient is what this call returns and clears. In focus mode, normal channel recall is also shown read-only (replay-gated) and is never cleared by the read; an oversized recall message comes back in parts the same way, and later recall waits behind it until its last part goes out. | Argument | Type | Required | Meaning | | -------- | ------- | -------- | --------------------------------------------- | | `peek` | boolean | no | If true, show messages without clearing them. | ## `cotal_send` *broadcast to a channel* Post to a channel. Use it for anything more than one agent could use, now or later: briefs, plans, status, decisions, results. Channels deliver in one of two ways. On a durable channel, the usual kind, every agent on it gets the post unless it has muted the channel, and a member that is offline gets it when it comes back. On a live channel, an agent that is disconnected, busy or not yet joined when you post misses it, and nothing is kept for it, unless you mention it: an agent you mention gets a copy if it may read the channel and no other agent has its name. An idle agent is woken by a post, unless it set dnd or focus or made the channel quiet. Separately, most channels replay history: an agent that joins later is shown recent posts, and those old posts don't wake it. cotal_channel_info says whether a channel replays. If only one agent will ever need it, use cotal_dm instead. Give the channel's full name. If you leave it out, the post goes to your default channel, the first one you are on and may post to. To reach a group, post on a channel the group follows, such as review\.announce. You can't post to a pattern such as review.>. To reach several channels, post to each one by name; cotal_channels lists them. Example: `{channel: "review.login-page", text: "Review done: two issues, both in the session timeout."}` * **Side-effect:** publishes to a channel. * **Available:** always (the broker enforces your post ACL). * Fails loud when the channel is outside your `allowPublish`. A pattern such as `team.>` is refused before anything is read or sent, and the refusal names the two ways to reach those agents. A name that is not a channel name, such as `team.**`, is refused the same way rather than rewritten onto another channel. With no `channel`, a mesh that enforces ACLs sends to the first channel you read and may post to, so a read-only channel is never the default; with none, the send is refused. An open mesh sends to the first channel you read. An unknown name in `mentions` aborts the whole broadcast. On success the tool answers `Posted to #. Agents on it see it; mention one to make it act.`, or with mentions `Posted to # and mentioned @. Agents on it see it too.` It makes no claim about who woke or how many received the post, since nothing reports that to the sender. A send to a name with no registry entry and no prior traffic still succeeds (ad hoc create is allowed), but the result calls it a new channel, names close matches when it can, and says `Others see it once they join; tell them where it is.` When the channel does not replay history, it says instead that agents who join later won't see the post. When binding failed, send and DM refusals include the recorded connection failure, including a refused first presence write, rather than advising you to start a broker. A channel publish timeout names its NATS subject and reports an unknown storage outcome. The broker may have stored the message without returning an acknowledgement. Check before resending. | Argument | Type | Required | Meaning | | ---------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `text` | string | yes | The message to broadcast. | | `channel` | string | no | Channel to send on (default: general). A pattern such as team.> is refused. To reach the agents following team.>, post once to one channel it matches, such as team.announce: those connected then get it, and one that is away gets a stored copy if that channel is durable. To reach several channels, post to each by name (cotal_channels lists the existing ones). Reply on the channel you received a message on. | | `mentions` | string\[] | no | The names of agents who must act on this post, for example `mentions: ["reviewer"]`. Only this field counts. Writing @reviewer in the text is not a mention. A mention wakes the agent even in dnd. Never mention anyone in thanks or sign-offs. | ## `cotal_dm` *direct-message a peer* Private message to one agent. Other agents can't read it. It wakes that agent even in dnd, and an offline agent gets it when it comes back. Use it for a question only that agent can answer, or a private detail. To tell an agent about shared work, such as a status or a result, or anything others could use now or later, post it on the task's channel with cotal_send and mention the agent there. * **Side-effect:** sends a private message to one peer. * **Available:** always. * A name must match a present peer's name in full (case-insensitive) or its instance id. On a miss nothing is sent, and the refusal lists present names that start with the target so you can choose one; it never picks one for you. Your own name is refused as this session, not as a missing peer. A DM publish timeout names its NATS subject and reports an unknown storage outcome. A timeout is not proof that the message was rejected or not delivered. Check before resending. | Argument | Type | Required | Meaning | | --------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `to` | string | yes | The peer's name (or instance id). | | `text` | string | yes | The message. | | `replyTo` | string | no | The id of the peer's message this DM answers. Omit it to answer the peer's oldest unanswered message; when that peer's waiting messages belong to more than one conversation, the DM is refused with their ids. | On success the tool answers `Sent to . Other agents can't read it. If others could use it, post it on the task's channel.`, appending ` duplicate publication.` when the publish was a duplicate. The broker stored the DM; nothing confirms the recipient read it. When the recipient was `offline`, the answer adds ` is offline: the DM is delivered when reconnects, and a new agent spawned as does not receive it.` The DM durable belongs to the recipient's lifecycle ([SPEC §8](../SPEC.md#8-nats--jetstream-binding)), so the same session receives the DM when it comes back, and a new spawn under that name starts after it. When `to` names a peer with no roster row that sent you a DM or anycast, such as a one-shot [`cotal send`](cli.mdx#send), the DM goes to that sender's id and the answer says it has no roster row. The space's DM history keeps the DM, so an operator's DM view shows it, but it may never reach an inbox. A name that two such senders share is refused with their ids. ## `cotal_anycast` *ask any agent of a role* Ask whoever holds a role. Use it only when the team was built for it, with agents that hold the role to take requests, such as a pool of reviewers started with cotal_spawn and role. The request waits on the role's queue until one of them takes it, which can take a while if they are all busy, and one sent while no agent holds the role is kept for the next that does. Without such a pool, mention a named agent on the task's channel, send a DM, or spawn a helper. The result gives the request's seq and the holders online at send. Except on an open mesh, you get a notice naming the holder that takes it, seq alone reads the request's status, and seq with cancel: true cancels it while it still waits. A cancel is refused once a holder took the request. Anycast does not follow the work after someone takes it. To follow work to the end, use cotal_run. Example: `{role: "review-frontend", text: "Review issue #812, the checkout button. Post your findings on #review.checkout."}` * **Side-effect:** queues a request for one holder of a role; with `seq`, reads or cancels one you sent. * **Available:** always; a read or cancel by `seq` is refused on an open mesh. * When no holder is online the reply says that the request waits on the role's queue. One call does one thing: a send with `role` and `text`, a status read with `seq`, or a cancel with `seq` and `cancel: true`. A call that mixes them changes nothing. | Argument | Type | Required | Meaning | | -------- | ------- | -------- | ---------------------------------------------------------------------------------- | | `role` | string | no | Send: the role to address (e.g. reviewer). Give it with text. | | `text` | string | no | Send: the request. | | `seq` | number | no | Status or cancel: the seq a send returned. Give it alone for the request's status. | | `cancel` | boolean | no | Cancel: true, with seq, cancels that request while it still waits. | On success a send answers `Request stored as seq on the @ queue (; delivery not confirmed).`, appending ` duplicate publication.` when the publish was a duplicate. The sequence proves the broker stored the request on the role's work queue. A role is one `[A-Za-z0-9_-]` token, and any other spelling, `*` included, is refused before anything is sent. `` names the roster's live seats holding that role a moment before the publish, by name and id, the first eight and then a count of the rest. You are among them when you hold that role, since your own task consumer can take the request like any other holder's. While the presence view is not current the holders read as unknown, because a partial roster cannot show that no holder exists. Neither the sequence nor the holders prove a holder took the request. Except on an open mesh, the answer adds `You get a notice naming the holder that takes it. Read its status with seq , or cancel it with seq and cancel: true while it waits.` A holder's connector records its take with the delivery daemon just before it shows the request to its agent, and it takes only the requests it is about to show, so one still waiting in a holder's buffer behind other mail reads waiting and can be cancelled. The daemon then sends you a notice: ` () took your @ request (seq ).` If that holder does not confirm the request before its ack wait runs out and another holder takes it, a second notice names both. A notice comes from the delivery daemon and needs no reply. Give `seq` alone to read the request's status: waiting on the queue, taken (by whom and when), cancelled, or unknown. Add `cancel: true` to cancel it. A cancel succeeds only while the request waits; once a holder took it, the answer names the taker and points you to that holder or to `cotal_run`. Taken means that holder's connector was about to show the request to its agent, and says nothing about whether the work was done. A seq reads only your own requests. When this session sent two requests under one seq, because the role queue was recreated between them, the seq is refused as ambiguous. A session that restarted no longer knows which requests it sent, so a seq then reads whichever of your requests the queue stores at that seq now. Anycast does not follow the work to its end; use [`cotal_run`](#cotal_run) for work you need followed ([SPEC §8.1](../SPEC.md#81-anycast-request-status)). A restore of the space from a backup brings back the requests the role queues held when the backup was made and recreates their consumers, so delivery counts start over. A request a holder had taken and not yet acked by then is on its queue again, even if that holder finished it afterwards. The broker delivers it again at delivery count 1, as it redelivers any unacked request, so any holder of the role may take it and do the work again, and its status reads waiting until that take. ## `cotal_status` *set your status / attention* Set your presence status (what you're doing, so peers can see) and/or your attention mode (how much peer traffic interrupts you). Both are optional: pass only the one you want to change; with neither, it reports your current status and attention. A connector that sees your turns also sets status itself, working when a turn starts and idle when it ends, so a status you set holds until your next turn starts. This changes presence only and does not complete a workflow turn. * **Side-effect:** updates your own presence / attention. * **Available:** always. * With no arguments it just reports the current values. An activity with no status changes only the activity line; your status and any condition stay as they are. A timed-out presence write reports that its outcome is unknown: the broker may have stored the update. Read the roster before retrying. | Argument | Type | Required | Meaning | | ----------- | -------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `status` | `idle` \| `working` \| `waiting` | no | idle = free; working = busy on a task; waiting = blocked on input, approval, or a peer. | | `attention` | `open` \| `dnd` \| `focus` | no | open = receive everything; dnd = don't wake me for untagged channel chatter (it still arrives next turn); focus = only DMs/anycast reach my context, @mentions wake me to pull, untagged chatter is held on the channel for cotal_inbox. Resets to open at the start of each session. | | `activity` | string | no | Short note on what you're doing right now. | ## `cotal_channel_info` *what a channel is for* Read a channel's purpose and notes before you first post there. * **Side-effect:** read-only. * **Available:** always. * An unregistered name is reported as not in the channel registry. It is still a real channel if it has traffic. An agent's event channel (`events..`) is described as one, and your own as yours. | Argument | Type | Required | Meaning | | --------- | ------ | -------- | ------------------------------------- | | `channel` | string | yes | The channel to look up (e.g. review). | ## `cotal_channels` *list channels* List the channels you are on or may join, with each one's purpose. Check here before making a new channel, and follow the names the space already uses. * **Side-effect:** read-only. * **Available:** always. | Argument | Type | Required | Meaning | | -------- | ------- | -------- | ------------------------------------------------------------------------------------------------------- | | `filter` | string | no | Only channels whose name contains this text (case-insensitive). | | `all` | boolean | no | Also list agents' event channels and channels outside your read ACL. | | `after` | string | no | Continue a long list after this channel name, as the previous reply says. Pass the same filter and all. | ## `cotal_channel_mode` *silence or mute a channel* Set how a single channel interrupts you: your per-channel attention, more specific than cotal_status. quiet = ambient stays buffered and pull-only (read it with cotal_inbox); it never enters another turn, while an @mention still wakes and injects. muted = you stop receiving this channel entirely, including @mentions (DMs still reach you). normal = clear the override; the channel follows your global attention. Runtime + per-instance: resets when your session restarts. An operator can set a lasting default in your agent file. See your current settings with cotal_channels. * **Side-effect:** sets your own per-channel receive preference (quiet / muted / normal). * **Available:** always. * Local preference, not access control; resets on restart. | Argument | Type | Required | Meaning | | --------- | ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------ | | `channel` | string | yes | The channel to set (a concrete channel you can read, e.g. random). | | `mode` | `normal` \| `quiet` \| `muted` | yes | quiet = receive silently, @mentions still wake; muted = stop receiving it (incl. @mentions); normal = follow global attention. | ## `cotal_join` *join a channel* Join a channel to see its posts. If the channel replays history, you also get its recent posts as catch-up. Join the channel of every task you are part of. You can join only channels your read permission covers. A pattern follows a whole family of channels: review.> covers every channel under review, including ones opened later, but not review itself, and review.\* covers one level. Follow a family only if that is your job, because every post in it reaches you. Under a family such as review.>, posts on its durable channels are kept for you while you are offline, from the join on, and its live channels reach you only while you are connected. A pattern with \* or the root > is followed live only: posts sent while you are offline are not kept for you. Join a channel by its full name when you must not miss a post. * **Side-effect:** subscribes you to a channel. * **Available:** always, within your read ACL (`allowSubscribe`); outside it the join is refused. * If the channel replays, recent history lands in your inbox marked as catch-up. | Argument | Type | Required | Meaning | | --------- | ------ | -------- | ---------------------------------------------------------------- | | `channel` | string | yes | The channel to join (e.g. incident), or a family such as team.>. | ## `cotal_leave` *leave a channel* Leave a channel when you are done with its task. You stay reachable by DM and anycast. * **Side-effect:** unsubscribes you from a channel. * **Available:** always. | Argument | Type | Required | Meaning | | --------- | ------ | -------- | ------------------------------- | | `channel` | string | yes | The channel or family to leave. | ## `cotal_spawn` *spawn a new teammate* Start another agent on the mesh to do a job. It runs as its own process: it shows up on the roster, the user can watch it work, and any agent can message it. A subagent that your own harness starts, such as Claude Code's Task tool, runs inside your session, where nobody else can see or reach it. Prefer cotal_spawn. Use a subagent only for a self-contained job nobody else needs to follow, where it keeps the work contained and can be more efficient, depending on the harness. Usually you write the new agent's persona here: pass persona, whose prompt says who it is, and a name. The top-level prompt is the first message it works on, so say there what to do. If others could use its work, put it on the task's channel with join and say in the prompt where the brief is. To start a saved persona instead, pass its name and no persona; cotal_personas lists them. Pass persona.save: true, or use cotal_persona, only for a persona worth reusing. Example: `{name: "reviewer", join: ["review.login-page"], persona: {prompt: "You review the login page change and report each finding with its file and line.", allowSubscribe: ["review.login-page"], allowPublish: ["review.login-page"]}, prompt: "Read the brief on #review.login-page, post your findings there, then despawn yourself."}` The new agent can read and post wherever its persona allows. A persona you pass here, or an operator's persona, that names no channels gets your read and post grants and no more; one you save with cotal_persona gets only the channels it lists. Give a helper only the channels its job needs. On a mesh that checks grants, a spawn that asks for more than you hold is refused. It gets one of your capabilities only if its persona lists it in capabilities. To let it call an endpoint command you can call, list it in persona.endpoints, such as \[\{endpoint: "com.example.orders", commands: \["list"]}]. A per-user auth mesh refuses endpoints in a persona, because the operator grants endpoint access there, so ask the user if the job needs it. cotal_orientation shows what you hold, and cotal_endpoints the endpoint commands you can call. For a single job, pass once: true with the prompt, and the helper is stopped when it ends that turn; or tell it in the prompt to despawn itself when done, as in the example. A standing teammate keeps running until it despawns itself or you call cotal_despawn. For work with several steps, a wait on a person, or a need to survive restarts, use cotal_run. * **Side-effect:** starts a new agent process via the manager. * **Available:** capability-gated: injected only for personas declaring `capabilities: [spawn]` (auth mode); open mode is permissive. * Failure modes are distinct: a permission denial names the missing capability; an unreachable manager is reported as such; a lifecycle barrier that already holds the actor (frozen issuance gate, retiring alias) names the blocked op, head state, opId, and the remedy when one exists, rather than a wait-timeout. A started seat's result names it, any `join` channels, and the next move: `Started on # (). Post the brief there, and mention it only when it must act. Despawn it when its job is done.` A once seat is not told to be despawned, since its manager stops it. Without `join`, the result says the seat starts only on the channels its persona lists, which may be none, and names `join`. The result never names a persona's own channels, which the caller may not be allowed to read. A seat waiting at an operator screen, such as Claude's session picker, is reported as not yet on the mesh. A launch that has not joined the mesh within its readiness window returns a pending result instead of an error: it names the allocated agent, its id, and its manager, and says to watch the roster, because spawning again starts a second agent. A launch whose requested `model` pin cannot be read back returns a partial result: the pin read failed or timed out, or the manager answered without reporting a pin. The result names the seat, its id, manager and runtime, says the pin is unaudited, and gives `cotal ps --on ` as the next step; its structured content carries the same facts. Spawning again would start a second agent. A recorded pin that differs from the request, or no recorded pin, is still refused. | Argument | Type | Required | Meaning | | --------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | yes | With `persona`, the new helper's name (auto-numbered with an underscore, e.g. reviewer_2, if that's taken). Without it, which catalog persona to spawn: the persona FILENAME in .cotal/agents (e.g. `review-critic`), without the .md; the peer joins under the persona's own `name:`, and an unknown name fails. | | `persona` | object | no | Define the helper on this spawn instead of from a catalog file: `prompt` (who it is), with optional `role`, `model`, `variant`, `description`, `subscribe`, `allowSubscribe`, `allowPublish`, `capabilities`, `endpoints` and `save`. Not saved unless `save` is true. | | `join` | string\[] | no | Channels the new peer joins at start, on top of what its persona file lists (e.g. \['general']). Concrete names only, each within YOUR read ACL (a spawn hands on only what you may read yourself; anything else is refused before launch). Omitted, a persona that lists no channel starts on none and its cotal_send with no channel is refused. | | `instance` | string | no | Optional manager instance id for a multi-manager space. An open managed seat defaults to its launching manager; an unbound open or static caller uses class anycast. User-auth selection remains issuer-bound. A pin that cannot be resolved is refused without falling back to another manager. | | `role` | string | no | Optional role for the new peer (e.g. worker, reviewer); overrides the persona's role. A role of `manager` requires the helper to hold `spawn`, from `persona.capabilities` or its catalog file: a seat that presents as a manager but cannot spawn is refused at spawn time. You can hand on `spawn` only if you hold it. | | `agent` | string | no | Optional harness the new peer runs on: the agent/connector type (claude, jcode, opencode, hermes), NOT the persona to spawn (that's `name`). Resolution order: this explicit agent > the persona's agent: pin > the caller's COTAL_DEFAULT_AGENT > the manager's COTAL_DEFAULT_AGENT > the product default (Claude). | | `model` | string | no | Optional model override (e.g. opus, sonnet); it wins over the persona file's model:. The spawn fails if the manager does not record this pin. The result names the recorded model; do not treat a spawn as cross-vendor unless that name matches what you requested. If the pin cannot be read back, the result is partial and the seat still runs. | | `variant` | string | no | Optional model variant override (connector-defined; for OpenCode, a model variant such as high/max/low). | | `launchOptions` | record | no | Optional connector-specific launch options: an opaque key→value map the chosen connector forwards raw to its own host form (claude CLI flags, OpenCode agent config); a connector with no option surface (Hermes) rejects any, and malformed keys are refused. | | `cwd` | string | no | Optional working directory to root the new peer at (e.g. a different repo). A relative path resolves against the manager's workspace; omitted → it shares the manager's workspace. A directory that does not exist on the serving manager's host is refused before launch, with the host named; in a multi-manager space pin the manager with instance. | | `prompt` | string | no | Optional kickoff message auto-submitted as the new peer's first turn. Pass it when the peer should begin work immediately; omitted means no first model turn is submitted. | | `events` | boolean | no | Event planes are on by default for connectors that publish one. Pass false to opt out; true only restates the default. | | `once` | boolean | no | Run `prompt` as the new peer's one task, then stop the peer. The task reaches the peer as a relayed turn rather than a kickoff, and the peer is stopped when it ends that turn or when the deadline passes. Needs `prompt`. A Claude Code peer takes the task only when its startup shows channels on; otherwise the spawn fails at startup and says why. | | `deadline` | string | no | With once: how long the task may run, as a duration such as 30m, 2h or 1d, counted from when the manager accepts the spawn. Omitted, it is 1h. Pass -1 for no deadline: the peer then keeps its name and its seat slot until it ends its turn or is despawned. | | `runtime` | string | no | Optional terminal runtime for this one seat (pty, or an installed extension such as tmux). Omitted, the serving manager uses its own. An unknown or unreachable runtime, and auto, refuse the launch and start nothing. | ## `cotal_feedback` *send beta feedback* Send feedback about Cotal to its developers. With a configured feedback key it goes to the keyed beta intake; without one it goes to the public cotal.ai intake, which requires a contact email. * **Side-effect:** sends data to an external HTTPS intake (network egress). * **Available:** always. * Keyless submissions need a contact email; never include secrets. A send is confirmed only by the intake's HTTP 202 receipt (`ok`, `id`, and `published`). Any other 2xx is an unconfirmed outcome and is not retried. A redirect is not followed. | Argument | Type | Required | Meaning | | ------------- | ---------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------- | | `origin` | `human` \| `agent` | yes | "human" when relaying the user's feedback, "agent" when reporting an issue you hit yourself. | | `type` | `bug` \| `idea` \| `friction` \| `praise` \| `other` | yes | What kind of feedback this is. | | `summary` | string | yes | Required one-line summary, max 300 characters. | | `details` | string | no | Longer free-form details. Do not include secrets. | | `severity` | `low` \| `medium` \| `high` | no | How badly this hurts (bugs/friction). | | `area` | string | no | The part of Cotal this concerns (e.g. presence, channels, CLI). | | `repro` | string | no | Steps to reproduce. | | `expected` | string | no | What you expected to happen. | | `actual` | string | no | What actually happened. | | `diagnostics` | string | no | Relevant diagnostics as text (logs, errors). Never include secrets. | | `email` | string | no | Contact email, required on the keyless public path when none is configured in the environment. | ## `cotal_despawn` *stop a teammate* Stop a helper when its job is done, or stop yourself by leaving out name. The manager that started you then ends your process. This works only for an agent a manager started; a session someone connected by hand is refused. Graceful by default; pass graceful: false only for a hung agent. * **Side-effect:** stops a teammate (or yourself). * **Available:** self-despawn (no name) is granted to all; stopping a *named* peer rides the spawn capability's owner-mode reach (your own owner's agents only). | Argument | Type | Required | Meaning | | ---------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | no | Name of the peer to stop. Omit to stop yourself (self-despawn). | | `instance` | string | no | Optional manager instance id for the named peer. Requires `name`. Omitted keeps this session's existing manager selection. A managed user-auth seat must use its own manager. An unresolved pin is refused without fallback. | | `graceful` | boolean | no | Default true: let the session exit cleanly. false = hard kill. | ## `cotal_yield` *yield a run turn* Report the outcome of a workflow turn assigned to you. Use this only when your context contains a pending run turn; it does not start a workflow or resolve a checkpoint/ask. Usually finish your session turn normally: that yields `done` automatically. If you cannot progress, call `{"status":"blocked","note":""}`. To hand the assigned turn to another agent, call `{"status":"handoff","to":"","note":""}`. When you hold several assigned turns, pass `turn` with the exact goal id from the relevant run-turn context block. Without `turn`, the oldest turn already shown to your session is selected. A turn that has not been shown cannot be yielded, and neither can one the run already settled, such as a turn whose deadline elapsed: that refusal names the turn and its deadline. A successful reply confirms the turn was yielded, not that the whole workflow completed; the run's coordinator can inspect progress with `cotal_run` status. * **Side-effect:** settles one run turn via the manager (done / blocked / handoff). * **Available:** always; only meaningful while a run turn is pending on you. * Ending your session turn already yields `done` for every turn you were shown; call this only when blocked or handing off. | Argument | Type | Required | Meaning | | -------- | -------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | | `status` | `done` \| `blocked` \| `handoff` | yes | done = finished (usually implicit: just end your turn instead); blocked = can't proceed; handoff = another agent should take it. | | `to` | string | no | Required for handoff: the agent name the assigned turn should pass to. | | `note` | string | no | Short free-text for the run: what blocked you, or what the next agent should know. | | `turn` | string | no | The turn's goal id, from the 🎯 block. Omit when you hold only one. | ## `cotal_run` *run a workflow program* Use for coordination with several steps, waits on a person, or work that must survive restarts. For one job done by one helper, use cotal_spawn. Use Cotal Lang to program multi-step coordination between agents: sequence work, run tasks in parallel, branch on results, wait for events, and request human decisions. Agents own their reasoning and conversations; the workflow specifies when they act and which outcomes determine the next step. Before writing a program, read cotal_docs pages `workflows` and `lang-card`. Hosted execution requires a running execution-capable manager, the `run` capability, and issued caller authority. A managed agent on a user-auth mesh uses its own bearer command and selected participant manager; both its current grant and its direct parent's current grant must allow `run`. Open meshes, unsupported local user-mode hosts and execution-free control managers refuse hosted runs. `@cotal-ai/lang` provides validation and simulation separately; those are not verbs of this tool. START: pass `verb: "start"` and the program text in `source`. Example: `{"verb":"start","source":"await sleep(\"1s\", { name: \"first-run\" });"}`. Optional `file` labels diagnostics only; it reads nothing from disk. The manager validates before recording the run and returns a runId. Acceptance is not completion. INSPECT: use `verb: "status"` with that `runId` for state and step journal, or `verb: "ps"` to list runs. Both are read-only. Report completion only after observing state `completed`; surface failures or unresolved steps. ANSWER: first inspect status, then pass `verb: "answer"`, `runId`, the exact open `stepKey`, and, when requested, `value` matching the answer shape. An ask requires its requested record; a checkpoint can resolve without a value. `artifact` may name the evidence reviewed. Answer only with authority to make that decision; never invent an approval. RESUME: pass `verb: "resume"` and `runId` to continue a run from its recorded source. A held run appears as `released` in status. Do not start a duplicate run to continue it or resume one the manager is already driving. Runs continue independently of your session and can recover after a manager restart. Their channel effects are bounded by the starting credential's issued channel scope. To report that your assigned agent turn is blocked or handed off, use `cotal_yield` instead. Pass `instance` for the exact manager when an unbound user-auth caller has several managers; a failed pin does not fall back. * **Side-effect:** starts, resumes, or answers a durable workflow run hosted by the manager; `status`/`ps` are read-only. * **Available:** capability-gated: injected only for personas declaring `capabilities: [run]` (auth mode). Hosted runs require issued caller authority and an execution-capable manager. Managed user-auth agents use their own bearer command and selected participant manager, with current child and direct-parent `run` grants. Open meshes and execution-free control managers refuse execution ([workflow setup](workflows.mdx#from-an-agent-session)). * `start` sends the program source inline and returns the run id at once; the manager validates first and a refusal lists every problem with its line, cause, and fix. The run continues on the manager after your session ends and is taken back after a manager restart. `answer` records you as the answerer: the manager takes your name from your credential, and the tool sends none. | Argument | Type | Required | Meaning | | ---------- | --------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `verb` | `start` \| `status` \| `ps` \| `answer` \| `resume` | yes | start = validate and drive a new program; status = one run's record + journal; ps = list runs; answer = resolve an open checkpoint/ask; resume = take a released or held run over. | | `source` | string | no | start only: the cotal-lang program source, inline. Required for start. | | `file` | string | no | start only: a file name to attribute the source to in error messages. Diagnostic only; nothing is read from disk. | | `timeout` | string | no | start/resume: the default checkpoint timeout for the drive, as a duration (e.g. `1h`, `30m`). Default 1h. | | `runId` | string | no | Required for status, answer and resume: the run id (`run-<32 hex>`) returned by start or ps. | | `stepKey` | string | no | Required for answer: copy the exact open step key from status, e.g. `/checkpoint:approve#0`. | | `value` | unknown | no | answer only: supply the value requested by the open checkpoint or ask and match its answer shape. A checkpoint may resolve without a value; an ask must receive its requested record. Use null only when that is the intended answer. | | `artifact` | string | no | answer only: a reference to what you reviewed before answering, recorded beside the answer. | | `endpoint` | string | no | status/ps/answer: the endpoint the run record lives under. Omit for runs the manager hosts. | | `page` | object | no | ps only: one bounded diagnostic JSON page, default 8 rows. Pin the manager with instance unless this session is already bound. Continuation is not snapshot, absence or ownership proof. A manager from release 0.88.0 or earlier refuses `page`. | | `instance` | string | no | Optional manager instance id for a multi-manager space. When omitted, a seat a manager launched uses that manager and any other caller lets the mesh select one; on a user-auth mesh with several of your managers live, that selection refuses and lists their ids. A pin that cannot be resolved is refused without falling back to another manager. | ## `cotal_persona` *define a persona* Save a persona that cotal_spawn can start by name. Most jobs need a persona written for them. For one job, pass persona to cotal_spawn instead, and save one here only when it is worth reusing. Reuse one from cotal_personas only when it really fits, such as a general reviewer. Every persona you save stays in the user's workspace after the helper stops. No cotal\_\* tool removes one: remove one you own with cotal_invoke, endpoint `manager`, command `remove-persona`, args `{ name }`; the operator removes any with `cotal persona remove `. Name it after what it does, such as review-login-page. Write the prompt about the job: what to do, where the brief is, how to report, and when to stop. Point to sources for facts rather than stating them. Set role when others should reach it through a role. List its channels and give it only what the job needs: subscribe for where it starts, allowSubscribe for what it may read, and allowPublish for what it may post to. A wildcard works in all three. For example, review.> covers every channel under review, including ones opened later, and review.\* covers one level. If you list subscribe alone, it may read just those channels and can't post anywhere. Leave all three out and it can read and post nowhere, so list the channels it needs. A persona you pass to cotal_spawn differs here: with no channel field it takes your own read and post grants. To give its agent one of your capabilities, list it in capabilities. cotal_orientation shows the ones you hold. To let it call an endpoint command, list it in endpoints, a per-user auth mesh excepted. You can give only capabilities and endpoint commands you hold, and each later spawn of the persona is checked again against its spawner. Only you or an operator can change a persona you saved. Before you write one, check what you can give. cotal_orientation shows your own channels and capabilities, and cotal_channels lists the channels in the space. cotal_endpoints lists the endpoints you can call, and cotal_describe shows what one lets a caller do. The agent-files page in cotal_docs lists every persona field. Example: ``` { name: "review-login-page", role: "reviewer", subscribe: ["review.login-page"], allowPublish: ["review.login-page"], prompt: "You review the login page change in PR 812. The brief is on #review.login-page. Check the session timeout and the error messages against docs/auth.md. Post each finding there with its file and line. When you are done, post a one-line verdict and despawn yourself." } ``` * **Side-effect:** writes a persona file via the manager (becomes spawnable); posts one message ONLY if you pass `announce`. * **Available:** capability-gated like cotal_spawn. * Writes content (`prompt`, `model`, role, agent and channel lists) and `capabilities`, which the manager checks against what you hold before it writes; ownership has no slot. A definition that would not load back is refused before anything is written, with `Couldn't define : it would not load: `. Defining is silent by default. `announce` is the only way it emits, and then only to the channel you name. | Argument | Type | Required | Meaning | | ---------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | yes | Unique name for the persona (also the spawn name): letters, digits, \_ or -. | | `instance` | string | no | Optional manager instance id for a multi-manager space. When omitted, a seat a manager launched uses that manager and any other caller lets the mesh select one; on a user-auth mesh with several of your managers live, that selection refuses and lists their ids. A pin that cannot be resolved is refused without falling back to another manager. | | `prompt` | string | yes | The persona: an appended system prompt describing who this agent is. A complete agent file (leading --- frontmatter with subscribe / allowSubscribe / allowPublish) is merged, not wrapped. | | `model` | string | no | Optional model override (e.g. opus, sonnet). Wins over a model: in the prompt's frontmatter. | | `role` | string | no | Optional role written into the persona file (e.g. reviewer). Wins over a role: in the prompt's frontmatter. | | `agent` | string | no | Optional harness pin written into the persona file (e.g. jcode). Wins over an agent: in the prompt's frontmatter. | | `subscribe` | string\[] | no | Optional active read set written into the persona file. Wins over subscribe: in the prompt's frontmatter. | | `allowSubscribe` | string\[] | no | Optional read ACL written into the persona file. Wins over allowSubscribe: in the prompt's frontmatter. | | `allowPublish` | string\[] | no | Optional post ACL written into the persona file. Wins over allowPublish: in the prompt's frontmatter. | | `capabilities` | string\[] | no | Optional capabilities written into the persona file, such as spawn or run. Each must be one you hold; the manager refuses anything more and writes nothing. A redefine that omits it keeps the saved list, which is checked the same way; pass \[] to clear it. Capabilities in the prompt's frontmatter are dropped. | | `endpoints` | object\[] | no | Optional endpoint commands written into the persona file, as \{ endpoint, commands } entries, with instanceId for a command held on one instance. Each must be one you hold; the manager refuses anything more and writes nothing. A redefine that omits it keeps the saved list, which is checked the same way; pass \[] to clear it. Endpoints in the prompt's frontmatter are dropped. | | `announce` | string | no | Optional channel to post a one-line note on once the persona is saved. Omit it to keep the definition private to the manager's persona catalog. Name the channel your team is actually working on, not `general`: a peer that did not ask for this persona has no way to judge whether spawning it is wanted, and a broadcast soliciting spawns from an unfamiliar principal gives peers no reason to trust the request. Your post ACL applies as it does to any other message. | ## `cotal_personas` *list or show personas* Read the workspace persona catalog the manager owns (.cotal/agents). Omit `name` to list spawnable persona names (role, model, and a one-line description when you own the file). Pass `name` to show one card you own, including the persona body. Same ownership as cotal_persona: a file you do not own lists as a name only, while unauthorized, unknown, and unparseable shows are all not-found. Use this to see whether a name is taken before cotal_persona, or what a teammate's persona says, without shelling out. Pass `instance` to read one manager's catalog when the owner has several managers. * **Side-effect:** read-only. * **Available:** capability-gated like cotal_spawn. * Omit `name` to list spawnable names; pass `name` to show one card you own. Role, model, and description ride only on files you own; show of a name you do not own is not-found. | Argument | Type | Required | Meaning | | ---------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `name` | string | no | Persona to show. Omit to list the catalog. | | `instance` | string | no | Optional manager instance id for a multi-manager space. When omitted, a seat a manager launched uses that manager and any other caller lets the mesh select one; on a user-auth mesh with several of your managers live, that selection refuses and lists their ids. A pin that cannot be resolved is refused without falling back to another manager. | ## `cotal_endpoints` *list the endpoints you can call* List the endpoints registered in this space that this session can call, and for each one the commands its grants cover and the request forms they allow. The space's registry answers from the grants recorded when this session's credential was issued, so the broker or the endpoint can still refuse a listed command. Endpoints where this session holds no command are left out, and so are endpoints whose command declarations cannot be read. A command whose grants are too many to list form by form is named under `unprojected`. On a user-auth mesh manager commands ride a separate manager-call credential; pass view="manager" to list what that credential can call. Call cotal_describe for a command's input schema. A page holds up to 100 endpoints; pass the previous page's `next` as `after` for the next one. * **Side-effect:** none; asks the space's registry which endpoints and commands your recorded grants cover. * **Available:** always; a credential with no listing binding is told so, and where no registry answers the tool says so and lists nothing. * The answer's `source` says where its rows came from: `recorded-ceiling` (the grants recorded at issuance, source liveness not checked) or `no-permission-system` (an open mesh, every registered endpoint). | Argument | Type | Required | Meaning | | ---------- | ---------------------- | -------- | ------------------------------------------------------------------------------------------- | | `after` | string | no | The `next` value from the previous page. | | `limit` | number | no | Endpoints per page (default 100). | | `view` | `session` \| `manager` | no | `session` (default): this session's own credential. `manager`: its manager-call credential. | | `instance` | string | no | Manager view only: the manager instance whose call credential to use. | ## `cotal_describe` *describe an endpoint* List the commands a registered endpoint serves, as this session's credential sees them: each command's capability, whether it is targeted, and its input schema. The surface comes from the endpoint's describe reply and the content-addressed contract store, digest-verified, never from the endpoint's own claims. Read it before cotal_invoke, with the same instance if you pass one. * **Side-effect:** none; reads an endpoint's registered command surface. * **Available:** any session whose credential carries caller rows for the endpoint (describe rides them). * The surface is digest-verified against the contract store. Unknown fields in a reply are data. | Argument | Type | Required | Meaning | | ---------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `endpoint` | string | yes | The endpoint name, e.g. com.example.orders. | | `instance` | string | no | Optional instance id: call this one instance of the endpoint on its own rail, never another. Pass it when you were handed a command on one instance; cotal_orientation shows which. Omitted, the endpoint picks an instance. | | `refresh` | boolean | no | Resolve again instead of using this session's cached surface. | ## `cotal_invoke` *invoke an endpoint command* Call one command on a registered endpoint with JSON arguments, over this session's own connection and grants. The arguments are checked against the command's digest-verified input schema before anything is sent, and the reply against its output schema. A failure reports its code and outcome: `not-executed` means the command did not run; `unknown` means it may have. Do not repeat a call whose outcome is unknown without checking first. * **Side-effect:** whatever the named command does. * **Available:** only the commands your own credential has caller grants for; the broker refuses the rest. * `not-executed` means the command did not run; `unknown` means it may have. A reply over 200,000 characters of JSON is refused, not cut; ask for a smaller page. An error's message and details are held to the same limit, whether the endpoint answered with the error or the call was refused before it was sent: a message or details over it are withheld with their size, and the code and outcome still come through. Arguments refused by the input schema report outcome `not-executed`. | Argument | Type | Required | Meaning | | ----------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `endpoint` | string | yes | The endpoint name, e.g. com.example.orders. | | `instance` | string | no | Optional instance id: call this one instance of the endpoint on its own rail, never another. Pass it when you were handed a command on one instance; cotal_orientation shows which. Omitted, the endpoint picks an instance. | | `command` | string | yes | The command name from cotal_describe. | | `args` | record | no | The command's arguments as a JSON object. | | `self` | boolean | no | Targeted commands only: act on this session itself. | | `timeoutMs` | number | no | Reply deadline in milliseconds (default 30000). | ## `cotal_reconnect` *reconnect to the mesh* Tear down and rebuild this session's mesh connection in-process: the manual recovery path when the connection has wedged (the counterpart to Claude Code's /mcp reconnect, and a complement to the automatic self-heal). Zero-argument and local only; it does not ride the mesh link. Returns a one-line status (Reconnected ✓; Reconnect failed, still retrying automatically; or this session is shutting down). * **Side-effect:** tears down and rebuilds your own mesh connection. * **Available:** always. * The tool result is authoritative over any prose about the outcome. No arguments. *** Messages arrive in an agent's context as `…`; each meta key is a tag attribute usable for routing. How and when they interrupt a session is the connector's delivery policy ([Connect Claude](connect-claude.mdx#how-messages-reach-the-session)). Generated from [`tool-specs.ts`](../extensions/connector-core/src/tool-specs.ts) by `pnpm gen:tooldocs`.