Spaces (TypeScript)
The @trycua/cua/spaces helpers: threads, events, teleport approvals and typed errors.
The @trycua/cua/spaces helpers: threads, events, teleport approvals and typed errors.
Import from @trycua/cua/spaces. This page covers the hand-written TypeScript layer; the generated native binding (sandboxes, guest, fleet, spaces objects) is documented per object in the Cua SDK reference.
One remote cursor's interpolation buffer.
new CursorSmoother(delayMs?): CursorSmoother;| Parameter | Type | Default value |
|---|---|---|
delayMs | number | STREAM_DELAY_MS |
alpha(localMs): number;Opacity at localMs.
| Parameter | Type |
|---|---|
localMs | number |
number
position(localMs): [number, number] | undefined;The position to draw at localMs, or undefined before any sample.
| Parameter | Type |
|---|---|
localMs | number |
[number, number] | undefined
push(
serverMs,
localMs,
x,
y,
target
): void;Adds a sample (serverMs 0 = unknown: the local time is used). Out-of-order samples are dropped.
| Parameter | Type |
|---|---|
serverMs | number |
localMs | number |
x | number |
y | number |
target | string |
void
reset(): void;Forgets every sample (the next one snaps).
void
A group chat. The 2..6 bound holds for every instance: construction and membership changes throw.
new GroupChat(
title,
members,
options?
): GroupChat;| Parameter | Type |
|---|---|
title | string |
members | readonly string[] |
options | { createdAt?: Date; id?: string; } |
options.createdAt? | Date |
options.id? | string |
| Property | Modifier | Type | Default value |
|---|---|---|---|
createdAt | readonly | string | undefined |
id | readonly | string | undefined |
messages | public | GroupMessage[] | [] |
title | public | string | undefined |
get isAtFloor(): boolean;boolean
get isFull(): boolean;boolean
get memberIDs(): readonly string[];Bot ids in join order. The human is implicit.
readonly string[]
get membershipLabel(): string;4 of 6 bots.
string
get remainingSeats(): number;number
add(botID): void;| Parameter | Type |
|---|---|
botID | string |
void
remove(botID): void;| Parameter | Type |
|---|---|
botID | string |
void
A membership rule was broken. The message says which number.
Errornew GroupChatError(code, message): GroupChatError;| Parameter | Type |
|---|---|
code | GroupChatErrorCode |
message | string |
Error.constructor| Property | Modifier | Type |
|---|---|---|
code | readonly | GroupChatErrorCode |
static alreadyAMember(id): GroupChatError;| Parameter | Type |
|---|---|
id | string |
static atFloor(): GroupChatError;static full(): GroupChatError;static notAMember(id): GroupChatError;| Parameter | Type |
|---|---|
id | string |
static tooFewBots(have): GroupChatError;| Parameter | Type |
|---|---|
have | number |
static tooManyBots(have): GroupChatError;| Parameter | Type |
|---|---|
have | number |
static unknownChat(id): GroupChatError;| Parameter | Type |
|---|---|
id | string |
Group chats: membership, fan-out, and the merged transcript.
new GroupChatStore(messenger?): GroupChatStore;| Parameter | Type |
|---|---|
messenger? | GroupMessenger |
| Property | Modifier | Type | Default value | Description |
|---|---|---|---|---|
chats | public | GroupChat[] | [] | - |
lastError | public | string | undefined | undefined | The last membership complaint, cleared on the next success. |
working | readonly | Map<string, Set<string>> | undefined | Bots producing output right now, per chat. |
add(botID, chatID): void;| Parameter | Type |
|---|---|
botID | string |
chatID | string |
void
attach(messenger): void;| Parameter | Type |
|---|---|
messenger | GroupMessenger |
void
chat(id): GroupChat | undefined;| Parameter | Type |
|---|---|
id | string |
GroupChat | undefined
collectReplies(chatID): Promise<GroupMessage[]>;Folds what members said since the last poll into the transcript, attributed.
| Parameter | Type |
|---|---|
chatID | string |
Promise<GroupMessage[]>
create(title, members): GroupChat;| Parameter | Type |
|---|---|
title | string |
members | readonly string[] |
delete(id): void;| Parameter | Type |
|---|---|
id | string |
void
displayName(botID): string;| Parameter | Type |
|---|---|
botID | string |
string
react(emoji, chatID): void;Attaches a reaction to the last line.
| Parameter | Type |
|---|---|
emoji | string |
chatID | string |
void
refreshWorking(chatID): void;| Parameter | Type |
|---|---|
chatID | string |
void
remove(botID, chatID): void;| Parameter | Type |
|---|---|
botID | string |
chatID | string |
void
send(text, chatID): Promise<GroupDelivery[]>;Sends one message to every member; returns each member's delivery.
| Parameter | Type |
|---|---|
text | string |
chatID | string |
Promise<GroupDelivery[]>
subscribe(fn): () => void;| Parameter | Type |
|---|---|
fn | () => void |
() => void
workingBots(chatID): string[];| Parameter | Type |
|---|---|
chatID | string |
string[]
Who is in a Space's presence and where their cursors are. Pure state.
new PresenceRoster(): PresenceRoster;get entries(): PresenceEntry[];Everyone, me first, then in join order.
get others(): PresenceEntry[];Everyone but me: the cursors to draw (mine is the real pointer).
apply(e): boolean;Folds one event in. Returns whether anything changed.
| Parameter | Type |
|---|---|
e | PresenceEvent |
boolean
colorOf(principalId): string;The color an agent shows as, for its avatar and its cursor alike: the color the server assigned once it is present (a requested color is kept unless another participant already holds it), else its stable presenceColor. Keyed by the id it joined with.
| Parameter | Type |
|---|---|
principalId | string |
string
static from(me, members?): PresenceRoster;A roster seeded from a fresh session: me and the members at join.
| Parameter | Type | Default value |
|---|---|---|
me | PresenceParticipant | undefined |
members | readonly PresenceMember[] | [] |
get(participantId): PresenceEntry | undefined;| Parameter | Type |
|---|---|
participantId | string |
PresenceEntry | undefined
Who is present and what to draw for each, folded from presence events.
new PresenceView(me, delayMs?): PresenceView;A view for me (the caller's participant id).
| Parameter | Type | Default value |
|---|---|---|
me | string | undefined |
delayMs | number | STREAM_DELAY_MS |
apply(e, localMs): boolean;Folds one event in at localMs. Returns whether anything changed.
| Parameter | Type |
|---|---|
e | PresenceEvent |
localMs | number |
boolean
drawables(localMs, pointer?): PresenceDrawable[];Everything to draw at localMs: remote cursors interpolated and faded,
and your own cursor at pointer (normalized; undefined when the pointer
is not over the surface) with its server shape. Also applies expire.
| Parameter | Type |
|---|---|
localMs | number |
pointer? | { x: number; y: number; } |
pointer.x? | number |
pointer.y? | number |
expire(localMs): string[];Drops everyone but the caller when heartbeats stopped for 3 intervals. Returns the removed ids.
| Parameter | Type |
|---|---|
localMs | number |
string[]
static from(
me,
members?,
delayMs?,
localMs?
): PresenceView;A view seeded from a fresh session: me and the members at join.
| Parameter | Type | Default value |
|---|---|---|
me | PresenceParticipant | undefined |
members | readonly PresenceMember[] | [] |
delayMs | number | STREAM_DELAY_MS |
localMs | number | ... |
participant(id): PresenceParticipant | undefined;| Parameter | Type |
|---|---|
id | string |
PresenceParticipant | undefined
participantIds(): string[];Participant ids, the caller first, then in join order.
string[]
setHeartbeatIntervalMs(ms): void;The expected heartbeat interval (default 5 s).
| Parameter | Type |
|---|---|
ms | number |
void
shapeOf(id): CursorShapeName | undefined;A participant's current shape (the caller's included).
| Parameter | Type |
|---|---|
id | string |
CursorShapeName | undefined
upsert(participant): void;Adds or updates a participant.
| Parameter | Type |
|---|---|
participant | PresenceParticipant |
void
Routines: storage, editing, and the clock that fires them.
new RoutineStore(storage, runner?): RoutineStore;| Parameter | Type |
|---|---|
storage | RoutineStorage |
runner? | RoutineRunner |
| Property | Modifier | Type | Default value | Description |
|---|---|---|---|---|
log | public | FiringRecord[] | [] | What the scheduler did, newest first (at most 50). |
routines | public | Routine[] | [] | - |
storage | readonly | RoutineStorage | undefined | - |
get isSchedulerRunning(): boolean;boolean
attach(runner): void;| Parameter | Type |
|---|---|
runner | RoutineRunner |
void
create(input): Routine;| Parameter | Type |
|---|---|
input | { botID: string; enabled?: boolean; now?: Date; prompt: string; schedule: RoutineSchedule; title: string; } |
input.botID | string |
input.enabled? | boolean |
input.now? | Date |
input.prompt | string |
input.schedule | RoutineSchedule |
input.title | string |
delete(id): void;| Parameter | Type |
|---|---|
id | string |
void
due(now): Routine[];| Parameter | Type |
|---|---|
now | Date |
Routine[]
fire(routine, now?): Promise<FiringRecord>;Fires one routine now, whatever the clock says ("Run now", and the scheduler's step).
| Parameter | Type |
|---|---|
routine | Routine |
now | Date |
Promise<FiringRecord>
load(): void;Reads the list back. A corrupt file starts empty, with a logged complaint.
void
routine(id): Routine | undefined;| Parameter | Type |
|---|---|
id | string |
Routine | undefined
routinesFor(botID): Routine[];| Parameter | Type |
|---|---|
botID | string |
Routine[]
save(): boolean;boolean
setEnabled(id, enabled): void;Enable or disable without deleting; the firing history is kept.
| Parameter | Type |
|---|---|
id | string |
enabled | boolean |
void
startScheduler(intervalMs?, clock?): void;One loop for every routine. Ticks never overlap.
| Parameter | Type | Default value |
|---|---|---|
intervalMs | number | 15_000 |
clock | () => Date | ... |
void
stopScheduler(): void;void
subscribe(fn): () => void;Called after every change. Returns an unsubscribe.
| Parameter | Type |
|---|---|
fn | () => void |
() => void
tick(now?): Promise<FiringRecord[]>;Evaluates the clock once and fires whatever is due; returns what it fired.
| Parameter | Type |
|---|---|
now | Date |
Promise<FiringRecord[]>
update(routine): void;| Parameter | Type |
|---|---|
routine | Routine |
void
Errornew SpacesError(
code,
message,
options?
): SpacesError;| Parameter | Type |
|---|---|
code | SpacesErrorCode |
message | string |
options | SpacesErrorOptions |
Error.constructor| Property | Modifier | Type |
|---|---|---|
code | readonly | SpacesErrorCode |
detail | readonly | string | undefined |
status | readonly | number | undefined |
target | readonly | string | undefined |
static auth(message, options?): SpacesError;| Parameter | Type |
|---|---|
message | string |
options? | SpacesErrorOptions |
static protocol(message, options?): SpacesError;| Parameter | Type |
|---|---|
message | string |
options? | SpacesErrorOptions |
static timeout(message, options?): SpacesError;| Parameter | Type |
|---|---|
message | string |
options? | SpacesErrorOptions |
static usage(message, options?): SpacesError;| Parameter | Type |
|---|---|
message | string |
options? | SpacesErrorOptions |
Serializes turns per Space, shared by every thread on that Space, so two bots on one Space take the Space in turn instead of fighting over it.
new SpaceTurnLock(): SpaceTurnLock;get active(): string | null;The turn currently holding the Space, or null.
string | null
enqueue(turnId): object;Queues turnId now (call order, not scheduling order).
| Parameter | Type |
|---|---|
turnId | string |
object
| Name | Type |
|---|---|
acquired | Promise<() => void> |
waitingBehind | string | null |
An agent run in a Space.
new Thread(init): Thread;| Parameter | Type |
|---|---|
init | { agent: AgentId; deleteOnClose: boolean; isolation: "space" | "none"; label?: string; notes?: string[]; runId: string; space: SpaceLike; spaces: SpacesLike; } |
init.agent | AgentId |
init.deleteOnClose | boolean |
init.isolation | "space" | "none" |
init.label? | string |
init.notes? | string[] |
init.runId | string |
init.space | SpaceLike |
init.spaces | SpacesLike |
| Property | Modifier | Type | Description |
|---|---|---|---|
agent | readonly | AgentId | - |
isolation | readonly | "space" | "none" | space when the thread has its Space to itself, none when shared. |
label | readonly | string | undefined | - |
notes | readonly | string[] | Preparation steps the runtime could not complete, named. |
runId | readonly | string | - |
space | readonly | SpaceLike | - |
get id(): string;string
close(): Promise<void>;Stops the run and deletes a dedicated Space created for it.
Promise<void>
events(options?): AsyncGenerator<ThreadEvent>;Polls the run and yields derived events: text, files, links, approval
prompts, and a state event on every status change. Stops once the run
settles or after maxPolls (bounded).
| Parameter | Type |
|---|---|
options | EventOptions |
AsyncGenerator<ThreadEvent>
send(text, options?): Promise<Turn>;Sends a follow-up. Turns on one Space are serialized. A run whose
published acceptsMessage is false (a turn is running, or it could not
be read) refuses unless force, and the refusal is returned, not hidden.
| Parameter | Type |
|---|---|
text | string |
options | { force?: boolean; } |
options.force? | boolean |
Promise<Turn>
status(tail?): Promise<ThreadStatus>;The run's status on the closed ladder, with the raw output tail.
| Parameter | Type | Default value |
|---|---|---|
tail | number | 200 |
Promise<ThreadStatus>
stop(): Promise<{
reason: string;
stopped: boolean;
}>;Stops the run; stopped says whether its death was witnessed.
Promise<{
reason: string;
stopped: boolean;
}>
Turns a growing transcript into events, without re-emitting what it already emitted.
The runtime gives us a tail, not a stream, so the adapter tracks what it has
consumed by content, not by offset: a tail that scrolled past our last known
position is detected, and only the portion it can prove is new is emitted.
When it cannot prove overlap at all: the tail
scrolled entirely past: it emits the whole tail and an error event saying
output was lost, rather than silently dropping it.
new TranscriptAdapter(): TranscriptAdapter;ingest(tail, now?): ThreadEvent[];Feed the newest transcript tail; get back only the newly observed events.
| Parameter | Type |
|---|---|
tail | string |
now | () => Date |
reset(): void;Reset for a new turn that restarts the session (codex resume does this).
void
The agent is blocked on a human decision.
No agent runtime in a Space emits this today (they run auto-approved). It is
defined because an app that puts an agent in front of a user needs the shape,
and because a derived detector can spot a REPL prompt that is waiting. Answer
it with thread.send(...): there is no separate approval RPC yet, and this
SDK will not invent one that silently does nothing.
ThreadEventBaseOne shape's art: an SVG path (absolute M, L, C, Z; nonzero fill) and its hot spot.
ThreadEventBaseA file the agent appears to have produced, by absolute path inside the Space.
Fetch it with space.download(path, destDir): the SDK does not pre-fetch.
ThreadEventBaseOne line of the scheduler's log, newest first.
| Property | Type |
|---|---|
at | string |
firing | RoutineFiring |
routineID | string |
title | string |
The result of fanning one message out to one member.
| Property | Type | Description |
|---|---|---|
at | string | - |
id | string | - |
reaction? | string | - |
speaker | GroupSpeaker | - |
text | string | - |
undelivered | boolean | This line records a message that did not reach its Bot. |
How a group reaches its Bots. deliver never throws: a refusal is a result.
deliver(text, botID): Promise<GroupDelivery>;| Parameter | Type |
|---|---|
text | string |
botID | string |
Promise<GroupDelivery>
displayName(botID): string;| Parameter | Type |
|---|---|
botID | string |
string
isWorking(botID): boolean;Whether the Bot is producing output right now (the typing row).
| Parameter | Type |
|---|---|
botID | string |
boolean
latestReply(botID): Promise<string | undefined>;The Bot's most recent utterance, or undefined.
| Parameter | Type |
|---|---|
botID | string |
Promise<string | undefined>
An image the agent produced. data is base64; path is set instead when the
image is only known by its in-Space location.
ThreadEventBaseThreadEventBaseOne cursor to draw now.
| Property | Type |
|---|---|
alpha | number |
color | string |
displayId | string |
displayName | string |
isAgent | boolean |
isMe | boolean |
participantId | string |
shape | CursorShapeName |
shapeSource | string |
windowId? | string |
x | number |
y | number |
One participant and their last cursor (normalized 0..1 over the streamed surface).
| Property | Type | Description |
|---|---|---|
agent | boolean | - |
color | string | - |
cursor? | object | - |
cursor.shape? | CursorShapeName | - |
cursor.visible | boolean | - |
cursor.windowId? | string | - |
cursor.x | number | - |
cursor.y | number | - |
displayName | string | - |
participantId | string | - |
principalId | string | The identity it joined with (PresenceIdentity.id), unless the server asserts one. |
One routine. Dates are ISO 8601 (UTC, whole seconds).
| Property | Type | Description |
|---|---|---|
botID | string | The Bot that runs it. A routine never spans Bots; a group chat does. |
createdAt | string | - |
id | string | - |
isEnabled | boolean | - |
lastFiredAt? | string | When the scheduler last started a firing (persisted, so a restart does not re-fire the past). |
lastOutcome? | string | The scheduler's words about the last firing: started, refused, failed. |
lastRunID? | string | The agent run the last firing produced. |
prompt | string | The text handed to the Bot when it fires. |
schedule | RoutineSchedule | - |
title | string | - |
Gives a Bot its routine turn. Never throws: a refusal is a result.
fire(routine): Promise<RoutineFiring>;| Parameter | Type |
|---|---|
routine | Routine |
Promise<RoutineFiring>
Where the routine list lives. load returns undefined when nothing was saved.
load(): string | undefined;string | undefined
save(json): void;| Parameter | Type |
|---|---|
json | string |
void
| Property | Type | Description |
|---|---|---|
agent | AgentId | - |
label? | string | Your own label, echoed on the thread. |
placement | ThreadPlacement | - |
prompt | string | The first task. There is no empty thread. |
show? | boolean | Open a terminal on the Space desktop tailing the run (default false). |
ThreadEventBase| Property | Type | Description | Overrides | Inherited from |
|---|---|---|---|---|
derived | boolean | true when this event was inferred from unstructured terminal output rather than reported by the agent runtime. Always check it before treating an event as authoritative. | - | ThreadEventBase.derived |
kind | "state" | - | ThreadEventBase.kind | - |
observedAt | string | Wall clock at the moment the SDK observed it, not when the agent produced it. | - | ThreadEventBase.observedAt |
reason | string | The ladder's reason for this status. | - | - |
seq | number | Monotonic within a thread, assigned by the SDK. | - | ThreadEventBase.seq |
state | AgentStatus | - | - | - |
ThreadEventBaseEverything the SDK knows about a run's current moment.
| Property | Type | Description |
|---|---|---|
acceptsMessage | boolean | A follow-up sent now starts the next turn: the server's published rule (idle, or a crashed or failed run it restarts; not mid-turn). |
desktopWindow | string | null | The agent's terminal window on the Space desktop, when it was found. null means "not found", which is not the same as "does not exist". |
reason | string | Why the ladder landed there, in words. Always populated. |
runId | string | - |
status | AgentStatus | - |
transcript | string | The raw transcript tail exactly as the Space reported it. Always present, because every derived event above is an interpretation of this. |
One delivered (or refused) message.
type AgentId =
| "claude-code"
| "gemini-cli"
| "google-antigravity"
| "goose"
| "hermes"
| "openai-codex"
| "openclaw"
| "opencode"
| "pi";Agent CLIs the Spaces runtime can start (the contract's AGENT_IDS).
type AgentStatus =
| "running"
| "awaiting_input"
| "idle"
| "finished"
| "failed"
| "crashed"
| "unknown";The agent status ladder: one closed vocabulary for every harness and every provider. A UI can rely on this being closed.
idle and finished are deliberately different: both mean "no turn is
running", but idle means the session can still be continued and finished
means it cannot.
unknown is a real, reachable state and is not a synonym for "done". A
probe that could not run, an unreachable Space, and an interactive REPL whose
working-vs-waiting we cannot tell apart all land here. Reporting any of them
as idle is how a caller concludes an agent finished when the Space actually
fell over: and crashed exists so a dead process that never recorded an
exit status is never read as a clean finish.
type CursorShapeName =
| "arrow"
| "text"
| "pointer"
| "resize_ew"
| "resize_ns"
| "resize_nwse"
| "resize_nesw"
| "move"
| "crosshair"
| "wait"
| "progress"
| "not_allowed"
| "grab"
| "grabbing";A presence cursor shape (the names of cua.env.v1.CursorShape).
type GroupChatErrorCode =
| "tooFewBots"
| "tooManyBots"
| "full"
| "atFloor"
| "alreadyAMember"
| "notAMember"
| "unknownChat";type GroupSpeaker =
| {
kind: "human";
}
| {
botID: string;
kind: "bot";
}
| {
kind: "system";
};Who said a line: the human, a Bot, or the group itself (joins, leaves, refusals).
type RoutineFiring =
| {
kind: "started";
runId: string;
}
| {
kind: "refused";
reason: string;
}
| {
kind: "failed";
reason: string;
};What happened when a routine fired. A refusal is not a failure.
type RoutineSchedule =
| {
kind: "everyMinutes";
minutes: number;
}
| {
hour: number;
kind: "dailyAt";
minute: number;
}
| {
hour: number;
kind: "weeklyOn";
minute: number;
weekday: number;
};The three recurrence shapes. weekday is 1 = Sunday … 7 = Saturday.
type SpacesErrorCode =
| "auth"
| "transport"
| "http"
| "protocol"
| "usage"
| "not_found"
| "ambiguous_sandbox"
| "timeout"
| "verification"
| "isolation"
| "space_command"
| "host_unavailable"
| "unsupported"
| "capability_missing"
| "host_capability_missing"
| "spacesd_not_available"
| "teleport_refused";Stable, matchable error codes. Adding a code is a minor release; removing or repurposing one is a breaking release.
type ThreadEvent =
| TextEvent
| FileEvent
| ImageEvent
| LinkEvent
| ApprovalRequestEvent
| StateEvent
| ErrorEvent;type ThreadEventKind =
| "text"
| "file"
| "image"
| "link"
| "approval_request"
| "state"
| "error";What an agent sends back.
The honest situation, as of this release: the agent runtime inside a Space is
a terminal. agent_status returns the tail of the run's output (the agent
runs as a detached, tagged cua-spacesd process). There is no structured
result channel yet: no file manifest, no image parts, no approval
protocol. The supported agents are launched auto-approved and the sandbox is
the safety boundary.
So this module does two things and is careful about the difference:
derived: true. A consumer can therefore tell a fact
("the agent emitted this file") from an inference ("a path-shaped string
appeared in the scrollback"). Nothing here pretends to be ground truth.When the agent runtime gains a structured channel (see docs/), the adapter
gains a branch that emits the same events with derived: false. The union is
the stable contract; the adapter is not.
type ThreadPlacement =
| {
deleteOnClose?: boolean;
image?: string;
kind?: string;
on?: string;
runtime?: string;
type: "dedicated";
}
| {
acknowledgeNoIsolation: true;
space: string | SpaceLike;
type: "shared";
};Where a thread's agent runs. There is no default; choosing is the point.
{
deleteOnClose?: boolean;
image?: string;
kind?: string;
on?: string;
runtime?: string;
type: "dedicated";
}| Name | Type | Description |
|---|---|---|
deleteOnClose? | boolean | Delete the Space when the thread closes. Default true. |
image? | string | Image of the Space this thread creates (default: the canonical Linux image). |
kind? | string | auto (default), container or vm. |
on? | string | Where: local or cloud (default: the user's default location). |
runtime? | string | auto (default) or an engine the location offers for the kind. |
type | "dedicated" | - |
{
acknowledgeNoIsolation: true;
space: string | SpaceLike;
type: "shared";
}| Name | Type | Description |
|---|---|---|
acknowledgeNoIsolation | true | Required, and required to be literally true: this thread shares a filesystem, a browser profile, cookies and every app login with every other thread on the Space; nothing inside a Space is a security boundary. |
space | string | SpaceLike | The Space (id or handle) to place this thread on. |
type | "shared" | - |
const AGENT_IDS: readonly AgentId[];const CURSOR_ART: object;The shared presence cursor art: fill with the participant's color over the outline.
| Name | Type |
|---|---|
canvas | number |
outline | object |
outline.color | string |
outline.width | number |
shapes | Readonly<Record<CursorShapeName, CursorArtShape>> |
const CURSOR_SHAPES: readonly CursorShapeName[];Every shape, in wire order.
const DATAGRAM_DELAY_MS: 66 = 66;Render delay on the 30 Hz datagram channel.
const GROUP_MAX_BOTS: 6 = 6;const GROUP_MIN_BOTS: 2 = 2;The product bound: a group of one is a thread; every message fans out to every member.
const PRESENCE_FALLBACK_COLOR: "#3b82f6" = "#3b82f6";Used when the server assigned no color.
const PRESENCE_PALETTE: readonly string[];The cursor palette, in cua-spacesd's assignment order.
const ROUTINE_PREFIX: "[routine]" = "[routine]";Marks a routine-originated turn in a transcript.
const SETTLED: ReadonlySet<AgentStatus>;Statuses after which events() stops polling.
const STREAM_DELAY_MS: 100 = 100;The presence netcode model, mirrored exactly from the Rust core
(cua_spaces::presence::view) and checked against the same conformance
vectors. Pure and deterministic: every method takes the local time in
milliseconds (Date.now()).
function adoptThread(
spaces,
spaceId,
runId
): Promise<Thread>;Adopts a run that already exists (started by another process or the MCP).
| Parameter | Type |
|---|---|
spaces | SpacesLike |
spaceId | string |
runId | string |
Promise<Thread>
function agentIdentity(id, displayName): object;An agent's presence identity, requesting its stable presenceColor.
| Parameter | Type |
|---|---|
id | string |
displayName | string |
object
| Name | Type |
|---|---|
agent | true |
color | string |
displayName | string |
id | string |
function approve(decide): TeleportApprover;A TeleportApprover from a function. The function sees exactly what
would leave this machine and returns the human's decision, or undefined
to cancel (the teleport then fails with TeleportRefused). It runs on a
worker thread of the SDK and must be synchronous.
| Parameter | Type |
|---|---|
decide | (manifest) => TeleportDecision | undefined |
TeleportApprover
function canCreateGroup(members): boolean;Whether a Create button should be enabled for members.
| Parameter | Type |
|---|---|
members | readonly string[] |
boolean
function clockLabel(hour, minute): string;8:05 AM.
| Parameter | Type |
|---|---|
hour | number |
minute | number |
string
function cursorArt(shape): CursorArtShape;The art for shape; unknown names get the arrow.
| Parameter | Type |
|---|---|
shape | string |
function cursorArtSvg(
shape,
color,
size?
): string;A standalone SVG of shape filled with color, size pixels square.
The hot spot is at cursorArt(shape).hotspot * size / CURSOR_ART.canvas.
| Parameter | Type | Default value |
|---|---|---|
shape | string | undefined |
color | string | undefined |
size | number | CURSOR_ART.canvas |
string
function detectApproval(fresh):
| {
options: string[];
prompt: string;
}
| null;Spot a terminal prompt that is waiting on a human.
Only fires on a prompt at the very end of the fresh output: a question in
the middle of the scrollback has already been answered. Recognizes the two
common shapes: a [y/N]-style suffix and a numbered choice list followed by
a prompt line.
| Parameter | Type |
|---|---|
fresh | string |
| {
options: string[];
prompt: string;
}
| null
function excerpt(body, max?): string;Trim an untrusted body for an error message without hiding it entirely.
| Parameter | Type | Default value |
|---|---|---|
body | string | undefined |
max | number | 400 |
string
function firingSummary(f): string;started run <id>, refused: <why>, failed: <why>.
| Parameter | Type |
|---|---|
f | RoutineFiring |
string
function frameGroupMessage(
text,
botID,
chat,
name
): string;The framing each member receives: the room, then the human's words on the last line (so an agent that reads the last line still sees them).
| Parameter | Type |
|---|---|
text | string |
botID | string |
chat | GroupChat |
name | (botID) => string |
string
function idleAlpha(idleMs): number;Opacity of a cursor idle for idleMs.
| Parameter | Type |
|---|---|
idleMs | number |
number
function isCursorShape(name): name is CursorShapeName;Whether name is a known shape.
| Parameter | Type |
|---|---|
name | unknown |
name is CursorShapeName
function isDue(routine, now): boolean;Whether the scheduler should fire routine at now. Measured from the
last firing, not the tick, so a sleeping scheduler fires once on waking.
| Parameter | Type |
|---|---|
routine | Routine |
now | Date |
boolean
function isoSeconds(d): string;ISO 8601 in UTC with whole seconds, the portable form every SDK reads.
| Parameter | Type |
|---|---|
d | Date |
string
function isSpacesError(value, code?): value is SpacesError;Narrowing helper for consumers: if (isSpacesError(e, 'verification')) …
| Parameter | Type |
|---|---|
value | unknown |
code? | SpacesErrorCode |
value is SpacesError
function lockFor(spaceId): SpaceTurnLock;One lock per Space id, so two handles to the same Space share it.
| Parameter | Type |
|---|---|
spaceId | string |
function memoryStorage(initial?): RoutineStorage & object;A RoutineStorage in memory.
| Parameter | Type |
|---|---|
initial? | string |
RoutineStorage & object
function nextFireDate(schedule, reference): Date | undefined;The first slot strictly after reference, in local time; undefined for an invalid schedule.
| Parameter | Type |
|---|---|
schedule | RoutineSchedule |
reference | Date |
Date | undefined
function parseRoutines(json): Routine[];Parses a saved routine list. Throws on anything malformed rather than guessing.
| Parameter | Type |
|---|---|
json | string |
Routine[]
function presenceColor(id): string;The stable presence color of an agent or other principal: a palette color
picked by a hash (FNV-1a, 32-bit, over the UTF-8 id), the same answer as the
Rust core's presence_color in every binding. Request it when the agent
joins presence (PresenceIdentity.color) and use it as the background of
its avatar, so avatar and cursor come from one source.
| Parameter | Type |
|---|---|
id | string |
string
function presenceTextColor(background): string;Black or white text, whichever has the better WCAG contrast on background (#rrggbb).
| Parameter | Type |
|---|---|
background | string |
string
function routineNextFire(routine, reference): Date | undefined;When routine next fires after reference, or undefined when disabled.
| Parameter | Type |
|---|---|
routine | Routine |
reference | Date |
Date | undefined
function routineTurnText(routine): string;The text a runner hands the Bot: [routine] <title>: <prompt>.
| Parameter | Type |
|---|---|
routine | Pick<Routine, "title" | "prompt"> |
string
function scheduleLabel(schedule): string;The one-line description of a schedule: Every day at 8:00 AM.
| Parameter | Type |
|---|---|
schedule | RoutineSchedule |
string
function startThread(spaces, options): Promise<Thread>;Starts an agent thread. placement is required and has no default.
| Parameter | Type |
|---|---|
spaces | SpacesLike |
options | StartThreadOptions |
Promise<Thread>
function toSpacesError(error): SpacesError;Wraps anything the native SDK threw as a SpacesError with a stable
code (the CuaError variant stays reachable as cause). Already-wrapped
errors pass through.
| Parameter | Type |
|---|---|
error | unknown |
function validatePlacement(placement): ThreadPlacement;Throws unless the caller genuinely chose a placement.
| Parameter | Type |
|---|---|
placement | ThreadPlacement | undefined |
function waitForPresence(
session,
match,
timeoutMs,
maxEvents?,
roster?
): Promise<PresenceEvent>;Reads session until an event matches, folding every event into roster
when given. Throws after timeoutMs or maxEvents events.
| Parameter | Type | Default value |
|---|---|---|
session | PresenceEventSource | undefined |
match | (e) => boolean | undefined |
timeoutMs | number | undefined |
maxEvents | number | 50 |
roster? | PresenceRoster | undefined |
Promise<PresenceEvent>
function wrapErrors<T>(body): Promise<T>;Runs body, rethrowing native errors as SpacesError.
| Type Parameter |
|---|
T |
| Parameter | Type |
|---|---|
body | () => Promise<T> |
Promise<T>