Skip to content

The control surface

Concept (informative) · For: operators and client authors who want to know how the manager and other daemons are driven · Normative: SPEC §13

Cotal once had a privileged control rail: a fixed set of named service tiers (self / manager / admin / delivery) on their own ctl.* subjects, with the manager as a special case the broker recognised by name. That rail is gone. Everything that serves structured commands now, the manager, the delivery daemon, a wrapped MCP server, a third-party service, is an ordinary endpoint: a daemon that registers a service identity, publishes its contracts, and answers describe. manager is an endpoint name like any other; no subject, envelope, or grant in this surface knows it specially. The manager is a service on the mesh, not an authority over it: it holds only the capability rows its callers grant it, and serves over a scoped credential.

One kind, ep, carries every request under a mode token that says where the request routes, never which verb it is (the verb rides the envelope): one (queue-group anycast, one and only one class member), all (scatter, every instance), and inst (one instance by its stable address). Replies come back on a reply rail keyed to the serving instance and its epoch. Around these sit the sibling planes the composites use: per-goal events, timers, sessions, and the journal that holds durable facts. Every request carries the caller as three forge-locked tokens, owner, actor, and lifecycle uid, plus an unguessable nonce, so the broker polices who is calling in the subject grammar itself. See SPEC §13.2 for the grammar and §13.5 for the verbs (call, cast, watch, claim, scatter).

A principal owner.actor is a reusable routing alias: a despawn frees the actor name and a later spawn may legitimately reuse it, so the alias alone is never authority. Two further coordinates make an identity durable: a lifecycle uid, an unguessable, never-reused id for one managed lifecycle under a principal, and a process epoch, the fenced ownership epoch of the process currently animating it, advanced on every restart or takeover. At most one live epoch owns an identity, and a superseded epoch must stop serving. Durables and credentials key on the lifecycle uid, not the reusable name, which is what lets a supervised restart recover the same lifecycle instead of minting a new one. See SPEC §13.1 and identity & auth.

No client has compile-time knowledge of any endpoint’s commands. cotal describe <endpoint> resolves a registered endpoint’s command set off the wire: the reserved describe command answers the registered contract digests, the schemas are fetched from the space’s content-addressed contract store, recompiled, and verified against those digests. Each command prints with its capability class and targeting shape. cotal invoke <endpoint> <command> --args '<json>' then calls one command by name, validating the arguments as they will be sent (JSON drops a key whose value is undefined) against the fetched input schema before publish. A refusal at that check means nothing was sent, and it is marked not-executed. An endpoint that refuses a request before running the command states not-executed in the reply’s error.outcome too, for example on a wrong envelope version, sender, contract digest or target mode, or a body that does not parse. A refusal the command itself raises carries only the outcome it states. A refusal that does not serialize comes back as internal, and one too large to publish as resource-exhausted, and both keep that outcome. A signed-in user invokes the same surface through their bearer, and the broker enforces each command’s existing capability grant. A manager alias supplied through --name resolves through its name-keyed inspect command, so an authorized targeted call does not need the manager-wide ps enumeration grant. Every built-in manager command uses this same trust chain, so there is nothing the built-ins can reach that a described contract cannot. The registered auth endpoint is describable the same way manager is: cotal describe auth lists retire-lifecycle and its exact-mode target shape. See SPEC §13.7 and cli.md.

The manager’s resolve-cwd command is in the manager.spawn capability class. It accepts an absolute path on that manager’s host and returns its canonical directory plus the host name. It refuses a relative, missing or non-directory path with failed-precondition; it creates nothing. spawn applies the same check at admission, before any credentials or durables are minted.

spawn refuses an empty or whitespace-only value in any of its optional string fields, such as role, agent or identity, with bad-request naming the field. To take the persona file’s value, omit the field.

Manager inspect keeps its successful response as the live managed-agent row. A live hit does not read durable lifecycle state, so a temporary records-store failure cannot break inspection of an agent the manager currently holds.

On a live miss, a static manager point-reads its durable slot row. A name with no slot, or a slot whose phase is retired, remains not-found. A nonterminal slot returns failed-precondition with error.details[].kind = ai.cotal.manager.static-slot-observation. The detail carries the slot’s slotPhase, owner, actor, slotLifecycleUid, cleanupComplete when recorded, and slotRevision. It then carries the separate lifecycle head’s headState, headOp when present, headLifecycleUid, and headRevision. Head fields are absent when provisioning has not written the lifecycle head yet. The error message carries the same diagnostic summary so string-only operator paths do not hide the structured detail.

