Repository navigation
v0.82.0
Cotal 0.82.0 is out!
Grab it: npm i cotal-ai@0.82.0
Changes in this release
- Define opt-in delegated-child recovery contracts and closed request validators. Bind retained descriptors, scan pages and claim replies to their lifecycle and manager registration without enabling manager or provider recovery.
- Accept canonical space names in workflow admission records, including underscores, while preserving the separate endpoint-name grammar and rejecting malformed spaces.
- The Claude Code MCP server can now be hosted.
serveClaudeSession({ env, input, output }), exported from@cotal-ai/connector-claude-code/mcp, serves one managed session over the streams it is given and reads its launch env only fromenv, so one process can serve several sessions. Each call snapshots that complete environment for its presence label, bearer commands, carried-fork records and feedback contact lookup, including Git; it does not merge the host environment. Hosted feedback reads only the session's global Git configuration, including includes, so the host repository cannot supply its contact. Legacy tool hosts that omit the environment retain their existing repository lookup. The runtime subpath exports onlyserveClaudeSession.EndpointOptions.environmentaccepts an explicit presence label, ornullto omit it without readingCOTAL_ENVIRONMENT; an omitted option preserves process inheritance. The subpath includes CommonJS declarations for TypeScript hosts. Direct stdio launches remain supported and also shut down on input closure; a failure in that teardown exits with code 1. Hosted teardown releases its input listeners, handles input EOF and transport closure, refuses input that ends during startup, and reports teardown failures without an unhandled rejection in the host. A pending broker dial that fails after shutdown begins no longer makes close fail or strands local inbox custody. Shutdown still waits for pending start and reconnect work, proves every owned connection closed, and propagates connection-close failures. connectOrThrowandconnectUserControlOrThrownow throw a user-auth mesh's login and exchange refusals (not logged in, auth service down, actor not granted) as aConnectRefusalcarrying the provider's sentence.connectOrThrowused to print that sentence and exit the process, so the console'sdelchanon a user mesh with no login on the machine ended the console instead of showing the refusal on its status line.connectOrExitandconnectUserControlOrExitstill print the same sentence and exit 1.- Launch the per-session MCP server with
--optimize-for-size --max-semi-space-size=1to cut its memory footprint. cotal_statuswith an activity and no status now changes only the activity. It used to read the current status when the tool ran and write it back behind any status write still queued, so a pendingwaitingwas published asworkingwith its condition cleared, and a pending turn-endidleleft the seat readingworking.- A Jcode seat now passes its pre-join readiness proof when Jcode calls
cotal_orientationthrough its deferredmcp_calltool. The proof matched only the completed tool's name, which ismcp_callon that path, so both readiness turns missed it and the seat exited without joining. The host now reads the call's streamed arguments and counts anmcp_callonly when it names servercotaland toolcotal_orientation, and only for themcp_callcompletion of that same call: a completion under another name, or a later call that reuses its id, does not count. An orientation call that fails or returns an MCP error result no longer counts on either path. - On OpenCode 2.x, a peer batch is acked only by the end of an execution that started after the batch was submitted. An end observed while idle, a replay of one, or an end positioned before the running execution started (even after a late copy of an earlier start) no longer acks a newly submitted batch, and a failed prompt submission no longer lets a second batch into an execution that is still running.
- The OpenCode launcher now stops its server on SIGINT or SIGTERM from the moment it starts it. The handler used to be installed only after the plugin's session handshake, so a graceful stop during the boot, which can take a minute on a cold server, ended the launcher and left the server running on the agent's database, with a
serve.pidrecord that refused every later launch of that name until the server was killed by hand. One handler now stops the server and, once it runs, the TUI. - The OpenCode launcher now records each server in a file of its own,
serve.<token>.pidin the agent's directory, and removes only that file when the server exits. Every launch of a name used to share oneserve.pid, and the launcher's exit handler removed it unconditionally, so a handler that ran after the next launch had started its server removed that server's record, and the launch after that started a second server on the same database. A launch now checks every record in the directory, including aserve.pidleft by an earlier version, refuses while any names a running server, and removes the records of servers that are gone. - The OpenCode 2.x adapter no longer starts a turn once its teardown has begun. A message handled after the disposer started, or a drive waiting on session creation when it started, used to be submitted to OpenCode as a new turn whose batch was never acked because the seat was going away.
drivenow refuses on entry and again after the session await, as the 1.x adapter does. cotal up --user-auth --idp <url>on a space that already pins an IdP now compares the normalized URL with the pin. Re-running the command that created the pin with a trailing slash was refused as a re-pointed IdP that "would re-key every derived owner", although both spellings name the same IdP. A malformed later value now gets the same URL refusal as a first enable, and a different IdP is still refused.- The manager-service authority request now refuses a redirect, as the other manager-authority requests already did. Before this, a 307 or 308 from the pinned endpoint re-sent the login proof to the address it named and returned that host's answer as the manager's authority material. All remote manager-authority requests now go through one endpoint lookup and one request path, so the redirect refusal and the refusal messages are the same for each of them.
cotal up --detachandcotal up -fnow exit 1 when the control plane does not come up on a first boot. Both printed! control plane degraded: ...and then exited 0, so a script or unit read success over a mesh with no manager or delivery daemon, while a refresh over the same failure already exited 1.cotal up -fandcotal spawn -fnow check--serveragainst the rules a manifest'sbroker.serversalready follows. A--serverURL with embedded credentials used to pass:up -f --dry-runprinted it whole in the plan, andspawn -fdialed it and printed it in its reach error. It is now refused with--server entry 1 must not embed credentials, a message that does not repeat the value. An invalid--serverURL is refused the same way, and so is a value that names no URL:--server ""used to fall back to the default broker, and a blank or comma-only--serverorbroker.serversfailed with a bareInvalid URL. Both now getnames no server URL.- A bare re-run of
cotal upnow finds this folder's own mesh when its first boot ran on an auto-selected port. The re-run started from the default URL, missed the record, picked another free port, and was refused withspace "<space>" is already in use by a mesh at <url>, so a refresh or repair needed--serverby hand. With no--server,cotal upnow starts from the URL this root recorded for the space, and--hostkeeps that URL's port. cotal updateno longer refuses its running-manager continuity check when the selected mesh is one this machine runs and it is stopped. A mesh selected with--spaceor by running inside its project, where nocotal superviseprocess on this machine may be serving that space and whose recorded broker address refuses the connection because nothing listens there, has no running manager to preserve, so the update now reconciles the connectors and extensions. This covers a local user-auth mesh too, which used to refuse on its stopped auth service first. Before this,cotal downfollowed bycotal update, the only way past alegacymanager verdict, refused with "no mesh running at ... runcotal upthere to restart" and left every extension at the old version. Anything short of that proof still refuses: a mesh registered withcotal meshes add, a--serveroverride, acotal superviseprocess still running from any folder whose command line names that space or no space, or an address where anything accepts the connection or the dial does not finish in time.- A cancelled
turn,askor escalation whose relay withdrawal is refused for a reason a retry cannot change now fails its step at once with that refusal's code. Before this, every refusal was retried silently every two seconds until the relay's deadline, so a cancelled step against a manager that serves nocancel(not-found), or an accepting manager with no such relay pending (failed-precondition), stayed in its scope for the step's whole timeout. Onlyunavailableanddeadline-exceededare still retried until the deadline. A withdrawal the accepting manager refuses is now thrown as anEpEnvelopeErrorcarrying its code.
What's Changed
- fix(connector-opencode): stop the serve on SIGINT or SIGTERM during the boot by @davidfarah2003 in #3881
- fix(workspace): throw user-auth connect refusals from connectOrThrow by @davidfarah2003 in #3883
- fix(runtime): fail a cancelled step at once when its relay withdrawal is refused for good by @davidfarah2003 in #3884
- fix(auth): refuse redirects on the manager-service authority request by @davidfarah2003 in #3891
- fix(cli): exit 1 when a first up boot's control plane does not come up by @davidfarah2003 in #3893
- fix(auth): compare a later --idp with the IdP pin after normalizing it by @davidfarah2003 in #3895
- fix(cli): check --server on up -f and spawn -f against the broker.servers rules by @davidfarah2003 in #3896
- fix(connector-opencode): record each serve at a path of its own by @davidfarah2003 in #3897
- fix(cli): let update reconcile when the selected mesh is stopped by @davidfarah2003 in #3899
- fix(connector-core): keep an activity-only cotal_status off the status by @davidfarah2003 in #3908
- fix(connector-jcode): prove readiness on a deferred mcp_call orientation by @davidfarah2003 in #3909
- fix(cli): start a bare cotal up re-run from the URL its mesh recorded by @davidfarah2003 in #3910
- fix(connector-opencode): refuse a 2.x drive once teardown has begun by @davidfarah2003 in #3911
- fix(connector-opencode): settle a 2.x batch only from the execution that carried it by @davidfarah2003 in #3912
- feat(core): define delegated recovery contracts by @davidfarah2003 in #3913
- perf(connector-claude-code): launch the MCP server with memory-saving V8 flags by @caffeinum in #2403
- fix(core): validate run admission with the canonical space grammar by @davidfarah2003 in #3919
- feat(connector-claude-code): expose the managed session server by @davidfarah2003 in #3921
Full Changelog: v0.81.1...v0.82.0