# Embedding package exports

## Workspace registry liveness

`@cotal-ai/workspace` exports `pruneStaleMeshes()` for a liveness sweep. It keeps every
registration and returns a `MeshSweep` containing only `offline: string[]`; catalog entries
are not probed. The former always-empty `pruned` field is removed.

Call `pruneMesh(space)` only after a credentials, mode, or on-disk space mismatch. It removes
an `up` or pre-origin record and returns whether it was removed. Manual and catalog records
stay registered. The reason argument and `PruneReason` type are removed. Callers that passed
`"gone"` must report the target offline without calling `pruneMesh`; callers that passed
`"mismatch"` omit the argument.

## Node connection signing

Node endpoints and `standaloneConnectOpts` sign NATS authentication challenges with the existing
native Ed25519 signer. Credentials are read on every connection attempt, including reconnects,
and the temporary signer is cleared after each callback. JWT, public-key and signature fields
use the NATS authenticator contract. Browser connections keep the NATS JavaScript implementation.

## User credential authority

`AuthProvider.userCredentials` returns the bearer and sentinel credential. A provider may also
return `authority`, containing the owner and the current `scope`, `allowSubscribe`,
`allowPublish` and `dmHistory` grant that its issuer authorized for that mint. The stock provider
returns this from the exchange response on local and remote user-auth spaces. It does not decode
the bearer to reconstruct access.

The field is optional for provider compatibility. Its absence means the caller has no
authoritative grant answer. A status surface must preserve unknown or unavailable instead of
inferring broad access from a bearer, successful exchange or broker ping.

## Login confirmation

`AuthProvider.confirmLogin` asks the space's IdP whether this machine's cached login still holds.
It mints nothing. It answers `confirmed`, `signed-out` when no login is cached, or `rejected` when
the IdP refused the cached one, and throws on any other failure. `cotal manager start` and
`restart` call it on a user-auth space before they save or launch anything, `cotal up` before it
starts the manager, and a team boot that resumes a stopped stack before any write. Each refuses
the manager `UNSUPPORTED` when the provider does not implement it.

## Compiled service contracts

`serviceContractTable(rows)` returns a frozen `contracts` table. Each command's input/output pair
compiles on first access, is frozen, and is reused on later reads. Listing command names does not
compile validators. Callers cannot replace a command or swap its compiled input/output contracts.
`artifactValues()` still returns the schema roots and closure manifests used at registration.

## Package entry points