A slot row records the manager instance that owns it. In a space with more than one manager, the class queue can hand inspect to an instance that does not host the name. When the row names a different instance and is not retired, the miss returns failed-precondition with the same detail plus ownerInstanceId, which names the only manager that can act on it. The message names both instances, so a caller that reads only the string can tell it from not-found. A sibling’s retired row remains not-found. A named cotal_despawn resolves its target through this read and cannot address an instance, so it asks again until the owning instance answers, up to 16 times.

The slot is read before the head. These records do not form one atomic snapshot, so the detail also carries readOrder: ["slot", "head"] and consistency: "ordered-not-atomic". A head can advance between the reads. The issuance gate is not projected because the retirement operation needed for this diagnosis is already recorded on the head, and reading a third record would add another non-atomic edge without changing the per-name result.

If either durable read fails or exceeds its bound, the miss returns unavailable with ai.cotal.manager.static-slot-read-failed rather than claiming the name is absent. That detail names the inspected name, the failed record (slot, head, or slot-or-head when the layer cannot distinguish them), and operation: "read". User-auth managers do not own mgrslot rows, so their inspect misses remain live-map reads.

For Linux custodied seats, retirement requires the runtime’s process-exit evidence before freeing the alias or deleting its credentials and delivery state. Socket loss alone is not proof of exit. The runtime retains the record captured at launch or adoption so a clean custodian exit can unlink its file without losing the recorded boot and process identities. If the file is missing, reaping uses that retained record and the existing kernel identity checks. An unknown reference without either record refuses cleanup. Reused process ids are never signalled on the strength of the old record.

Manager slots (manager.read, untargeted) lists the durable static slot rows this manager owns. Only static managers hold these rows: a user-mode or open manager answers failed-precondition, and a manager whose durable store is not standing answers unavailable. Each row carries the same readOrder and consistency fields inspect uses, because the list is read the same way: torn across rows as well as within each row’s slot/head pair. A retired row is never listed. live reflects the manager’s live roster at render time, not the durable row. A slot row is never deleted, so a row whose latest operation is a DEL or PURGE marker is corruption: the list answers unavailable naming that row, as inspect does for its name.

Long-running commands are actions (SPEC §13.6): the caller submits with a client-generated goalId and a request fingerprint, the endpoint records a durable accept or reject decision, progress rides per-goal events, and the work ends in one terminal outcome (succeeded, failed, cancelled, expired, or uncertain). Spawn is the reference case. Rather than block the caller for up to 30 seconds while an agent comes up, the manager accepts the goal and returns the allocated identity at once:

{
"name": "reviewer_2",
"owner": "u_...", "actor": "reviewer_2", "uid": "...",
"goalId": "...", "fingerprint": "...",
"readinessDeadlineMs": 30000,
"executor": { "lifecycleUid": "...", "epoch": 3 }
}

The uid is the lifecycle the agent runs at. On a participant manager whose host enrolls its agents, the host picks that uid, so the manager accepts the goal only after the host has answered. A host refusal there refuses the spawn, and no goal is bound.

The name is the one actually allocated: a persona-derived collision is auto-numbered (reviewer, then reviewer_2), while a hard-pinned --name that collides with a live agent is refused at accept, before anything is minted. Auto-numbering never hands out a numbered name it has already issued in that manager process, even after the agent holding it is gone, so a collision takes the next number. Only numbering consults that history: a hard-pinned --name, or a persona whose own name is a numbered string, takes that name whenever it is free, and numbering does not skip a string such a spawn held before. The triple plus goalId let the caller follow progress (connector handoff, process launched, presence join) and reconcile later against the exact instance that accepted. Presence within the manager’s default 30-second readiness window, or a connector’s declared bounded window, settles the goal succeeded; an early process exit is failed; the window passing with neither is uncertain, a bounded, durable outcome that a later ps or status read settles against the live roster. uncertain is a real terminal outcome, not an absence and not a silent hang. It carries the diagnosis of whoever owned the deadline: for a launch that names the agent and says to inspect it rather than re-issue, since re-issuing after a launch that in fact succeeded mints a duplicate. A follower keeps the acceptance as the data of any terminal other than succeeded, so cotal_spawn returns an uncertain launch as a pending result instead of an error: it names the allocated agent, its id, and its manager, and tells the calling agent to watch the roster. A committer that supplies no diagnosis falls back to “the success signal did not arrive within the readiness deadline”. The agent’s own eventual state is then observable on its presence record.

