What changed, release by release.
Every release's mods API against the one before it: which nouns, verbs, events and types it added, which it removed, and which changed shape, with the lines that moved. A removal is marked breaking; a change that took something out may break a mod; one that only added to a shape is marked extended.
v2.1.283
+0 added · 0 removed · 2 changed · 2 docs only since 2.1.282Types
-
The props of
Button, every surface's pressable leaf: an address, a label, the closure a press runs, and the label styles a hover overrides.plain?: true; dimColor?: boolean; variant?: 'primary' | 'secondary'; role?: 'dismiss'; autoFocus?: true; hover?: TextHoverProps; onPress: () => void; -
What a render hook returns, and what
next(e)resolves to: a plain-data tree of elements (a Box or Text is a StyledElement), strings as children.plain?: true; dimColor?: TextProps['dimColor']; variant?: ButtonProps['variant']; role?: ButtonProps['role']; autoFocus?: true; }; press: {
2 docs only: reworded, same shape
RenderPropsOftypeThe plain-data props of each renderable component, as
ui.rendersees them undere.props; a hook rewrites them withnext({ ...e, props }).TurnCompleteFieldstypeWhat every
turn.completecarries whatever its reason: the answer, the duration, the interrupt flag, the turn's id, its loop and what it cost.
v2.1.282
+0 added · 0 removed · 5 changed · 3 docs only since 2.1.281Types
-
The props of
Button, every surface's pressable leaf: an address, a label, the closure a press runs, and the label styles a hover overrides.action?: string; plain?: true; dimColor?: boolean; variant?: 'primary' | 'secondary'; autoFocus?: true; hover?: TextHoverProps; onPress: () => void; -
What a
prompt.fillhook returns and whatnext(e)resolves to: whether the text went into the prompt box.export type PromptFillResult = { isFilled: boolean; refusal?: 'no_composer' | 'dialog';}; -
What
$.prompt.fillresolves to: whether the box took the text, and the box afterwards (PromptBox) as the caller's own$.prompt.read()reads it.export type PromptFilled = { isFilled: boolean; refusal?: 'no_composer' | 'dialog'; text: string; cursor: number;}; -
What a render hook returns, and what
next(e)resolves to: a plain-data tree of elements (a Box or Text is a StyledElement), strings as children.action?: string; plain?: true; dimColor?: TextProps['dimColor']; variant?: ButtonProps['variant']; autoFocus?: true; }; press: { -
An external-event wake the delivery's text parsed as (a GitHub relay event, a signal's notice): the envelope's attributes and its JSON body.
export type SessionReceiveEvent = { source: string; kind: string; from?: string; data: Record<string, unknown>; untrustedKeys: readonly string[];};
3 docs only: reworded, same shape
MarkdownPropstypeThe props of
Markdown, a block of markdown every surface draws as it draws an assistant reply's text: its own renderer, links, tables, fences.RenderPropsOftypeThe plain-data props of each renderable component, as
ui.rendersees them undere.props; a hook rewrites them withnext({ ...e, props }).TurnCompleteFieldstypeWhat every
turn.completecarries whatever its reason: the answer, the duration, the interrupt flag, the turn's id, its loop and what it cost.
v2.1.281
+41 added · 0 removed · 2 changed · 6 docs only since 2.1.280The engine
-
Returns the version of the engine the session runs on, the release it is built from, and when it was built.
-
Named values held by the host for the session, each with a version: plain data that survives a hot reload of the plugin's code.
-
Resolves the value under
refand the version it stands at; a value never written isundefinedat version 0. -
Writes
valueunderref, which must be this plugin's own; the sites that read it while drawing are drawn again, at the redraw rate.
Events
-
The argument of
$.session.version(). -
The argument of
$.state.get(ref): the reference itself,plugin,keyand a family member'sid; identity, pinned. -
The argument of
$.state.set(ref, value, { ifVersion }): the reference, the value, the condition, andprevious, what stood there (the host's).
Types
-
What each call on
$answers (thevalueof its event's result), by event name.'session.surfaces': readonly RenderSurface[]; 'session.authorize': SessionAuthorization; 'session.usage': SessionUsage; 'session.version': SessionVersion; 'turn.abort': void; 'prompt.read': PromptBox; 'tool.list': ToolInfo[];… 'store.set': void; 'store.delete': void; 'store.keys': string[]; 'state.get': StateRead; 'state.set': StateSetResult; 'clock.now': number; 'clock.sleep': void; 'clock.after': void; -
What a hooks module uses, as the host scanned its source before loading it: the same lists
claude plugin validateprints and the host's rule reads.reads: readonly string[]; writes: readonly string[]; }; state?: { reads: readonly StateName[]; writes: readonly StateName[]; };}; -
A named value with its initial, as
atom(ref, initial)makes it: read, it is neverundefined; while nothing is written it reads as the initial. -
atom(ref, initial): a named value with its initial, so a read is neverundefined; given{ shape }, for a key declaredShaped<T>. -
The options of
atom:shape, a tag the value is kept under, so a reload of the plugin's code that names another tag finds the value absent. -
The state events of each declared value in a union of
[plugin, key]pairs, one variant per pair (it distributes), so a matcher narrowse. -
eofstate.getand ofstate.setfor one declared value: its typed reference, and for a write the change, of the declared type. -
Every named value the enabled contracts declare, as one union of
[plugin, key]pairs;neverwhile PluginState is empty. -
What a
state.seton one declared value carries beside its reference: the value being written and the one that stood there, of the declared type. -
derive(sources, fn): a value computed from atoms and references, cached by their versions:readrunsfnagain only when one moved. -
A value computed from other values, as
derive(sources, fn)makes it:readrunsfnagain only when a source's version moved. -
memberOf(family, e): the member of a family for the instance being drawn, keyed bye.requestId; of an atom over a family, that member's. -
The named values plugins keep in the session (
$.state), by plugin name then key, for declaration merging; empty by default. -
read($, source): the value of an atom (its initial while absent), of a derived value, or under a plain reference; one$.state.getper value. -
What
$.session.version()answers: the version of the engine the session runs on, the release that version is built from, and when it was built. -
A value kept with a shape tag, as an
atomgiven{ shape }keeps it: a reload whose code names another tag reads the value as absent. -
What an atom given a shape reads and takes for a key declared
Shaped<T>:T;neverfor a key declared otherwise, so that atom does not compile. -
The values
derive's function receives for its sources, in their order: an atom's or a derived value's own, a plain reference's orundefined. -
Which named value a
$.statecall is about, as it crosses to the host: the owning plugin, the key, and a family member'sid. -
What the state library's
readandupdatetake of$: itsstatenoun, on which they make the calls a hook would make itself. -
A key of PluginState that holds one value of type
Tperid(one per drawn row, per worker): its reference must carryid: string. -
eofstate.get: one variant per value a contract declares, so a matcher onpluginandkeynarrows it; the untyped address while none does. -
Which named value: the plugin that owns it and its key there, both literals where a contract declares the value.
-
What
$.state.getanswers: the value and the version it stands at; a value never written isundefinedat version 0. -
A typed reference to one named value: the owning plugin and the key, both literals, and for a StateFamily key the member's
id. -
eofstate.set: one variant per value a contract declares, so a matcher onpluginandkeynarrowse.value; the untyped write while none does. -
The options of
$.state.set:ifVersionmakes the write conditional on the value still standing at that version (compare-and-set). -
What
$.state.setanswers: whether the write landed, and the version the value stands at now (a landed write's own, a missed one's the current). -
The type of the value under key
Kof pluginP, as its contract declares it in PluginState; a StateFamily's member type for a family key. -
A
$.state.setas it crosses to the host and as its hooks see it when no contract declares the value: the address, the value, and the condition. -
update($, target, fn): reads the value, appliesfnhere in the plugin's environment, writes withifVersion, and tries again on a miss. -
A named value with its initial:
readanswers the initial while nothing is written, so neverundefined. Pure; runs in the plugin's environment. -
A value computed from atoms and references, cached by their versions.
-
A family's member for the instance being drawn, keyed by
e.requestId. -
Reads an atom, a derived value or a reference through
$.state.get; while aui.renderhook draws, that subscribes the drawing. -
Reads, applies
fnin the plugin's environment, writes withifVersion, and tries again on a miss: what a handler closure calls.
6 docs only: reworded, same shape
$.ui.toastverbShows
textfor a few seconds under the plugin's name: a small box on the stack of plugin toasts over the transcript's top right corner.ElementstypeThe element constructors each surface draws, by
e.surface: what$.ui.resolve(e)returns and aui.resolvehook passes on; no globals.PaneOpenArgstypeThe argument of
$.ui.open: which pane, its title, whether it asks the person's keyboard, its dialog manners, its size: rows inline, columns docked.RenderPropsOftypeThe plain-data props of each renderable component, as
ui.rendersees them undere.props; a hook rewrites them withnext({ ...e, props }).RenderViewporttypeThe size of what a surface draws into, in character cells of the surface's monospace metric, and whether its layout docks a pane.
UiOpenResulttypeWhat
$.ui.openresolves to and what aui.openhook's{ value }holds.
v2.1.280
+40 added · 2 removed · 21 changed · 27 docs only since 2.1.278The engine
-
Runs one text completion through the session's own API client and resolves a result: the reply's text and cost, or why there is no text.
(request: ModelCompleteRequest) => Promise<string>(request: ModelCompleteRequest) => Promise<ModelCompleteResult> -
Runs one tool-less completion over the session's OWN transcript as the main thread last sent it, so the API serves that prefix from its cache.
(request: ModelForkRequest) => Promise<ModelForkResult | null>(request: ModelForkRequest) => Promise<ModelForkResult> -
Returns the transcript so far, one SessionMessage per user or assistant message; progress rows,
$.ui.loglines and notices are not messages.() => Promise<SessionMessage[]>SessionMessagesCall -
Opens a pane, a framed region the surface places and this plugin draws by hooking
ui.renderfor{ component: "Pane" }; says if it is drawn.(pane: PaneOpenArgs) => Promise<void>(pane: PaneOpenArgs) => Promise<UiOpenResult> -
Starts a command on the host by its argument vector (no shell) and streams what it writes, piece by piece, then how it ended.
-
Sends a plain-text message to another agent or session: the event
session.send, the model's SendMessage tool's own call and delivery. -
Puts
texton the clipboard of a surface the session draws on, as the DOM'snavigator.clipboard.writeText, and says whether it took.
Events
-
The argument of
$.session.messages(args):{}for the main conversation,{ agentId }for one of its agents,asfor the form.NoArgsSessionMessagesArgs -
The argument of
$.process.spawn(request): the request itself. -
Fires when a plain-text message is about to leave this conversation for another agent or session (the SendMessage tool, or
$.session.send). -
{ isDelivered: true }, or{ isDelivered: false, reason }. -
The argument of
$.ui.copy({ text, surface }),surfacefilled with the session's first when left out; rewritable, deniable, answerable.
Types
- removed
ContextApiUsagetype breakingThe token counts the last API response of the live window reported, as the API spells them; the breakdown's
Messagesrow is reconciled to it. - removed
ModelForkUsagetype breakingWhat one fork cost, as the API counted it: the four token counts of the fork's completions summed.
-
The chunk type of each streaming event, by name: what its stream yields.
export type ChunkOf = { 'turn.step': TurnStepChunk; 'process.spawn': ProcessSpawnChunk;}; -
What a test holds as
$, the engine's own: every call on it is made as the REPL, the query loop and the render sites make theirs, over every plugin.export type Engine = { [N in keyof EventCalls]: N extends 'ui' ? EngineNoun<N> & EnginePress & EngineMount : EngineNoun<N>; [N in keyof EventCalls]: N extends 'ui' ? EngineNoun<N> & EnginePress & EngineInput & EngineSelect & EngineMount : EngineNoun<N>;} & { classic: EngineClassic;}; -
The engine's own events as calls on
$, one signature each:$.<noun>.<event>(input)resolves to its result, or to its stream.session: { start: (input: SessionStartInput) => Promise<SessionStartResult>; receive: (input: SessionReceiveInput) => Promise<SessionReceiveResult>; send: (input: SessionSendArgs) => Promise<SessionSendResult>; compact: (input?: SessionCompactArgs) => Promise<SessionCompactResult>; attach: (input: SessionAttachInput) => Promise<SessionAttachResult>; detach: (input: SessionDetachInput) => Promise<SessionDetachResult>; -
What
$.model.completetakes.prompt: string; system?: string; maxTokens?: number; effort?: ModelEffort; timeoutMs?: number;}; -
What
$.model.forkresolves to: a completion's result (ModelCompleteResult) or that there was nothing to fork yet.export type ModelForkResult = { text: string; usage: ModelForkUsage;export type ModelForkResult = ModelCompleteResult | { isAnswered: false; reason: 'nothing-to-fork';}; -
What each call on
$answers (thevalueof its event's result), by event name.export type OpValueOf = { 'model.complete': string; 'model.complete': ModelCompleteResult; 'model.classify': string | undefined; 'model.fork': ModelForkResult | null; 'model.fork': ModelForkResult; 'audio.play': void; 'audio.speak': SpeakResult; 'mcp.call': McpToolResult;… 'session.model': string; 'session.turns': number; 'session.id': string; 'session.messages': SessionMessage[]; 'session.messages': SessionMessagesValue; 'session.repo': SessionRepo | null; 'session.surface': RenderSurface | null; 'session.surfaces': readonly RenderSurface[];… 'ui.log': void; 'ui.notice': void; 'ui.invalidate': void; 'ui.open': void; 'ui.open': UiOpenResult; 'ui.close': void; 'ui.panes': readonly UiPane[]; 'ui.copy': UiCopyResult; 'ui.blit': UiBlitResult; 'fs.read': string | FsBytes; 'fs.write': void;… 'clock.every': void; 'http.fetch': HttpResponse; 'process.run': ProcessRunResult; 'process.spawn': ProcessSpawnResult; 'settings.read': Settings; 'env.get': string | undefined; 'env.set': void; -
A compaction that stands: the conversation as it reads afterwards, and the counts and request usage the engine recorded when it was the one compacting.
messages: readonly SessionMessage[]; tokensBefore?: number; tokensAfter?: number; usage?: ModelUsage; skip?: undefined;}; -
The context window broken down as /context breaks it down: the rows, the grid and the lists beneath it, in the SDK's
get_context_usageshape.skills?: ContextSkills; autoCompactThreshold?: number; isAutoCompactEnabled: boolean; apiUsage: ContextApiUsage | null; apiUsage: ModelUsage | null;}; -
The input of
session.receive: one inbound delivery, sanitized, before it is queued (a relay's event, a peer's message, a message for an agent).origin: SessionReceiveOrigin; text: string; event?: SessionReceiveEvent; agentId?: string;}; -
Where an inbound delivery came from, as the bridge classified it from the server's stamps:
prompt.submit'se.origin, less what never arrives.export type SessionReceiveOrigin = { kind: 'bridge' | 'task-notification' | 'scheduled-trigger' | 'peer' | 'peer-send-message' | 'projects-relay' | 'slack-ping' | 'unclassified'; kind: 'bridge' | 'task-notification' | 'scheduled-trigger' | 'peer-send-message' | 'projects-relay' | 'slack-ping' | 'unclassified';} | { kind: 'peer' | 'coordinator'; plugin?: string;} | { kind: 'peer' | 'coordinator'; plugin?: string; teammate: string; isVerified: boolean;}; -
What
$.session.usage()answers: when the session began, the context window's fill, the account's rate-limit windows and the session's cost.export type SessionUsage = { startedAt: number; context: SessionContextUsage; rateLimits: SessionRateLimit[]; cost?: SessionCost; -
The rest of the chain as a hook on a streaming event receives it: Next, except that
next(e)is the stream beneath (HookStream), not a promise.export type StreamNext<N extends StreamingEventName = StreamingEventName, E = Args<N>, O = NextResult<N>, S extends {export type StreamNext<N extends StreamingEventName = StreamingEventName, E = Args<N>, O = EventResult<N>, S extends { [K in N]?: unknown;} = { [K in N]: Args<K>; -
The events that stream: their hooks are async generators,
next(e)is the stream of everything beneath, and the result is what it returns.export type StreamingEventName = 'turn.step';export type StreamingEventName = 'turn.step' | 'process.spawn'; -
What a
tool.callhook returns and whatnext(e)and$.tool.call(input)resolve to: the tool's result ({ result, context? }) or{ deny }.ref?: undefined; text?: undefined; isError?: undefined; isReadOnly?: undefined;} | { result: ToolResultOf<Name>; context?: readonly string[]; ref?: number; text?: string; isReadOnly?: true; isError?: undefined; deny?: undefined;} | {… text?: string; ref?: number; context?: readonly string[]; isReadOnly?: true; deny?: undefined;}; -
One tool_use block of an assistant message, with its outcome once the transcript holds the call's tool_result (paired by
tool_use_id).result?: unknown; text?: string; isError?: true; agentId?: string; durationMs?: number;}; -
What a model turn, or one response inside it, cost as the API reported it: the four token counts (ModelUsage) and the model's id.
export type TurnUsage = ModelForkUsage & {export type TurnUsage = ModelUsage & { model: string;}; -
One content block of an ApiMessage:
typenames its kind (text,tool_use,tool_result,image,document,thinking, ...). -
One message of the conversation in Messages API form, as
$.session.messages({ as: "api" })returns it. -
A classic hook event the engine raises on its own, by its own name (
SessionStart,Stop): all butPreToolUse, which ridestool.call. -
What
$.classic.<Event>takes: the event's own fields as its hook sees them one, less what the engine stamps at every call site. -
The classic (settings) hook events as the engine raises them: each a call running the
classic.<Event>chain over every plugin hooked on it. -
A surface typing into an Input a test rendered: the
ui.inputchain over every plugin hooked on it, the Input's own handler last. -
A surface picking an option of a Select a test rendered: the
ui.selectchain over every plugin hooked on it, the Select's ownonSelectlast. -
What
$.ui.inputtakes: the plugin whose hook drew the Input, itskey, the field's text, which input it is, instance and surface when several. -
Which kind of API failure ended a model call (a completion, a fork), in the word Claude Code classifies every API error with (StopFailure's).
-
What one model call resolves to: the reply when the model answered (
isAnswered), else which of three things left it without text (reason). -
How hard a request asks the model to think, by the levels the engine and
turn.stepname:lowtomax,xhighbetweenhighandmax. -
What one model call cost, as the API counted it: the four token counts in the API's spelling, summed over the call's responses when it made several.
-
One piece of a spawned child's output as
$.process.spawnstreams it: which pipe it came from, and the text. -
The argument of
$.process.spawn(request), and theeits hooks see: the command by its argument vector and how the child is started. -
How a spawned child ended, as the stream of
$.process.spawnreturns it once every piece has been read: its exit code, or the signal that did it. -
What
$.ui.selecttakes: the plugin whose hook drew the Select, itskey, the picked option's value, instance and surface when several. -
A
$.session.messagescall for the rows (SessionMessage) of the main conversation or of one agent's:agentIdalone, noas. -
A
$.session.messagescall for the Messages API form (ApiMessage) of the main conversation or, withagentId, of one of this session's agents'. -
What
$.session.messages({ as: "api", agentId })resolves to: the agent's conversation as ApiMessage, or{ deny }(SessionMessagesDeny). -
What
$.session.messages(args)takes and asession.messageshook reads one: whose conversation (agentId) and in which form (as). -
$.session.messages: the main conversation's rows with no argument, with{ as: "api" }its Messages API form; withagentIdan agent's, or deny. -
What
$.session.messages({ agentId })resolves to when the id names no conversation this session can read: why not, indeny. -
A
$.session.messages({ as: "api" })call naming no agent: the main conversation, whose answer is always the messages (ApiMessage). -
What
$.session.messages({ agentId })resolves to: the messages (SessionMessage), or{ deny }(SessionMessagesDeny). -
What a
session.messageshook's{ value }holds, for any call: the rows (SessionMessage), the Messages API form (ApiMessage), or{ deny }. -
Whom
$.session.sendaddresses: a recipient as the SendMessage tool names one (a string), or a session or an agent of this session by id. -
session.send's input as a plugin's$.session.send(args)takes it:origin(the calling plugin) andagentIdare the engine's to set. -
The input of
session.send: one plain-text message about to leave this conversation for another agent or session; the dual ofsession.receive. -
Who is sending at
session.send: the model through its SendMessage tool, or a plugin through$.session.send; stamped by the engine, pinned. -
What a
session.sendhook returns andnext(e)and$.session.sendresolve to: whether the message was delivered, and why not when not. -
The argument of
$.ui.copyand the input ofui.copy: the text, and which surface's clipboard takes it, the caller's choice. -
What
$.ui.copyresolves to and what aui.copyhook's{ value }holds: whether the text reached a clipboard (isCopied), else why not. -
What
$.ui.openresolves to and what aui.openhook's{ value }holds.
27 docs only: reworded, same shape
$.clock.sleepverbResolves after
msmilliseconds; rejects at once whensignalaborts.$.prompt.submitverbSubmits a prompt: the event
prompt.submit, the same call the engine makes for a typed prompt; a turn of its own, once the session is idle.$.sessionnounThe running session, read as plain data; compacting it; and sending a message from it to another agent or session.
$.session.authorizeverbHolds the session's Anthropic credential on the host and answers an opaque handle and its kind; the secret never reaches the plugin.
$.session.usageverbReturns when the session began, and the context window's fill, the rate-limit windows and the cost as the status line has them, itemized.
$.uinounDisplay: a line under an open dialog, a redraw or a repaint, a log line, panes the surface places, a window or ring, a surface's clipboard.
$.ui.focusverbMoves the focus ring of one of this plugin's sites onto an element it drew there, as the DOM's
element.focus(), while it holds the keys.session.detacheventFires when a client leaves the roster: it detached, or the session ended with it attached (
e.reason). Observe;next(e)echoes{ clientId }.session.endeventFires once when the session ends (exit, /clear, resume, logout, signal, a
-prun done), after its SessionEnd settings hooks;e.reasonsays which.session.receiveeventFires when a delivery reaches the session (a relay's event, a peer's message, a Remote Control prompt), before it is queued;
{ text }.ButtonPropstypeThe props of
Button, every surface's pressable leaf: an address, a label, the closure a press runs, and the label styles a hover overrides.ClassicEventOftypeThe classic (settings) hook events, one per classic event name:
eis the hook's whole stdin input, base fields (transcript_path,cwd) included.EnginePresstypeA surface pressing a Button a test rendered, or a Markdown's link: the
ui.presschain over every plugin hooked on it, its own closure last.HookBudgettypeThe time bounds every hook runs under, in milliseconds: the engine's own constants are typed by these members, and
next.budgetreads the live one.HookOftypeThe hook event
Etakes: an async generator over its chunks for a streaming event (StreamingEventName),($, e, next) => resultotherwise.ModelForkRequesttypeWhat
$.model.forktakes.MountedMemberstypeEvery member a mounted drawing of component
Ccan have;Mounted<P, C>keeps the ones surfacePhas the element for (ElementOfAct).NexttypeThe rest of the chain, as one hook receives it: made once per dispatch per hook, frozen;
next(e)resolves to the downstream result.NextBudgettypeThe budget the code reading
next.budgetruns under: the whole allowance and what is left of it now, plain data read fresh on each access.PaneOpenArgstypeThe argument of
$.ui.open: which pane, its title, whether it asks the person's keyboard, its dialog manners, its size: rows inline, columns docked.SessionCompactInputtypeThe input of
session.compact: one compaction of the conversation, about to run;messagesis the transcript it runs over.SessionCompactResulttypeWhat a
session.compacthook returns and whatnext(e)resolves to: the compaction ({ messages, tokensBefore?, tokensAfter?, usage? }) or a skip.SessionEndInputtypeThe input of
session.end: the session is ending, why, and how to come back to it; every field is the engine's: a hook observes,next(e)passes it on.ToolResultSummarytypeOne tool_result block of a user message.
TurnStepInputtypeThe input of
turn.step: one model request inside a turn, at the moment the engine is about to send it; the bottom of the chain sends it.UiFocusArgstypeWhat a plugin's
$.ui.focus(args)takes: one of its own elements, by thekeyit drew it under, in one of its sites that holds the keyboard now.UiPanetypeOne of this plugin's open panes as
$.ui.panes()lists it: the pane's id and title, and where it stands with the person right now.