Everything below is a real export of a published package, reachable from the package root (each
package publishes `.` via `dist/index.{js,d.ts}` and ships `files: ["dist"]`).
`@cotal-ai/connector-claude-code` also publishes `./mcp`, which hosts managed Claude Code sessions
in one process ([Connect Claude](/docs/connect-claude/#host-sessions-in-one-process)).
`@cotal-ai/core` also publishes `./browser-control` and `./browser-validators-build`
([Browser control](/docs/embedding/#browser-control)). Type-only names are marked; import them with `import type`.

## Endpoint presence metadata

`CotalEndpoint` accepts `environment` as an explicit presence label. Pass `null` to omit the label
without reading `COTAL_ENVIRONMENT`. Omitting the option preserves the process environment default.

Shared connector sessions report `card.meta.host` and `card.meta.cwd` from the connector process
when the session is constructed. They override agent-file values and are advisory display data.
The directory is a startup snapshot, not a model harness's later shell directory. Neither field
changes routing or access, and the connector reads no command-line arguments or environment dump
for these values. A connector whose process can host several sessions passes
`{ withholdProcessCwd: true }` as `MeshAgent`'s third argument and reports each session's directory
with `setCwd` (`CotalEndpoint.setCardCwd`) once the harness supplies it; until then the field is
absent. The reported path is kept byte for byte, whitespace included; an empty string leaves it unchanged. Claude Code sessions do this from their `SessionStart` hook.


### Daemon APIs

**Daemon runners and lifecycle**

| symbol | package | purpose |
|---|---|---|
| `runAuthService(args, store?, options?)` | `@cotal-ai/auth` | boot the auth-service daemon; `store` injects the secret material, and `options` takes the daemon lifecycle hooks or [`interactiveManagerSelection`](/docs/embedding/#interactive-manager-primary). |
| `runDelivery(args, store?, onStarted?)` | `@cotal-ai/delivery` | boot the delivery daemon; `store` injects the scoped `delivery` cred, and `onStarted` receives a `status()`/`close()` handle once it serves. |
| `startAuthService(inputs)` | `@cotal-ai/auth` | start one account-scoped auth-service context and return an `AuthServiceHandle` with the loopback `url`, the per-start `cap`, `readiness`, `drain`, and idempotent `close`. `close` rejects when the context did not release its plane claim: the claim row was no longer its own, or the release write failed. The row then stays held, and the next start reclaims it through the liveness oracle. With the optional `publicFace` input it also serves the public exchange face and carries `publicUrl`. The optional `calloutLimits` input sets the auth callout's deadline, concurrency and slow-line limits ([callout deadlines](/docs/identity-and-auth/#callout-deadlines)). Every full hosted context serves the capability-gated `MANAGED_ACTIVATE_PATH` below, including a separate process with no `platformControl`. With the optional `platformControl` input the handle also has `platformControlAuthority`, the in-process platform control door, `platformControlReadiness`, its read-only readiness read, `observeManagerGate`, the manager gate read a host composing the delegated user intent decisions passes them, and `activateManagedLifecycle`, the same native activation used by the loopback door. With `platformControl.host` it also has `registerHostIncarnation`, which registers the host process's own endpoint instance and returns the incarnation a delegated execution pins, `observeHostGate`, the read of that endpoint's issuance gate, and `awaitHostFence`, which resolves once a later registration or barrier fences an incarnation. `runAuthService` remains the CLI entry. |
| `MANAGED_ACTIVATE_PATH`, `ManagedLifecycleActivationRequest`, `ManagedLifecycleActivationResult` | `@cotal-ai/auth` | `POST /managed-lifecycle/activate` on the full auth service's loopback face. A separately hosted account authority accepts only `{ accountPublicKey, owner, actor, lifecycleUid }` with its per-start `Bearer <cap>`. The account key must equal that context's assigned data account. Success means the exact UID is active and returns the same coordinates plus `activated: true`. The public face and callout-only replicas do not serve it. |
| `PlatformControlAuthorityRequest`, `PlatformControlInnerRequest`, `PlatformControlAuthorityResult`, `PlatformControlAssignment` *(types)* | `@cotal-ai/core` | the closed envelope, its inner request union, its result and the backend's assignment row for `platformControlAuthority`. `platformControlOwner` in `@cotal-ai/auth` derives the `p_` owner the door issues under. |
| `startDeliveryService(inputs)` | `@cotal-ai/delivery` | start one account-scoped delivery instance and return a `HostedServiceHandle` with `readiness`, `drain`, and idempotent `close`. `close` rejects when its lease release does not commit or cannot be confirmed, or when another holder's lease row is still there after it. The process runner remains the CLI entry. |
| `deliveryCredsKey(space, composition)`, `membershipRwCredsKey(space, composition)` | `@cotal-ai/workspace` | build the secret-store keys the delivery cred and the membership feed's rw cred are read/re-signed under. Keys are **per-space**: `space.<hex>/<kind>`. A hosted composition passes `{ injected: true }`. |
| `retireManagerInstanceIdentity(root, space, expected)` | `@cotal-ai/workspace` | remove a persisted manager identity only if its complete instance id and serve identity still match `expected`. Returns `removed` or `absent`; refuses malformed, nonregular, and changed records. `absent` is not proof of ownership or successful teardown. The caller must separately prove stop and retirement ownership before using it. |
| `DELIVERY_CREDS_KIND`, `MEMBERSHIP_RW_CREDS_KIND` | `@cotal-ai/workspace` | the operator-facing KIND names (`delivery.creds`, `membership-rw.creds`) those keys are built from, and what renewal results report. A kind is **not** a key: putting a cred under the bare kind writes the pre-0.4 flat location, which nothing reads. |

### Manager APIs

| symbol | package | purpose |
|---|---|---|
| `Manager`, `ManagerOptions` *(type)* | `@cotal-ai/manager` | construct and run a supervisor in-process; `ManagerOptions.secretStore` injects the one store it reads/writes every secret through. `ManagerOptions.remoteAuthority` is the hosted manager-service authority bundle, including host-owned release, retained-validation, goal-index, and serve-time admin-authorization callbacks. |
| `ManagerOptions.pooled` | `@cotal-ai/manager` | require signerless remote authority and either an explicit non-custodial runtime or `execution: "none"`. A pooled composition must supply the assigned account key and all-duty renewal callback; the CLI's default remains unchanged. A signed-in human's manager gets that material from `managerServiceAuthority`. A platform-run control manager gets it from `AuthServiceHandle.platformControlAuthority` with the shipped `remoteManagerClient` builders, as the [platform control authority](https://github.com/Cotal-AI/Cotal/blob/main/docs/design/platform-pooled-control-authority.md) design describes. |
| `ManagerStatus` *(type)* | `@cotal-ai/manager` | verified status payload, including optional advisory `host` and `version` from the answering Manager. Older payloads may omit them. |
| `ManagerOptions.execution` | `@cotal-ai/manager` | omitted or `"runtime"` keeps runtime execution. Explicit `"none"` accepts a genuine hosting user-auth root, or pooled complete signerless authority, with no `runtime` option. It constructs no Runtime and performs no connector inspection, seat launch or workflow hosting. |
| `createRuntime`, `Runtime` *(type)* | `@cotal-ai/manager` | resolve the spawn backend (pty built in). |
| `liveKvEntries(kv, options?)` / `liveKvEntries(kv, filter, options?)`, `LiveKvEntriesOptions` *(type)* | `@cotal-ai/core` | read live KV entries in one finite scan. Pass `{ signal }` as the second argument or after a key filter to cancel. An interrupted scan throws `IncompleteKvScan`; cancellation throws the signal reason, including during an empty-bucket bind. The scan deletes only its owned consumers, including each one nats.js rebuilt from it, after the broker has answered every create those rebuilds sent. A not-found delete counts as gone, a refused one leaves the consumers to broker inactivity expiry (which also covers a crash), and any other delete failure is thrown, as is a not-found delete of a consumer whose create got no reply from the broker before a timeout or a closed connection. A cleanup failure is thrown only when the scan would otherwise return; the scan's own error, its cancellation reason and `IncompleteKvScan` take precedence. |

`remoteManagerServePrincipal(owner, instanceId)` from `@cotal-ai/core` derives the manager's
serve actor and serializes it through `principalKey`, validating both tokens. Use it when a
host derives the serve principal from an instance id. APIs that already receive a serve actor
serialize that supplied actor with `principalKey(owner, serveActor).key`.


### Pooled renewal authority

The remote manager authority parser accepts `renewStandingBundle` and `renewRunDriver` only with
an assigned account nkey, the current manager process epoch, and a host-authenticated registration
proof. A run renewal also names its active holder, takeover, epoch, fencing token, and the two
existing nkeys. The host must fresh-check those coordinates against its registration gate and run
journal before issuing server-selected profiles. A host without that renewal authorization refuses
the request. Until the host issuer wires the operations and validates them on real connections,
the presence of these types is not an operational pooled renewal guarantee.


### Execution-free control

An execution-free control Manager retains native registration, goal recovery, session-ledger,
renewal and maintenance duties. Its status reports `execution: "none"`, `runtime: "none"`,
`custody: "none"`, no children or connectors, and false `classSpawn`, `runHosting` and
`terminalSessions`. Local NONE uses this existing status schema without a new wire field.
Execution is recorded per instance. An incompatible record, retained seat/turn inventory or an
older unclassified instance refuses boot before recovery. NONE refuses caller-driven writes,
including persona definition, purge, transcript transfer, preservation and resume, and resolves
no model adapter. It starts no transcript receiver or sweep. Autonomous registration, lease,
renewal, session-ledger and goal maintenance still write their native control state.

Select the genuine participant Manager with a host-issued, instance-pinned `manager-caller`
view for workflow and terminal operations. That Manager retains the children, workflow journal
and terminal sessions. The control instance neither adopts roster peers nor proxies user runs.
Missing participant selection or authority refuses. This capability adds no application routing.

### Local control admission

For a genuine local control instance, pass `execution: "none"` without `pooled`, `remoteAuthority`
or `runtime`. Startup requires that space's local signing trust, provider pin and user-mode mesh
record. It keeps the native persisted local instance and serve identity; local-primary selection
uses the existing gate. An existing unclassified identity, including a preclaimed identity with no
execution record, is refused. A NONE record cannot restart as runtime. Retained seat or turn
inventory refuses before recovery. Do not remove identity or capability files to change modes.

The public `cotal supervise --execution none --space <space>` composition supports the same local
mode. It validates arguments before connector seeding, resolves no Runtime, and rejects startup
workload flags and participant registrations. Omitted execution keeps the ordinary PTY behavior.
This does not opt an auth service into local-primary, change scopes or broaden native ps.


## Manager execution modes

Runtime remains the default, but local startup now claims its native identity and execution
record during admission, before later authentication and registration checks. A failed start
can leave those files classified as runtime. Malformed identity or capability files also refuse
earlier. These lifecycle timing changes do not change the instance's identity format or authority.

With `renewStandingBundle` configured, the manager renews all five standing credentials together.
It checks every returned credential for the held nkey and assigned account, test-connects each one,
and adopts them only if the serve epoch has not moved. A refused or failed candidate leaves the
current credentials in place and records the refusal as cleanup debt until a later renewal succeeds.
On shutdown, after the standing context is drained, an expired maintenance executor is renewed
through the existing scoped host operation so deregistration can finish without restarting duties.

Issued-authority references, source coordinates and stores accept nonempty space tokens in
`[A-Za-z0-9_-]`, including underscores. These boundaries reject input that would be rewritten by
the subject-token sanitizer. Endpoint names still use the separate DNS-label grammar.


### Provisioning APIs

**Provisioning and minting** (all `@cotal-ai/core`)

| symbol | purpose |
|---|---|
| `createBrokerAuth(label)` | mint BROKER trust: the operator and system account one nats-server trusts. One per broker, shared by every space on it. |
| `createSpaceAccountAuth(broker, space)` | mint one space's own data account, signed by that broker's operator: the add-a-tenant primitive. |
| `createSpaceAuth(space)` | the one-space convenience: broker trust + one account in a single composed bundle. |
| `setupSpaceStreams({ servers, space, creds })` | create the space's JetStream streams. |
| `ensureDefaultDeliveryClass({ servers, space, creds?, deliveryClass })` | write the space's default delivery class at creation so it is wire-discoverable (SPEC section 4). |
| `serverConfig(broker, spaces, { storeDir, transport, maxFileStore?, maxPayload?, authTimeout?, extraAccounts?, port?, host?, wsPort?, wsHost? })` | render the broker config: one operator, N space accounts. `wsPort` enables an optional WebSocket listener; `wsHost` defaults to loopback. `storeDir` is required, `maxFileStore` caps JetStream file storage in bytes (omitted, nats-server's dynamic default applies), `maxPayload` sets the broker's `max_payload` in bytes (omitted, nats-server's 1 MiB default), `authTimeout` renders `authorization { timeout }` in whole seconds for the auth callout (omitted, no block and nats-server's default), and `extraAccounts` preloads the auth-callout account. |
| `mintCreds(auth, identity, profile, opts?)` | mint a scoped cred for any `Profile`. |
| `mintMembershipObserverCreds`, `mintConnectionEvictorCreds` | mint the membership/eviction scoped creds. |
| `provisionAgent`, `provisionAgentDurables` | create a principal's bind-only durables. |
| `newIdentity`, `stripSpaceAuth` | a fresh nkey identity; a stripped signer bundle (data signing seed only). |
| `Profile`, `CredentialKind`, `MintOpts`, `SpaceAuth` *(types)*, `CREDENTIAL_LIFETIMES` | the profile matrix and cred lifetime policy. |


### Authentication APIs

**Auth building blocks** (all `@cotal-ai/auth`)

| symbol | purpose |
|---|---|
| `createCalloutAuth`, `startAuthCallout` | the NATS auth-callout responder. It requires an awaited `recordIssuance`, which must durably record each success's broker user key before the response; the authority plane's `recordIssuance` is the stock one. |
| `createUserTokenIssuer`, `pinnedJwksResolver` | mint and verify the Cotal user bearer. |
| `createIdpBridge` | exchange a verified IdP JWT for a Cotal bearer (see [the callout contract](/docs/identity-and-auth/#the-idp-callout-contract)). |
| `deriveOwnerToken`, `validateUserToken` | owner derivation; strict bearer validation. |
| `cotalAuthProvider` | the self-registering `auth-provider` extension. |
| `ensureCalloutAuth`/`loadCalloutAuth`, `ensureIssuer`/`loadIssuer`, `ensureOwnerSecret`/`loadOwnerSecret` | read/write the auth secret kinds through a `SecretStore`. Each `ensure*` writes its first value with `create`, so concurrent first calls on one space return the one value the store holds. |
| `PLANE_CLAIM_REFUSED`, `planeClaimRefusal`, `PlaneClaimRefusal` *(type)* | every plane-claim refusal carries a `PLANE_CLAIM_REFUSED` detail, and `planeClaimRefusal(err)` reads its `reason`: `corrupt`, `live-peer`, `unknown`, `concurrent`, `fenced`, `released` or `lost`. Only `unknown`, an inconclusive liveness observation, is coded `unavailable`. A host can retry contention and stop on a corrupt row without matching message text. |

`startAuthCallout` processes up to 32 connections concurrently. Its hooks must support overlapping
calls for different connections. A slow authority check or recorder occupies one slot; other
connections can still authenticate. Each response waits for that connection's authority checks,
durable issuance and final expiry check. Work beyond the bound waits and can still reach the
broker's authorization deadline. The returned `done` waits for admitted hooks when the subscription
ends and rejects an unexpected worker failure after those hooks settle.


### Composition APIs

**Seams and the wire** (all `@cotal-ai/core` unless noted)

| symbol | purpose |
|---|---|
| `SecretStore` *(type)* | the durable hosted-secret seam (get/put/create/delete). `create` writes only while the key is absent and reports whether it did, so it must be one atomic step in the backend. `get()` returns raw seeds/keys into process memory, so it is a blob seam, not HSM/KMS signing. |
| `FsSecretStore`, `workspaceSecretStore(root)` | the filesystem default. **These live in `@cotal-ai/workspace`, not core.** |
| `AuthProvider` *(type)*, `Connector` *(type)*, `Runtime` *(type)*, `Command` *(type)* | the extension contracts; implementations self-register on import. |
| `registry` | the shared registry a composition root pulls surfaces into. |
| `CotalEndpoint`, subjects, message types | the wire client and shapes. |
| `ParsedArgs` *(type)* | the shape the daemon runners take (see below). |

For a Linux Unix-socket adapter, `peerCredentials(socket)` from `@cotal-ai/seat` returns
kernel-observed peer `pid`, `uid` and `gid`. Compare these against the host's authorization
policy; request-supplied identity and process liveness do not replace that policy or a
lifecycle fence. The helper starts no custodian and refuses unsupported platforms or a
missing native helper.

The runners take a CLI-shaped `ParsedArgs`, not a typed options object, so a host fabricates one:

```ts
const args: ParsedArgs = { values: { space, server, port: "0" }, positionals: [], raw: [] };
```

## Long-lived endpoint credentials

`EndpointOptions.bearer` accepts either a string or a function, and the difference is not stylistic.
A string is minted once, so when it expires (which it will: callout bearers live minutes) the
endpoint has nothing to renew with. It will not present the dead token to the broker, since that is
a guaranteed denial that still costs a full auth-callout round trip. It refuses to reconnect, emits
`warning` saying which case it is in, and retries on a widening backoff until the process
re-authenticates and rebuilds it. Retry notices use `warning` rather than `error` because Node
rethrows an unhandled `error` event and would kill a host the endpoint is still trying to recover.

When the broker refuses a bearer at connect, the `warning` says the broker refused this endpoint's
bearer and that the auth service logs why, because nats-server passes the client no reason. The
endpoint then retries on its capped backoff. Each wait is a random point in the upper half of its
step, so endpoints refused together, after a broker restart or by an auth limit, do not retry
together. A bearer source that throws an error with a numeric `retryAfterSeconds` is called again
when those seconds have passed, not before, and a reconnect inside that wait dials on the bearer it
holds. The auth provider's rate-limited exchange throws that way, and `agentBearerCommand` prints
`retry-after <seconds>` for it.

Pass a **function** for anything that outlives one bearer. That is a renewal source: it is called
ahead of each expiry and again whenever a reconnect finds the cached bearer dead, and it requires
explicit `card.owner` and `card.actor`. The first-party surfaces already do this
(`UserViewAuth.source`, the connector's `agentBearerCommand`). A string bearer is for a short
one-shot connection.

A `MeshAgent` a host runs in its own process takes the same kind of source. Pass
`userAuth.bearer`, a function returning a fresh bearer, instead of `userAuth.bearerCmd`, the argv a
launched seat execs. Such an agent has no manager-call bearer, so its spawn, despawn, persona and
run calls return a refusal without reaching a manager.

### Endpoint event handling

Long-lived hosts must also subscribe to the endpoint's `warning` event. It carries conditions the
endpoint is surviving, including failed credential renewal, reconnect retries, its own DM inbox
missing from the broker while the connection is up, a durable leave
it keeps retrying after the broker refuses a durable channel's live subscription, and a channel
registry entry that does not decode to a valid config, such as a raw put of an unknown delivery
class or of `null` on the defaults key. The endpoint drops that entry from its cache and applies the
default policy until a valid entry is written. The DM inbox warning comes once, after the broker
has reported the inbox missing twice. The endpoint does not recreate the inbox. It keeps checking
and receives again if its provisioner creates the inbox again. A host may choose
to ignore warnings for a one-shot endpoint whose awaited operation owns the verdict, but that choice
should be explicit. An unhandled warning is nonfatal and silent.

The `error` event carries a fault the endpoint cannot return from a call, such as a refused
subscription or a refused publish that no request was waiting on. Attach a listener before `start()`,
since Node throws on an unhandled `error`. A denial the broker returns to a request, such as an
observer's read of the DM stream, reaches only that call, which decides what it means, and is not
emitted again as an `error`.

## Native transport liveness

`CotalEndpoint` accepts `transportPingIntervalMs` and `transportMaxPingOut` together
as positive safe integers. Omission uses a 10-second interval and two outstanding pings. Connector seats and CLI endpoints use these defaults, including loopback proxy connections. A silent link normally disconnects within about 30 seconds, subject to scheduling. The delivery daemon retains its 2.5-second override. Native PING/PONG uses the
resident socket without another authenticated probe connection. A stale connection
emits a transport disconnect before reconnect attempts. The
[delivery daemon's connection handling](/docs/delivery-daemon/#where-it-runs) explains how
that event affects the service. The option validation and NATS mapping are in
[`endpoint.ts`](https://github.com/Cotal-AI/Cotal/blob/main/packages/core/src/endpoint.ts).

`transportConnectTimeoutMs` is a positive integer bounding the first connection attempt. Omission keeps the transport's 20-second default. Transport liveness does not prove endpoint readiness, presence health, or a send outcome.

## Finite KV scans

`liveKvEntries(kv, options?)` and `liveKvEntries(kv, filter, options?)` read one finite scan of live entries.
A `{ signal }` argument can appear second or after a key filter. The filter may be a string, an array
of strings, or `undefined`. `liveKvValues(kv, decode, options?)` and
`liveKvValues(kv, decode, filter, options?)` provide the same forms with decoded results.
Passing options in both slots is a TypeScript error and rejects with `TypeError` at runtime before
scanning. Combine the signal and callbacks into one options object.
An interrupted scan throws `IncompleteKvScan`.
Cancellation throws the signal's reason, including during a bind to an empty bucket.
The ordered consumer's pending count distinguishes an empty completed scan from an interrupted read.
Completion requires a zero pending count at bind or a delivered message reporting zero pending.
Successful empty and nonempty results await cleanup before returning.
Cancellation still wins while cleanup is pending, before a result returns.

Cleanup deletes only the scan's owned consumers, including consumers nats.js rebuilt from them.
It waits for broker replies to every create sent by those rebuilds.
A confirmed not-found delete counts as gone.
A refused delete leaves the consumer to broker inactivity expiry, which also covers a crash.
Other delete failures are thrown.
A not-found delete also fails when the broker never answered that consumer's create before a timeout or closed connection.

A cleanup error replaces only an otherwise successful result.
The scan's own error, cancellation reason, or `IncompleteKvScan` takes precedence.

## Related contracts

### Runtime execution

Manager execution mode determines whether a host can launch agents and workflows. See [the detailed contract](/docs/embedding-exports/#manager-execution-modes).