The acceptance carries that exact readinessDeadlineMs. A synchronous follower treats its own request deadline as a floor and waits through the accepted readiness budget plus delivery margin, so a connector-specific slow boot cannot be reported as a caller timeout while the manager is still legitimately waiting for its terminal.

A spawn that is refused because a lifecycle barrier already holds the actor (a frozen issuance gate, a retiring alias, a retired uid) is not a wait-timeout. The manager already knows the blocked op (registration / retirement / activation / takeover), the opId holding it, and the remedy when one exists (retry, cotal reconcile-gate). The detail carries headState (active / retiring / retired) only when the refusing site read the lifecycle head, and gateState (frozen / retired) only when it read the issuance gate. A gate frozen by a takeover or a registration says nothing about the head, so that refusal carries gateState=frozen and no headState. Those facts ride error.details[] as kind = ai.cotal.ep.lifecycle-blocked and are also appended to the error string, so a caller that only prints error.message still sees them. The CLI and the connector tools hand a refusal on in one shape, so cotal spawn -f keeps the same code, details, rendered facts and acceptance data as cotal spawn --detach and cotal_spawn. A connector that collapses the refusal to “startup failed (unknown)” or a SPEC 13.6 wait-timeout is hiding a knowable state, not reporting a missing one.

A space can run more than one manager. Each manager persists a stable logical instance id across restarts and advances its process epoch when it comes back, so callers address a specific manager without caring which process currently serves it. A start serves only at the epoch its own registration committed, never at the epoch of a later start of the same instance. On a static or open mesh, an untargeted spawn rides class anycast (any manager may accept, and the acceptance records which one did). cotal spawn <persona> --detach --on <instance> and cotal_spawn(instance: "<instance>") pin one instance by its exact id. A foreground CLI spawn has no manager to pin and refuses the flag. An MCP pin that does not resolve is refused without falling back to class anycast. There are no ordinal aliases and no short forms: wherever a display names an instance you can address, it prints the whole id, because both surfaces take nothing else.

On a user-auth mesh, manager commands obtain a short-lived manager-caller view from the exchange. It authorizes one concrete manager instance using the caller’s current actor grant and the host’s registered service records. Discovery and invocation both use that instance’s inst route. This view grants no registry scan, class queue, or additional command capability. An absent, ambiguous or unauthorized selection refuses before the command is sent.

Managed launches carry COTAL_MANAGER_INSTANCE so their tools address the manager that launched them. Existing unbound sessions can use the exchange’s unique authorized selection without replacing their actor or conversation. The connector uses a separate control connection; the standing message connection and its credential source are unchanged. Accepted spawn goals are followed on that renewing connection, using its existing caller-scoped progress grant, so a long readiness budget does not depend on the short-lived control credential. The follower confirms its progress subscription with the broker before submitting on the separate connection. A caller still checks the resolved instance and epoch, and never retries an ambiguous mutation outcome.

The manager’s goal-result command accepts {goalId} and returns {goalId, result?}. It reads only the authenticated caller’s owner, actor and lifecycle through the manager’s separate trusted goal-writer connection. The caller receives an attributed reply, never a raw JetStream reader grant. Each read is admitted by the connection’s broker-enforced command grant. A live user-auth connection remains bounded by its bearer expiry after revocation; a renewed connection is checked against fresh authority. There is no separate per-read ledger check. An absent result means no terminal is recorded; it does not prove the goal is running or permit another submission. The existing trusted goal-writer’s leader-served EPF read is space-wide at the broker; the handler confines it to this endpoint and caller triple.

The manager’s reserved cancel command accepts {goalId, mode?} and returns {goalId, state}. It is served for a turn the manager relays. The goal is the authenticated caller’s own, so a caller withdraws only a turn it submitted. The turn ends cancelled, its seat is not shown it again, and a later yield of it is answered with that terminal. A goal that already ended is refused failed-precondition with its cached outcome attached, and a goal this manager does not relay is refused without being changed. So is a second cancel that arrives while a first is still ending the turn; a first that fails leaves the turn pending unless something ended it meanwhile. A workflow run sends it for the turn, ask attempt or escalation of a branch it cancelled.

A followed mutation requires a manager whose attributed describe includes goal-result. Update the manager, issuer and client together before using that recovery path. Reloading an issuer alone cannot change an already-running participant manager. Recovery re-resolves the accepting instance’s epoch, preserves the caller lifecycle and validates the result against the accepted goal and any acceptance fingerprint. Stopping the caller ends its observation, not the already accepted goal.

A followed call resolves the endpoint within its deadline before the submission starts, so a refused or unanswered describe surfaces as its own error. A describe or command publish that the broker refuses reports not-executed. Cancellation before submission reports not-executed. Once submission starts, cancellation or a lost reply reports an unknown outcome unless an attributed refusal proves otherwise. A received refusal remains a refusal even when stop races it. Local failures do not invent responder identities. The follower owns its subscription, timers and read cancellation signal. Reconciliation begins before the wait deadline, and late read completions cannot settle an expired observation. Its read callback receives the accepting caller triple, remaining budget and abort signal; borrowed bearer commands and control connections use that signal. An in-flight dial that finishes after cancellation closes without publishing. A local reply-subscription failure prevents publication and is observed by the same request promise, including when the transport is closing or draining. Request cancellation does not revoke or resubmit the accepted operation.

“Only one manager per space” is not the current invariant. A split topology that keeps the broker host manager-free is still a topology choice: cotal up on that host starts a manager you then stop with cotal down manager after ✓ manager up in .cotal/manager.<spaceKey>.log (detach stdout listing manager is pidfile liveness, not a teardown boundary), and cotal supervise --server runs the manager elsewhere (Run a mesh). Extra live managers are addressable, not an error.

The reserved describe bootstrap is the one request the resolver may repeat while waiting: it is read-only, it is re-published under the same request binding, and every attempt stays inside the original deadline. This covers the startup window where Core NATS discards the first request before the manager has subscribed. If the connection closes while the resolver waits, the describe fails cleanly instead of throwing from the retry timer. The resolved command is never repeated by this readiness behavior.

The describe and the contract store reads after it share the resolver’s one deadline, so a slow store read fails the resolve with deadline-exceeded when that deadline expires. Cancelling a resolve settles a store read in flight instead of waiting for it to return.

The resolve and the invoke are separate trips through the same anycast queue, so in a multi-manager space an unpinned call can land on an instance the caller did not resolve. Every call carries the incarnation it resolved against, and a manager that is not that incarnation refuses before running the command, so the failure an operator sees says the command did not run, and re-issuing it cannot duplicate the effect. That is the difference that matters for a mutation: the older behaviour detected the mismatch on the reply, after the manager had already acted, and could only tell you to go and check. --on still matters for reaching a specific manager (ps, stop, attach, spawn --detach), but it is no longer what stands between a split and a duplicated spawn. Against a manager older than this fence the refusal is still after the fact, and its message says so. The re-issue is automatic only when the refusal states not-executed in its outcome field; a refusal that omits the field, or states unknown, is surfaced to the caller instead of repaired, because neither proves the command did not run. The CLI’s manager commands, cotal invoke, the cotal run verbs and the manager row of cotal status re-describe and re-issue an unpinned call after each such refusal, up to 16 times, so a split reaches the operator only when every attempt split. A hosted run’s own manager calls use the same bound. A pinned call is never re-issued. An agent’s own manager tools, such as cotal_spawn and cotal_despawn, re-describe and re-issue with the same bound, including the goal-result read that follows a spawn to its outcome.

An unpinned targeted call, such as cotal_despawn or a hosted run’s turn relay, can also reach a manager that does not host its target, because each manager resolves targets against the agents it runs. That manager refuses with expired and not-executed and says it holds no mapping for the target, and the same re-issue repairs it within the same bound. An agent that no manager hosts still ends in that refusal once the re-issues run out. A pinned call gets the refusal of the instance it named.

A manager whose boot inventory marked every declared connector unavailable does not subscribe spawn or launch on the class one rail. Those commands stay on scatter and on this instance’s inst rail, so a sibling that can launch them can take an unpinned spawn, and a caller that pins this instance with --on still gets a named harness refusal. describe still lists the commands: the instance rail serves them, and describe itself stays on the class rail (SPEC 13.7). An unpinned spawn can therefore bind-fence: describe may land on the skip member while spawn lands on a sibling, the command was not run, and the caller re-issues or pins --on. status reports classSpawn: false when that skip is in effect. A manager that can launch some connectors keeps the class rail. If the queue hands it a harness its inventory marked unavailable, the refusal names --on because the standing serve credential cannot read sibling inventories. Pin the capable instance (the whole id, as ps prints it).

ps and status become a scatter across every registered instance: the caller freezes the expected set from the service registry, invokes each under a shared deadline, and merges the results with per-instance attribution. A non-answering instance is labelled as registered with no answer within the deadline, never silently omitted. See SPEC §13.5 (scatter) and cli.md.

The expected set comes from the registry, which records registration rather than liveness. An instance that crashes never deregisters, so it stays in the set and the gather has nothing left to wait for but an answer that cannot come. It pays the whole deadline, on every scatter, indefinitely. A scatter can therefore be given a per-instance liveness probe: when the broker itself reports that an instance holds no subscription on its own instance rail, the gather stops waiting for it. Only that affirmative report counts. A lapsed presence entry, a probe that timed out, and a probe that failed are all absence of evidence, and treating any of them as death would turn a slow correct answer into a fast wrong one, so they leave the full deadline standing. Nothing about the outcome changes either way: an instance that did not answer is still unreachable, still surfaced, and the scatter is still not complete.

The probe is supplied by the caller, not invented by the scatter. Asking about an instance is a publish on that instance’s rail, and a credential that holds no row for it is refused by the broker asynchronously, while the publish itself returns normally. The probe verb watches for that refusal and raises it as permission-denied naming the rail, so it is never mistaken for a quiet instance, and it never burns the probe budget waiting out a refusal. Only the layer that minted the credential knows which ids it may ask about, so that layer asks about those and no others. cotal ps freezes the class on its first connection, re-mints an instrument pinned only to the frozen ids, and scatters on a second; a refusal the broker raises anyway is printed and the instance’s row says the probe was refused, which is a fact about the credential, not about the instance.

This does not help against an instance that is connected but not answering. A hung manager holds its subscriptions, so it is indistinguishable from a slow one, and it still costs the full deadline. That is the correct result, not a gap in the probe.

A probe makes a dead registration cheap to skip; it does not remove it. Removal is the registration’s own exit, and there are two explicit routes to it (SPEC §13.5: a deleted svc spec is the deregistration).

A manager that stops cleanly removes its own registration, so an ordinary shutdown leaves no stale row. The delete is pinned to the registration revision that process wrote. When a successor has registered the same instance since then, the stop logs that and leaves the successor’s registration alone. It refuses that delete while this instance holds the endpoint governance slot at the live issuance-gate generation (a registration still completing its reopen). A leftover slot whose generation is behind that live generation is not in-flight and does not block the stop. A manager that cannot renew or read its lease keeps serving, stays registered, and retries. If another process holds the same instance key, that process has taken the instance over, so this one logs the conflict and exits without deregistering, leaving the successor’s registration alone.

A restart that died mid-registration is a different residue: the issuance gate stays frozen under that op. The successor completes the dead registration on boot when the freeze-holder is affirmatively gone under a complete CONNZ sweep (the same composition as cotal reconcile-gate). A committed spec write is finished under that same freeze; only a definite no-commit abort-reopens and then runs the normal takeover. It does not invent a TTL and it does not start a new freeze over a still-held one.

That residue has a second half, and it is the endpoint governance slot rather than the gate. Every registration takes the endpoint-wide slot before it publishes its spec and holds it until its own gate reopens, which is what serializes registration for the endpoint. An instance that stopped between those two points leaves the slot held with no registration behind it, so the endpoint refuses new registrations while nothing is actually in flight. The slot is stamped with the generation of the gate its holder had frozen when it took it, and a slot is promoted only at that same generation. So once the holder’s gate has reopened past the stamp, the slot can never be promoted by anyone, and the next registration for that endpoint replaces it. That reclaim is part of an ordinary start and needs no operator step.

A slot whose holder’s gate is still at the stamped generation is a registration that is genuinely in flight, and it keeps refusing. The two states read differently only in the holder’s gate coordinate, so reopening that gate is what separates them: the holder’s own restart heals it on boot, and cotal reconcile-gate is the operator’s route when the boot path cannot run. The registration path is the slot’s only writer, and neither repair command writes it. A registration that cannot read the holder’s gate at all refuses, because an unreadable gate does not distinguish the two states either. Each of these refusals carries kind = ai.cotal.ep.foreign-slot-held in error.details[] with the holder’s instance id and the condition that refused: in-flight for a holder gate still at the stamp, or no-seam, unreadable, garbled or behind when the registration could not read that gate or read it below the stamp. A remote manager asks its host to reconcile the holder only on in-flight, the one condition a gate repair can clear.

For the instance that cannot cooperate, an operator names it: cotal deregister-instance --instance <id> (cli.md). It removes the record only on the same evidence cotal ps acts on: the broker reporting nothing subscribed on that instance’s own rail. It refuses if the instance answers a describe, refuses if the probe could not run at all, and refuses if the instance is merely quiet, because a hung process still holds its subscriptions and is therefore not affirmed gone. It also refuses while that instance holds the endpoint governance slot at the live issuance-gate generation (a registration still completing); a leftover slot behind that generation is not in-flight and does not block. Nothing sweeps the registry on an age threshold or on silence. An instance that is deregistered while it is merely wedged re-registers over the tombstone on its next start, which is what makes the operator’s decision a recoverable one.

cotal attach no longer returns a ws://127.0.0.1 URL. It creates a one-use, holder-bound session offer: the manager mints a token bound to the caller, the target lifecycle, its own instance id and epoch, and an expiry, and replies with a session id and expiry only, no URL and no secret in the reply. The CLI redeems the offer over the mesh (a second redeem is refused). On a registered open mesh that redeem is a bare connection, the same path other control commands already use; on a static-auth mesh it is still a session-caller credential minted from the resolved root’s seed. On a user-auth mesh the CLI holds no seed: it exchanges its login and the grant for a session-caller view bearer, and the callout mints the same caller rails with the grant’s expiry. Terminal bytes then stream on core-NATS session subjects scoped to the two parties. Backpressure is a bounded in-flight window with an explicit drop notice, never silent loss; a late attach still repaints the full screen from a replayed terminal snapshot. Close, expiry, target despawn, and a manager restart are distinct, surfaced end states: a restarted manager’s successor refuses the old epoch’s sessions and the client shows “manager restarted; re-attach”.

attach is a stream, so it is the wrong shape for a program that wants to send one line: it holds a session open and expects a terminal at the caller’s end. The input command is the other half. One authorized call writes text into a running seat’s terminal as if it had been typed there, and answers with the seat and the number of bytes delivered.

It exists for harness commands. A line beginning with / (/compact, /clear, /model) is neither chat nor an event: the agent’s own harness handles it, and the keyboard is the only way in. An external control surface that can already read a seat’s turns and talk to it still cannot drive it without this.

The op is targeted, rides the manager.lifecycle capability, and declares authz modes owner and any, the row shape attach and despawn already carry, checked by the same authorization. Enter is appended unless the caller suppresses it, and nothing is echoed back, since the resulting turns already have somewhere to go.

Who may call it is narrower than either of those, and the reasoning is worth stating because the natural assumption is wrong. despawn and attach are granted to anything holding spawn; input is granted only to operator credentials. The tempting argument for treating them alike is that an attach session’s write already reaches the same terminal, so input adds nothing. It does not reach it: an attach yields a signed session offer, and redeeming one needs a per-session credential minted from the space signing seed, which no agent holds. So input would be new authority, and the own-owner rule that bounds despawn covers every seat under an owner rather than only the ones a caller launched. Killing a peer is denial; typing into a peer is control of it. The write therefore sits with the credential that is already the administrative authority for the domain.

Only a runtime that owns the child’s input stream can serve it. The pty runtime does; the external terminal runtimes attach to a process they do not own, and there the command refuses and names the runtime rather than dropping the keystroke. A seat that is not running refuses for its own reason, and the two are distinguishable, so a caller can tell “this will never work” from “not right now”. See cli.md.

There is no broad control credential. A caller holds one capability row per command it is allowed to send, and minting maps each named capability to the request subjects it needs and no others. The manager serves over a scoped serve credential that can answer and reply but cannot, for instance, write another endpoint’s records or forge a goal terminal; the goal-fact writer and the session writer are separate, narrowly scoped credentials the broker fences by subject. Authorization is checked at the serving boundary, and for actions it linearises at acceptance: a spawn refused there mints no reservation and leaves no process. See SPEC §13.9 and identity & auth.

A carried resume transcript never rides the rails. The operator-only transcript-receive command answers whether to upload and hands back a one-time claim for spawn, and the bytes travel through the target instance’s own transfer bucket under two one-shot credentials: a writer the operator mints for that one transcript, and a reader the target instance mints for its own bucket, or that the host issues a remote manager through its transferReader authority operation.

  • Architecture, where the manager and the wire fit in the whole system.
  • CLI, for describe, invoke, spawn, ps, status, attach, and input.
  • SPEC §13, the normative contract.