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.272
No change to the surface since 2.1.271v2.1.271
+77 added · 0 removed · 20 changed · 16 docs only since 2.1.270The engine
-
Resolves milliseconds since the epoch, now.
() => number() => Promise<number> -
Returns the context window's fill, the rate-limit windows and the cost, as the status line has them; with
breakdown, by category too.() => Promise<SessionUsage>(args?: SessionUsageArgs) => Promise<SessionUsage> -
Repaints a
Rasterthis plugin's own render hook drew, still mounted, with new cells, without the redrawinvalidateasks for. -
Moves 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. -
Scrolls something into view as the DOM's
scrollIntoViewwould: a render instance byrequestId, an element bykey, a site's edge.
Events
-
The argument of
$.session.usage({ breakdown, columns }).NoArgsSessionUsageArgs -
The argument of
$.clock.after(ms, fn): the wait beforefn, which stays in the plugin's environment and runs once the dispatch resolves. -
The argument of
$.clock.every(ms, fn), dispatched once per period:fnruns each time a dispatch resolves, and the next period is asked. -
The argument of
$.clock.now(). -
The argument of
$.clock.sleep(ms, { signal }); the signal does not cross, it aborts the dispatch. -
The argument of
$.ui.blit({ requestId, key, cells }); a hook above the painter may repaint the cells withnext, or refuse with{ deny }. -
Fires before a site's focus ring moves: the person's Tab, arrows or click in a
Paneor the band; anautoFocuselement taking it;$.ui.focus. -
{}once the ring moved, or{ deny }. -
Fires before a site's window moves: the person's wheel or scroll keys on a
Panebody or theAbovePromptband, at its edges too;$.ui.scroll. -
{}once the window moved, or{ deny }.
Types
-
The
Boxprops ahovermay override, none of which moves layout, andscope, which names the hover group the Box joins instead of a style.export type BoxHoverProps = { scope?: string; borderStyle?: string; borderColor?: string; borderDimColor?: boolean; -
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.key?: string; label?: string; hotkey?: string; action?: string; plain?: true; dimColor?: boolean; autoFocus?: true; hover?: TextHoverProps; onPress: () => void;}; -
The element table a surface module draws with,
surface.elements: the terminal's (Elements) lessClient(none nests) andRaster(needs$).export type ClientElements = Omit<Elements['terminal'], 'Client'>;export type ClientElements = Omit<Elements['terminal'], 'Client' | 'Raster'>; -
command.run's input as a plugin's$.command.runtakes it:argsmay be left out (/command, bare);originandpresentationthe engine sets.export type CommandRunArgs = Omit<CommandRunInput, 'origin' | 'args'> & {export type CommandRunArgs = Omit<CommandRunInput, 'origin' | 'args' | 'presentation'> & { args?: string;}; -
The input of
command.run: one slash command about to run, the way the person typed it (/name args), and where the run came from.command: string; args: string; origin: PromptOrigin; presentation: CommandPresentation;}; -
The element constructors each surface draws, by
e.surface: what$.ui.resolve(e)returns and aui.resolvehook passes on; no globals.Link: ElementConstructor<LinkProps>; Code: ElementConstructor<CodeProps>; Client: ElementConstructor<ClientProps>; Raster: ElementConstructor<RasterProps>; }; desktop: { Box: ElementConstructor<BoxProps>; -
The engine's own events as calls on
$, one signature each:$.<noun>.<event>(input)resolves to its result, or to its stream.ui: { render: <C extends RenderComponent>(input: RenderInput<C>) => Promise<RenderElement>; resolve: <E extends ResolveInput>(e: E) => Elements[E['surface']]; scroll: (input: UiScrollArgs) => Promise<UiScrollResult>; focus: (input: UiFocusArgs) => Promise<UiFocusResult>; };}; -
The props of
Input, every surface's one-line text field: an address, optional texts, and the closures a change and a submit run. A leaf.placeholder?: string; value?: string; submitLabel?: string; autoFocus?: true; onInput?: (value: string, e: UiInputArgument) => void; onSubmit: (value: string, e: UiInputArgument) => void;}; -
What each call on
$answers (thevalueof its event's result), by event name.'ui.invalidate': void; 'ui.open': void; 'ui.close': void; 'ui.blit': UiBlitResult; 'fs.read': string; 'fs.write': void; 'fs.list': FsEntry[];… 'store.set': void; 'store.delete': void; 'store.keys': string[]; 'clock.now': number; 'clock.sleep': void; 'clock.after': void; 'clock.every': void; 'http.fetch': HttpResponse; 'process.run': ProcessRunResult; 'settings.read': Settings; -
The argument of
$.ui.open: which pane, its title, whether it asks the person's keyboard, its dialog manners, and the rows it wants inline.id: string; title?: string; focus?: true; closeOnEscape?: true; holdToasts?: true; rows?: number;}; -
Everything
ui.rendercan draw: one name per component that has a render site; a matcher narrows on it.export type RenderComponent = 'AskUserQuestion' | 'UserMessage' | 'AssistantMessage' | 'ToolUse' | 'ToolResult' | 'ToolGroup' | 'Spinner' | 'TurnDuration' | 'InfoNotice' | 'SessionMode' | 'PromptHint' | 'AbovePrompt' | 'Pane';export type RenderComponent = 'AskUserQuestion' | 'UserMessage' | 'AssistantMessage' | 'ToolUse' | 'ToolResult' | 'ToolGroup' | 'CommandOutput' | 'Spinner' | 'TurnDuration' | 'InfoNotice' | 'SessionMode' | 'PromptHint' | 'AbovePrompt' | 'Pane'; -
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.export type RenderElement = { type: 'Box'; props?: Record<string, string | number | boolean>; hover?: BoxHoverProps; children?: RenderNode[];} | { type: 'Text'; props?: Record<string, string | number | boolean>; hover?: TextHoverProps; children?: RenderNode[];} | {export type RenderElement = StyledElement<'Box', BoxHoverProps> | StyledElement<'Text', TextHoverProps> | { type: 'Button'; props: { key: string; label: string; hotkey?: string; action?: string; plain?: true; dimColor?: TextProps['dimColor']; autoFocus?: true; }; press: { plugin: string;… placeholder?: string; value?: string; submitLabel?: string; autoFocus?: true; }; press: { plugin: string;… label?: string; options: readonly SelectOption[]; value?: string; autoFocus?: true; }; press: { plugin: string;… props: SvgProps; children?: undefined;} | { type: 'Raster'; props: RasterProps; raster: { plugin: string; }; children?: undefined;} | { type: 'engine'; ref: number;}; -
The plain-data props of each renderable component, as
ui.rendersees them undere.props; a hook rewrites them withnext({ ...e, props }).isActive: boolean; isExpanded: boolean; }; CommandOutput: { command: string; args: string; text: string; isErrored: boolean; }; Spinner: { word: string; message: string | null;… hasSurvey: boolean; isWorking: boolean; maxRows: number; bodyColumns: number; scroll: SiteScroll; view: SiteView; }; Pane: { title: string;… bodyColumns: number; placement: 'dock' | 'inline'; scroll: SiteScroll; view: SiteView; };}; -
The props of
Select, every surface's one-of-several picker: an address, a label, the options, the one selected, the closure a pick runs. A leaf.label?: string; options: readonly SelectOption[]; value?: string; autoFocus?: true; onSelect: (value: string, e: UiSelectArgument) => void;}; -
The live context window as the status line reads it, and by category as /context breaks it down when the call asked (
{ breakdown }).tokens?: number; window: number; percent?: number; breakdown?: SessionContextBreakdown;}; -
The
Textprops ahovermay override (its colors and styles, not its wrapping) andscope, the hover group it joins; aButton's label too.export type TextHoverProps = { scope?: string; color?: string; backgroundColor?: string; dimColor?: boolean; -
The 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.model: string; effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max' | number; messageCount: number; agentId?: string;}; -
A value that matches by a rule inside
toEqualand its kin (expect.any,expect.objectContaining), known by its text in a failure. -
The same checks on what a promise received settles with, each resolving once the promise has settled and the check passed.
-
The argument of the
$.clockwaits (sleep,after,every): how long, in milliseconds, before the dispatch resolves. -
Where a command's answer will show: which of the terminal's two layouts the surface renders, and how wide it is when the command runs.
-
A class, as
toThrow,toBeInstanceOfandexpect.anytake it. -
One custom agent whose description the Agent tool's prompt carries; built-in agents are left out.
- added
ContextApiUsagetypeThe token counts the last API response of the live window reported, as the API spells them; the breakdown's
Messagesrow is reconciled to it. -
How a context breakdown is counted:
fullwith the token-count API per category,summaryfrom the last response's usage and local estimates. -
One row of the breakdown, as /context lists it beside the grid (
System prompt,Messages,Free space,Autocompact buffer). -
What a breakdown row is; branch on this, never on the row's
name. -
One square of the grid /context draws: which row it belongs to and how full it is.
-
One MCP tool's schema as the context carries it.
-
One memory file the context carries (a CLAUDE.md, a rules file, an auto-memory entry).
-
One skill whose listing the context carries.
-
The skills the context lists for the model: how many there are, how many fit the listing's budget, and each one's share.
-
The slash commands the Skill tool's prompt lists, counted.
-
How the window the breakdown measures against was settled; /context prints its
Auto-compact windowline off this. -
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. -
One call on the engine's
$: the event's input whole, as an engine call site passes it, to its result, or for a streaming event to its stream. -
One noun of the engine's
$: each of its events as the engine calls it,tool.callandui.rendertyped per tool and component,ui.resolveout. -
The events of one noun a test's
$carries: every one butui.resolve, which a render hook calls on its own$and the engine never raises. -
The terminal pressing a Button a test rendered: the
ui.presschain over every plugin hooked on it, the Button's ownonPressat the bottom. -
The checks on a value (
expect(received)), and with them the matchers that stand inside an expected value (expect.any(Number)). -
What
expect(received)answers: the checks, their negation, and the checks on what a promise received resolves or rejects with. -
expect(received, message?): the checks on a value, a message of the test's own leading a failure's. -
The checks
expect(received)offers; each throws an AssertionError when it fails, naming what was expected and what was received. -
The matchers that stand inside an expected value, each matching received there by a rule instead of by equality.
-
The world beneath the plugins, mocked noun by noun: each member registers hooks of the test's on
on, visible where the test calls it. -
The clock
mock.clockhands back: the time its hooks answer, and the only ways it moves. -
Where a mocked clock starts:
now, in milliseconds (0 when not given). -
A set of checks and, under
not, the same set passing where they fail. -
Written inline in a test and loaded as a plugin folder is: its name, the tier it loads in (
userwhen not given), and its hooks module'sregister. -
Whose element: the plugin whose hook drew it, stamped by the runtime as the tree leaves it; a Box's or Text's
group, a Client's or Raster's own. -
A tier a plugin loads in: every tier but the engine's own.
-
What
$.ui.presstakes: the plugin whoseui.renderhook drew the Button, thekeyit gave it, and the instance when it drew one in several. -
The props of
Raster, the terminal surface's cell-grid leaf: a fixed box of cells, each a glyph, a foreground and a background, packed incells. -
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. -
What
$.session.usage(args)takes: nothing for the status line's figures alone;breakdownto have the window broken down as /context breaks it. -
Which transcript the person has on screen where a site draws: the main conversation's, or one agent's, opened from the tasks list.
-
The shape a
Boxand aTextshare in a render tree: allowlisted props, an optionalhover, the group stamp ahover.scopeearns, and children. -
A test: the engine's
$, andon, a plugin's registrar, whose hooks sit beneath every plugin; beneath them the bottom hook throws, naming its event. -
What
testtakes beside its name: the inline plugins it loads beside the one under test, and how long it may run (5000 ms when not given). -
What follows a test's name: its body, or its options then its body.
-
What
toThrowcompares the thrown error with: a substring or pattern of its message, its class, a value carrying the whole message, or nothing. -
What a plugin's
$.ui.blit(args)takes: which of its mounted Rasters to repaint, in which of its sites, and the cells to paint it with. -
What
$.ui.blitresolves to and what aui.blithook's{ value }holds:{}once the cells are the Raster's next frame, or why not. -
What 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. -
The render components whose site keeps a focus ring: a pane's body and the band above the prompt, each a ring over the elements hooks drew there.
-
The input of
ui.focus: a site's focus ring about to move onto one of the elements a hook drew in it (aButton,InputorSelect), or off them. -
Who moves the ring at
ui.focus, as the engine stamps it where the move starts; a closed set a matcher narrows on. -
What a
ui.focushook returns, whatnext(e)resolves to, and what$.ui.focushands back:{}once the ring moved, or why it did not. -
What a plugin's
$.ui.scroll(args)takes: what to bring into view, in which of its sites, and where in the window it lands. -
Where in its scrollable a revealed row lands, as the DOM's
scrollIntoView({ block })names it. -
The render components whose site the engine scrolls: a pane's body and the band above the prompt, each a window over the tree a hook drew there.
-
The input of
ui.scroll: a site's window asked to move over the tree a hook drew in it (a pane's body, the band above the prompt). -
Who moves the window at
ui.scroll, as the engine stamps it where the move starts; a closed set a matcher narrows on. -
The cell the pointer was over when the person's wheel raised
ui.scroll, in the site's body: the box itsui.renderhook draws into, as painted. -
What a
ui.scrollhook returns, whatnext(e)resolves to, and what$.ui.scrollhands back:{}once the window moved, or why it did not. -
What
$.ui.scrollbrings into view: never a row number, always a thing drawn somewhere. -
An error-like value
toThrowcompares by its whole message. -
A group of tests: its name leads the title of each test declared inside, and its body runs at once, while the file loads.
-
Checks a value:
expect(received).toEqual(expected)throws an AssertionError naming both sides when it fails, a message given leading. -
The world beneath the plugins, mocked noun by noun:
mock.clock,mock.storeandmock.env. -
One test: it passes when its body returns or resolves, and fails when it throws, rejects or outlasts its time (5000 ms, or
timeoutMs). -
Says which tier the plugin under test loads in, once, at the top of the file:
prepend,user(when unsaid),appendorbuiltin.
16 docs only: reworded, same shape
$.clocknounThe time and timers, each an event through the host:
clock.nowreads the time;clock.sleep,afterandeverywait until it has passed.$.clock.afterverbCalls
fnonce aftermsmilliseconds;cancel()before then stops it.$.clock.everyverbCalls
fneverymsmilliseconds (at least 1) untilcancel().$.uinounDisplay: a line under an open dialog, a redraw or a repaint, a transcript line, a pane the surface places, a window or a ring moved.
$.ui.closeverbCloses one of the open panes; an id that is not open is left alone.
$.ui.invalidateverbRe-runs an event whose results the engine caches:
ui.renderdraws the instances this plugin may draw again; the others drop the cached answers.$.ui.openverbOpens a pane: a framed region the surface places, whose body this plugin draws by hooking
ui.renderfor{ component: "Pane" }.turn.stepeventFires when the engine is about to send a model request of a turn, main's or a subagent's (
e.agentId);next(e)resolves to the whole response.AgentSpawnInputtypeThe input of
agent.spawn: what the Agent tool decided about the subagent it is about to start, before its model is resolved.BoxPropstypeThe props of
Box: the layout, margin, padding and border props of Ink's Box a tree may set, and the two of hover.ConfigRowtypeOne
/configrow as$.config.list()returns it: what the menu would draw now, after everyconfig.describehook, a hidden row left out.PaneCloseOrigintypeWhy a pane closes, as the engine stamped it at
ui.close.PluginOptionstypeA plugin's options as
register(on, options)receives them: the values of the fields its manifest'suserConfigdeclares, defaults filled in.RenderViewporttypeThe size of what a surface draws into, in character cells of the surface's monospace metric: on the terminal, the conversation's columns and screen rows; on a remote surface, the pane's width and height divided by the advance and line height of its code font. A pixel-sized companion arrives with the first element that lays out in pixels; until then every element on every surface is cell-based, and so is this.
TextPropstypeThe props of
Text: the color and style props of Ink's Text a tree may set. Colors are a theme key or a raw color.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.270
No change to the surface since 2.1.269v2.1.269
+60 added · 0 removed · 16 changed · 22 docs only since 2.1.268The engine
-
Every row of the settings menu (
/config), the panel's own and each enabled plugin'suserConfigfields alike: listing and changing them. -
Returns the rows the
/configmenu would draw now, in its order, each with its current value, its kind, its owner and its lock. -
Changes one row as if the person did in the menu: the event
config.setwithorigin{ kind: 'plugin', name }, then the writer. -
Returns every surface the session draws on, each once:
terminalunder the REPL first, thendesktopandmobilein the order they attached. -
Asks the engine's permission decision for a tool call now: the event
tool.check, resolved to{ decision, reason?, rule? }.
Events
-
Fires once per
/configrow, when the menu lists it and for$.config.list;next(e)resolves to{ label, description, isHidden }. -
{ label, description, isHidden }. -
The argument of
$.config.list(). -
Fires when a
/configrow is about to change, from the menu or a plugin's$.config.set;next(e)resolves to{ value }once written. -
{ value }once written, or{ deny }. -
Fires once per hooks module about to join the chain, at load (the set folded and built, nothing swapped in) and at reload; core allows.
-
{ allow: true }, or{ refuse }. -
Fires when a remote client joins the session's roster of attached surfaces: it said so (ui_attach), or it first asked to draw.
-
{ clientId }. -
Fires when a client leaves the roster: it detached, or the session ended with it attached (
e.reason). Observe;next(e)echoes{ clientId }. -
{ clientId }. -
The argument of
$.session.surfaces(). -
Fires when the engine decides whether a tool call may run, after the
tool.calland PreToolUse hooks and before the mode settles an ask. -
{ decision, reason?, rule? }.
Types
-
agent.spawn's input as the call takes it: what the Agent tool's caller says; the engine fills the rest.export type AgentSpawnArgs = Pick<AgentSpawnInput, 'prompt'> & Partial<Pick<AgentSpawnInput, 'description' | 'subagentType' | 'model' | 'name' | 'cwd' | 'background'>>;export type AgentSpawnArgs = Pick<AgentSpawnInput, 'prompt'> & Partial<Pick<AgentSpawnInput, 'description' | 'subagentType' | 'model' | 'name' | 'cwd'>>; -
What an
agent.spawnhook returns and whatnext(e)resolves to: the started subagent's{ model, agentId }, or{ deny: reason }, refusing it.export type AgentSpawnResult = { model: string; text?: string; isError?: true; agentId?: string; deny?: undefined;} | { deny: string; model?: undefined; text?: undefined; isError?: undefined; agentId?: undefined;}; -
The handler
on(...).catch(handler)takes for a hook of typeF: the hook's($, e, next), run afresh when it throws, misreturns or overruns.export type CatchHandler<F> = F extends ($: infer D, e: infer E, next: infer N) => infer R ? ($: D, e: E, next: N & Caught) => R | undefined | Promise<Awaited<R> | undefined> : never;export type CatchHandler<F> = F extends ($: infer D, e: infer E, next: infer N) => infer R ? [R] extends [AsyncGenerator<unknown, unknown, unknown>] ? ($: D, e: E, next: N & Caught) => R : ($: D, e: E, next: N & Caught) => R | undefined | Promise<Awaited<R> | undefined> : never; -
command.run's input as a plugin's$.command.runtakes it:argsmay be left out (/command, bare), andoriginis the engine's to set.export type CommandRunArgs = Omit<CommandRunInput, 'origin'>;export type CommandRunArgs = Omit<CommandRunInput, 'origin' | 'args'> & { args?: string;}; -
The engine's own events as calls on
$, one signature each:$.<noun>.<event>(input)resolves to its result, or to its stream.export type EventCalls = { tool: { call: ToolCallOverloads; check: (input: ToolCheckArgs) => Promise<ToolCheckResult>; describe: (input: ToolDescribeInput) => Promise<ToolDescribeResult>; }; command: { run: (input: CommandRunArgs) => Promise<CommandRunResult>; describe: (input: CommandDescribeInput) => Promise<CommandDescribeResult>; }; config: { set: (input: ConfigSetArgs) => Promise<ConfigSetResult>; describe: (input: ConfigDescribeInput) => Promise<ConfigDescribeResult>; }; prompt: { submit: (input: PromptSubmitArgs) => Promise<PromptSubmitResult>;… start: (input: SessionStartInput) => Promise<SessionStartResult>; receive: (input: SessionReceiveInput) => Promise<SessionReceiveResult>; compact: (input?: SessionCompactArgs) => Promise<SessionCompactResult>; attach: (input: SessionAttachInput) => Promise<SessionAttachResult>; detach: (input: SessionDetachInput) => Promise<SessionDetachResult>; }; turn: { start: (input: TurnStartInput) => Promise<TurnStartResult>; step: (input: TurnStepInput) => Promise<TurnStepResult>; step: (input: TurnStepInput) => HookStream<TurnStepChunk, TurnStepResult>; complete: (input: TurnCompleteInput) => Promise<TurnCompleteResult>; }; ui: { -
The hook signature of each event,
($, e, next), as one mapped type over EventOf; a streaming event's is the generator form (StreamHook).export type Events = { [E in keyof EventOf]: ($: E extends 'engine.create' ? NoEngineInterface : EngineInterface, e: Frozen<Args<E>>, next: Next<E>) => EventResult<E> | Promise<EventResult<E>>; [E in keyof EventOf]: E extends StreamingEventName ? StreamHook<E> : ($: E extends 'engine.create' ? NoEngineInterface : EngineInterface, e: Frozen<Args<E>>, next: Next<E>) => EventResult<E> | Promise<EventResult<E>>;}; -
What
$.ui.invalidatetakes: a render event, or one of the five events whose answers the engine caches for the session.export type InvalidatableEventName = RenderEventName | 'prompt.section' | 'prompt.context' | 'tool.describe' | 'command.describe';export type InvalidatableEventName = RenderEventName | 'prompt.section' | 'prompt.context' | 'tool.describe' | 'command.describe' | 'config.describe'; -
The hook
on(pattern, matcher, hook)takes:($, e, next)withenarrowed by the matcher (MatchedEvent), and a tagged result the same way.export type MatchedHook<P extends Pattern, M> = ($: EngineInterface, e: Frozen<MatchedEvent<P, M>>, next: Next<MatchedNames<P, M>, KeptEvent<P, M>, MatchedResult<P, M>, {export type MatchedHook<P extends Pattern, M> = P extends StreamingEventName ? MatchedStreamHook<P, M> : ($: EngineInterface, e: Frozen<MatchedEvent<P, M>>, next: Next<MatchedNames<P, M>, KeptEvent<P, M>, MatchedResult<P, M>, { [K in MatchedNames<P, M>]: Narrowed<Args<K>, M>;}>) => MatchedResult<P, M> | Promise<MatchedResult<P, M>>; -
What each call on
$answers (thevalueof its event's result), by event name.'session.messages': SessionMessage[]; 'session.repo': SessionRepo | null; 'session.surface': RenderSurface | null; 'session.surfaces': readonly RenderSurface[]; 'session.authorize': SessionAuthorization; 'session.usage': SessionUsage; 'turn.abort': void;… 'command.register': { command: string; }; 'config.list': ConfigRow[]; 'agent.list': AgentInfo[]; 'ui.toast': void; 'ui.status': void; -
prompt.submit's input as a plugin's call takes it:origin,turnIdandwaitare the engine's to set,contextthe hooks' to attach.export type PromptSubmitArgs = Omit<PromptSubmitInput, 'origin' | 'turnId' | 'wait'>;export type PromptSubmitArgs = Omit<PromptSubmitInput, 'origin' | 'turnId' | 'wait' | 'context'>; -
The input of
prompt.submit: the prompt as typed, after the input became a user message and before it enters the session.export type PromptSubmitInput = { text: string; attachments?: readonly PromptAttachment[]; context?: readonly string[]; turnId?: string; wait: boolean; origin: PromptOrigin; -
The plain-data props of each renderable component, as
ui.rendersees them undere.props; a hook rewrites them withnext({ ...e, props }).title: string; isFocused: boolean; bodyColumns: number; placement: 'dock' | 'inline'; scroll: SiteScroll; };}; -
One settled run of a link beneath the caller, as
next.tracelists it: data, not a handle.readonly outcome: TraceOutcome; readonly reason?: string; readonly ms: number; readonly chunks?: number; readonly received: E; readonly returned: O | undefined;}; -
What every
turn.completecarries whatever its reason: the answer, the duration, the interrupt flag, the turn's id, its loop and what it cost.durationMs: number; isAborted: boolean; turnId: string; agentId?: string; usage?: TurnUsage;}; -
The 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.export type TurnStepInput = { turnId: string; index: number; answer: string; toolUses: readonly TurnStepToolUse[]; stopReason: 'end_turn' | 'max_tokens' | 'stop_sequence' | 'tool_use' | 'pause_turn' | 'compaction' | 'refusal' | 'model_context_window_exceeded'; usage?: TurnUsage; model: string; effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max' | number; messageCount: number;}; -
What a
turn.stephook returns and whatnext(e)resolves to: the model's response to the step's request, once its blocks are all in.export type TurnStepResult = { turnId: string; index: number; usage?: TurnUsage; answer: string; toolUses: readonly TurnStepToolUse[]; stopReason: TurnStopReason; usage: TurnUsage | null;}; -
What a hook on streaming event
Nyields, and what itsnext(e)yields to it (ChunkOf by name). -
The chunk type of each streaming event, by name: what its stream yields.
-
What every
turn.stepchunk may carry: the engine's handle on the item of its own stream the chunk was read off, absent on a chunk a hook made. -
The input of
config.describe: how one/configrow presents, at the moment the menu lists it (and for$.config.list). -
What a
config.describehook returns: the label, help text and hidden flag the menu uses; the key and provider stay as they were. -
How a
/configrow takes its value:booleantoggles,choicepicks one of itsoptions,texttakes a string,numbera number. -
Where a
config.setcame from, inprompt.submit's words: the person in the/configmenu (composer), the bridge, or a plugin, named. -
One
/configrow as$.config.list()returns it: what the menu would draw now, after everyconfig.describehook, a hidden row left out. -
config.set's input as a plugin's$.config.set(args)takes it: the row's key and the value; the engine fills the rest. -
The input of
config.set: one/configrow about to change, from the menu or a plugin's$.config.set, with what it holds now and who owns it. -
What a
config.sethook returns and whatnext(e)resolves to:{ value }once written, or{ deny: reason }, the row left as it was. -
A
/configrow's value as a hook and$.configsee it: a toggle's boolean, a choice's or a text's string, a number, or a list of strings. -
The hook event
Etakes: an async generator over its chunks for a streaming event (turn.step),($, e, next) => resultfor every other. -
What
next(e)returns on a streaming event: the stream of everything beneath, chunk by chunk, whose return value is the result from beneath. -
The hook
on(event, matcher, hook)takes on a streaming event: the generator form,enarrowed by the matcher,next(e)the stream beneath. -
What a matched streaming hook's
next.is(pattern, e)narrowseto: the streaming event's argument narrowed by the matcher. -
A matched streaming hook's
next: the variants the matcher keeps, the result tagged the same way,next.isnarrowing as the matcher does. -
The input of
plugin.register: one hooks module the engine is about to load, read off its manifest and its scanned source. Every field is pinned. -
What a
plugin.registerhook returns and whatnext(e)resolves to:{ allow: true }from core, or{ refuse: reason }. -
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. -
The input of
session.attach: a surface joined the session's roster of attached clients (a phone opened the session; the desktop app connected). -
What a
session.attachhook returns and whatnext(e)resolves to:{ clientId }, echoed by core; a hook's own value changes nothing. -
The input of
session.detach: a client left the session's roster. Every field is the engine's: a hook observes, andnext(e)passes them on. -
Why a client left the roster:
detach, it said so (ui_detach);end, the session ended with it still attached. -
What a
session.detachhook returns and whatnext(e)resolves to:{ clientId }, echoed by core; a hook's own value changes nothing. -
The hook a streaming event takes:
async function* ($, e, next) {}, yielding the event's chunks and returning its result. -
What a hook on a streaming event evaluates to: the async generator an
async function*makes, yieldingCand returningRor nothing. -
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. -
The events that stream: their hooks are async generators,
next(e)is the stream of everything beneath, and the result is what it returns. -
tool.check's input as$.tool.checktakes it: the tool and its arguments;tool_use_idis the engine's to set, never a query's. -
The verdict of
tool.check: run the tool, put it to the mode's decider (the dialog, the auto-mode classifier, a headless host), or refuse it. -
The input of
tool.check: the tool, its arguments, and the call's id when the engine is deciding a real call. -
What a
tool.checkhook returns and whatnext(e)resolves to: the verdict, why, and the settings rule behind it when one decided. -
One piece of a
turn.stepresponse as it streams through the chain: what a hook'snext(e)yields and what the hook yields up in turn. -
An item of the engine's stream the other chunk kinds do not model (the envelope, a block's start and end, a retry marker), opaque by
ref. -
A piece of a tool call's arguments as they arrive: JSON text, partial, for the
toolchunk of the sameindex. -
The response is whole: why the model stopped and what the request cost, as the step's result will carry them. The last chunk of one response.
-
A piece of the response's visible text as it arrives, in block
index. -
A piece of the model's thinking as it arrives, in block
index: what the person sees of it live. -
The model begins a tool call in block
index: the tool's name and the call's id; its arguments follow asinputchunks of the same index. -
Why the model stopped, as a
turn.stepresult and its stop chunk carry it: one of the API's stop reasons, or null when no response arrived.
22 docs only: reworded, same shape
$.agent.spawnverbSpawns a subagent: the event
agent.spawn, the same call the engine makes when the Agent tool starts one; the engine fills the rest.$.command.runverbRuns a slash command as if the person typed
/command args: the eventcommand.run, queued and run once the session is idle.$.session.surfaceverbReturns the first of
$.session.surfaces(), or null where nothing draws.$.ui.closeverbCloses one of the open panes; an id that is not open is left alone.
$.ui.invalidateverbRe-runs an event whose results the engine caches:
ui.renderdraws the instances this plugin may draw again; the others drop the cached answers.$.ui.openverbOpens a pane: a framed region the surface places, whose body this plugin draws by hooking
ui.renderfor{ component: "Pane" }.turn.stepeventFires when the engine is about to send one model request of the main thread's turn;
next(e)sends it and resolves to the whole response.turn.stepresultThe response:
{ turnId, index, answer, toolUses, stopReason, usage }.ui.closeeventThe argument of
$.ui.close({ id })withoriginplugin; the engine raises it too, for the person (person) and an unload (unload).ClientModuletypeThe component a surface module exports (default, or its one PascalCase export): from props and surface to the tree drawn (no nested
Client).ClientPropstypeThe props of
Client: which of the plugin's surface modules draws here, under what key, with what data, in how much room.CommandRunResulttypeWhat a
command.runhook returns and whatnext(e)and$.command.runresolve to: the command's output text, when it has one.ElementstypeThe element constructors each surface draws, by
e.surface: what$.ui.resolve(e)returns and aui.resolvehook passes on; no globals.PaneCloseOrigintypeWhy a pane closes, as the engine stamped it at
ui.close.PaneOpenArgstypeThe argument of
$.ui.open: which pane, its title, and whether the plugin asks the person's keyboard for it.PromptSubmitResulttypeWhat a
prompt.submithook returns and whatnext(e)resolves to: the prompt that entered,{ text, context?, origin? }, or{ drop: reason }.RenderElementtypeWhat a render hook returns, and what
next(e)resolves to: a plain-data tree of elements, strings allowed as children of Text and Box.RenderInputOftypeOne
ui.renderinput, for a component narrowed to one surface.SessionReceiveResulttypeWhat a
session.receivehook returns and whatnext(e)resolves to: the delivery that was queued,{ text }, or{ consumed: reason }.SessionStartInputtypeThe input of
session.start: the session the process starts with, read the way$.sessionreads it at that moment.TurnCompleteResulttypeWhat a
turn.completehook returns and whatnext(e)resolves to:{ text }; a text other than a main-loop answer's is shown beneath it.UiMessageArgumenttypeThe argument of
ui.message: what aClientinstance's surface module posted (surface.post(data)), addressed by where the instance is drawn.
v2.1.268
+24 added · 6 removed · 53 changed · 46 docs only since 2.1.267The engine
- removed
$.session.turnCountverb breakingReturns how many prompts the user has sent this session (user turns in the transcript).
-
Runs one tool-less completion over the session's OWN transcript, sharing the main thread's prompt cache; the reply's text and the fork's usage.
(request: ModelForkRequest) => Promise<ModelForkReply | null>(request: ModelForkRequest) => Promise<ModelForkResult | null> -
Asks the user
questionin the engine's own AskUserQuestion dialog and resolves to the label they chose, or the text typed under "Other".(question: string, options?: readonly string[] | AskProps) => Promise<string>(question: string, options?: readonly string[] | AskOptions) => Promise<string> -
Writes
input.textinto the prompt box as the person's draft, cursor at its end, replacing what it held: the eventprompt.fill. -
Proposes
input.textas the prompt box's dim suggestion, Tab to take: the eventprompt.suggest, as the engine's own guess after a turn. -
Holds the session's Anthropic credential on the host and answers an opaque handle and its kind; the secret never reaches the plugin.
-
Returns how many prompts the user has sent this session (user turns in the transcript).
Events
- removed
session.turnCountevent breakingThe argument of
$.session.turnCount(). -
Fires when a
Buttona render hook drew is pressed on a surface;eis{ plugin, element, component, surface },elementthe button'skey.UiPressInputUiPressArgument -
Fires when a text is about to be written into the prompt box as the person's draft (a plugin's
$.prompt.fill);next(e)writes it. -
{ isFilled }. -
Fires when a text is proposed as the prompt box's dim suggestion, Tab to take: the engine's guess after a turn, or a plugin's
$.prompt.suggest. -
{ isShown }. -
The argument of
$.session.authorize(). -
The argument of
$.session.turns(). -
The argument of
$.tool.register(spec).
Types
- removed
AskPropstype breakingOptions of
$.ui.ask. - removed
ModelForkReplytype breakingWhat
$.model.forkresolves to when the fork answered: the reply's text and what the fork cost. - removed
RenderAnswerOptionstype breakingHow a site instance asks for its
ui.renderanswer: the version it is on, whether a static frame is drawing, and whose submit it serves. - removed
UiPressInputtype breakingThe argument of
ui.press: a press on aButtona render hook drew. Flat and frozen like every event's. -
The input of
command.describe: how one slash command presents in the typeahead and/help, at the moment the engine lists it.type CommandDescribeInput = {export type CommandDescribeInput = { command: string; description: string; argumentHint?: string; -
What a
command.describehook returns: the description, hint and hidden flag the menu uses; the name,immediateandproviderstay as they were.type CommandDescribeResult = Omit<CommandDescribeInput, 'command' | 'immediate' | 'provider'>;export type CommandDescribeResult = Omit<CommandDescribeInput, 'command' | 'immediate' | 'provider'>; -
One slash command as
$.command.list()returns it.type CommandInfo = {export type CommandInfo = { name: string; description: string; source: CommandSource; -
command.run's input as a plugin's$.command.runtakes it:originis the engine's to set (the calling plugin's name).type CommandRunArgs = Omit<CommandRunInput, 'origin'>;export type CommandRunArgs = Omit<CommandRunInput, 'origin'>; -
The input of
command.run: one slash command about to run, the way the person typed it (/name args), and where the run came from.type CommandRunInput = {export type CommandRunInput = { command: string; args: string; origin: PromptOrigin; -
What a
command.runhook returns and whatnext(e)and$.command.runresolve to: the command's output text, when it has one.type CommandRunResult = {export type CommandRunResult = { text?: string; ref?: number;}; -
Where a slash command comes from, as
$.command.list()tells them apart.type CommandSource = 'builtin' | 'plugin' | 'user' | 'mcp';export type CommandSource = 'builtin' | 'plugin' | 'user' | 'mcp'; -
What
$.command.registertakes: the slash command this plugin serves.type CommandSpec = {export type CommandSpec = { name: string; description: string; argumentHint?: string; -
The element constructors each surface draws, by
e.surface: what$.ui.resolve(e)returns and aui.resolvehook passes on; no globals.Code: ElementConstructor<CodeProps>; Client: ElementConstructor<ClientProps>; }; mobile: { Box: ElementConstructor<BoxProps>; Text: ElementConstructor<TextProps>; Button: ElementConstructor<ButtonProps>; Svg: ElementConstructor<SvgProps>; Link: ElementConstructor<LinkProps>; Code: ElementConstructor<CodeProps>; };}; -
The engine's own events as calls on
$, one signature each:$.<noun>.<event>(input)dispatches the event and resolves to its result.}; prompt: { submit: (input: PromptSubmitArgs) => Promise<PromptSubmitResult>; fill: (input: PromptFillArgs) => Promise<PromptFillResult>; suggest: (input: PromptSuggestArgs) => Promise<PromptSuggestResult>; section: (input: PromptSectionInput) => Promise<PromptSectionResult>; context: (input: PromptContextInput) => Promise<PromptContextResult>; }; -
The hook signature of each event,
($, e, next), as one mapped type over EventOf.export type Events = { [E in keyof EventOf]: ($: E extends 'engine.create' ? NoEngineInterface : EngineInterface, e: Args<E>, next: Next<E>) => EventResult<E> | Promise<EventResult<E>>; [E in keyof EventOf]: ($: E extends 'engine.create' ? NoEngineInterface : EngineInterface, e: Frozen<Args<E>>, next: Next<E>) => EventResult<E> | Promise<EventResult<E>>;}; -
The hook
on(pattern, hook)takes for a glob or a negation: one function placed on every selected event,eand the result typed as their union.export type GlobHook<P extends Pattern, N extends EventName = Selected<P>> = ($: EngineInterface, e: Args<N>, next: GlobNext<P>) => EventResult<N> | Promise<EventResult<N>>;export type GlobHook<P extends Pattern, N extends EventName = Selected<P>> = ($: EngineInterface, e: Frozen<Args<N>>, next: GlobNext<P>) => EventResult<N> | Promise<EventResult<N>>; -
nextin a hook on a glob or a negation: an overload per selected event, then one over their union for anenot yet narrowed.(e: Args<N>): Promise<GlobNextResult<N>>; readonly to: (e: Args<N>, tier: TargetTier) => Promise<GlobNextResult<N>>; readonly signal: AbortSignal; readonly is: <M extends PatternOver<N>>(pattern: M, e: unknown) => e is Args<Extract<N, Selected<M>>>; readonly is: <M extends PatternOver<N>>(pattern: M, e: unknown) => e is Frozen<Args<Extract<N, Selected<M>>>>; readonly event: N; readonly origin: Origin; readonly trace: readonly TraceEntry<N, Args<N>, GlobNextResult<N>>[]; -
Options of
$.http.fetch.method?: string; headers?: Record<string, string>; body?: string; auth?: string;}; -
The hook
on(pattern, matcher, hook)takes:($, e, next)withenarrowed by the matcher (MatchedEvent), and a tagged result the same way.export type MatchedHook<P extends Pattern, M> = ($: EngineInterface, e: MatchedEvent<P, M>, next: Next<MatchedNames<P, M>, KeptEvent<P, M>, MatchedResult<P, M>, {export type MatchedHook<P extends Pattern, M> = ($: EngineInterface, e: Frozen<MatchedEvent<P, M>>, next: Next<MatchedNames<P, M>, KeptEvent<P, M>, MatchedResult<P, M>, { [K in MatchedNames<P, M>]: Narrowed<Args<K>, M>;}>) => MatchedResult<P, M> | Promise<MatchedResult<P, M>>; -
The rest of the chain, as one hook receives it: made once per dispatch per hook, frozen;
next(e)resolves to the downstream result.(e: E, tier: TargetTier): Promise<O>; }; readonly signal: AbortSignal; readonly is: <M extends PatternOver<N>>(pattern: M, e: unknown) => e is S[Extract<N, Selected<M>>]; readonly is: <M extends PatternOver<N>>(pattern: M, e: unknown) => e is Frozen<S[Extract<N, Selected<M>>]>; readonly event: N; readonly origin: Origin; readonly trace: readonly TraceEntry<N, E, O>[]; -
What each call on
$answers (thevalueof its event's result), by event name.export type OpValueOf = { 'model.complete': string; 'model.classify': string | undefined; 'model.fork': ModelForkReply | null; 'model.fork': ModelForkResult | null; 'audio.play': void; 'audio.speak': SpeakResult; 'mcp.call': McpToolResult; 'session.cwd': string; 'session.model': string; 'session.turnCount': number; 'session.turns': number; 'session.id': string; 'session.messages': SessionMessage[]; 'session.repo': SessionRepo | null; 'session.surface': RenderSurface | null; 'session.authorize': SessionAuthorization; 'session.usage': SessionUsage; 'turn.abort': void; 'tool.list': ToolInfo[]; -
Who raised a dispatch, as
next.originholds it: the calling plugin's name and the tier it sits in; the engine readsengineincore.type Origin = {export type Origin = { readonly plugin: string; readonly tier: Tier;}; -
The argument of
$.ui.close: the pane to close ({ id }).originis the engine's to set: a plugin's call readspluginat the hooks.type PaneCloseArgs = Omit<PaneCloseInput, 'origin'>;export type PaneCloseArgs = Omit<PaneCloseInput, 'origin'>; -
The input of
ui.close: the pane closing and why (PaneCloseOrigin). Closing an id that is not open does nothing.type PaneCloseInput = {export type PaneCloseInput = { id: string; origin: PaneCloseOrigin;}; -
Why a pane closes, as the engine stamped it at
ui.close.type PaneCloseOrigin = 'plugin' | 'person' | 'unload';export type PaneCloseOrigin = { kind: 'plugin' | 'person' | 'unload';}; -
The argument of
$.ui.open: which pane, its title, and whether the plugin asks the person's keyboard for it.type PaneOpenArgs = {export type PaneOpenArgs = { id: string; title?: string; focus?: true; -
Options of
$.process.run.type ProcessRunInit = {export type ProcessRunInit = { cwd?: string; env?: Record<string, string>; stdin?: string; -
What
$.process.runresolves with once the child has exited.type ProcessRunResult = {export type ProcessRunResult = { exitCode: number; stdout: string; stderr: string; -
What an element takes as
children, as JSX passes them: a node, a number (drawn as its string), a value the factory drops, or a list that may nest.export type RenderChildren = RenderNode | readonly RenderChildren[];export type RenderChildren = RenderNode | number | boolean | null | undefined | readonly RenderChildren[]; -
The plain-data props of each renderable component, as
ui.rendersees them undere.props; a hook rewrites them withnext({ ...e, props }).export type RenderPropsOf = { AskUserQuestion: { toolName: string; tool: string; questions: unknown[]; metadataSource?: string; };… }; AssistantMessage: { text: string; firstOfReply: boolean; isFirstOfReply: boolean; }; ToolUse: { tool_use_id: string; toolName: string; tool: string; input: unknown; running: boolean; errored: boolean; interrupted: boolean; isRunning: boolean; isErrored: boolean; isInterrupted: boolean; output?: unknown; }; ToolResult: { tool_use_id: string; toolName: string; tool: string; output: unknown; errored: boolean; isErrored: boolean; }; ToolGroup: { calls: ReadonlyArray<ToolGroupCall>; active: boolean; expanded: boolean; isActive: boolean; isExpanded: boolean; }; Spinner: { word: string;… }; Pane: { title: string; focused: boolean; isFocused: boolean; bodyColumns: number; scroll: SiteScroll; }; -
Where a render event's component is drawn:
terminalis Ink, which draws the hook's whole tree;desktop(Claude Code Desktop) andmobile(the Claude mobile app) are remote surfaces that draw the tree themselves.export type RenderSurface = 'terminal' | 'desktop';export type RenderSurface = 'terminal' | 'desktop' | 'mobile'; -
type SDKAssistantMessageError = 'authentication_failed' | 'oauth_org_not_allowed' | 'account_on_hold' | 'billing_error' | 'rate_limit' | 'overloaded' | 'invalid_request' | 'model_not_found' | 'server_error' | 'unknown' | 'max_output_tokens' | 'cloud_credential_error';type SDKAssistantMessageError = 'authentication_failed' | 'oauth_org_not_allowed' | 'account_on_hold' | 'verification_required' | 'billing_error' | 'rate_limit' | 'overloaded' | 'invalid_request' | 'model_not_found' | 'server_error' | 'unknown' | 'max_output_tokens' | 'cloud_credential_error'; -
The live context window as the status line reads it: the last API response's input side against the model's window.
type SessionContextUsage = {export type SessionContextUsage = { tokens?: number; window: number; percent?: number; -
What the session has cost, as
/costand the status line total it.type SessionCost = {export type SessionCost = { usd: number;}; -
One rate-limit window as the rate-limit notices read it.
type SessionRateLimit = {export type SessionRateLimit = { kind: string; percentUsed: number; resetsAt?: 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 = 'bridge' | 'task-notification' | 'scheduled-trigger' | 'peer' | 'peer-send-message' | 'projects-relay' | 'slack-ping' | 'unclassified';export type SessionReceiveOrigin = { kind: 'bridge' | 'task-notification' | 'scheduled-trigger' | 'peer' | 'peer-send-message' | 'projects-relay' | 'slack-ping' | 'unclassified';}; -
The input of
session.start: the session the process starts with, read the way$.sessionreads it at that moment.export type SessionStartInput = { cwd: string; surface: RenderSurface | null; interactive: boolean; isInteractive: boolean;}; -
What
$.session.usage()answers: the context window's fill, the account's rate-limit windows and the session's cost, as the status line has them.type SessionUsage = {export type SessionUsage = { context: SessionContextUsage; rateLimits: SessionRateLimit[]; cost?: SessionCost; -
What
$.settings.readanswers: an object keyed as a settings.json is (permissions,env,hooks,model,enabledPlugins, ...).type Settings = Readonly<Record<string, unknown>>;export type Settings = Readonly<Record<string, unknown>>; -
What
$.settings.read(args)takes.type SettingsReadArgs = {export type SettingsReadArgs = { source?: SettingsSource;}; -
One source of settings by the name a plugin gives it, lowest precedence first; the engine's own name is the same word with
Settingsappended.type SettingsSource = 'user' | 'project' | 'local' | 'flag' | 'policy';export type SettingsSource = 'user' | 'project' | 'local' | 'flag' | 'policy'; -
Where a site's window sits over the tree a hook drew in it (a pane's body, the band): the engine's to move (the person scrolls), the plugin's to read.
type SiteScroll = {export type SiteScroll = { offset: number; bodyRows: number;}; -
nextin a*hook: the set of events is open at runtime, soeisunknownuntilnext.is(pattern, e)narrows it to events it knows.(e: unknown): Promise<unknown>; readonly to: (e: unknown, tier: TargetTier) => Promise<unknown>; readonly signal: AbortSignal; readonly is: <M extends Pattern>(pattern: M, e: unknown) => e is Args<Selected<M>>; readonly is: <M extends Pattern>(pattern: M, e: unknown) => e is Frozen<Args<Selected<M>>>; readonly event: EventName; readonly origin: Origin; readonly trace: readonly TraceEntry<EventName, unknown, unknown>[]; -
The props of
Svg, the desktop and mobile surfaces' vector leaf: the markup is the element's data, as a string is a Text's, drawn isolated.alt: string; width?: number; height?: number; interactive?: boolean; isInteractive?: boolean;}; -
One tool call of a ToolGroup, as
ui.rendersees it undercalls.export type ToolGroupCall = { tool_use_id?: string; toolName: string; tool: string; input: unknown; running: boolean; errored: boolean; interrupted: boolean; isRunning: boolean; isErrored: boolean; isInterrupted: boolean; output?: unknown;}; -
One tool_result block of a user message.
export type ToolResultSummary = { id: string; tool_use_id: string; text: string; isError: boolean; result?: unknown; -
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).export type ToolUseSummary = { id: string; name: string; tool_use_id: string; tool: string; input: Record<string, unknown>; result?: unknown; text?: string; -
What the chain decided for one link, as
next.tracenames it.type TraceOutcome = 'caught' | 'expired' | 'kept' | 'passed' | 'rejected' | 'returned' | 'skipped';export type TraceOutcome = 'caught' | 'expired' | 'kept' | 'passed' | 'rejected' | 'returned' | 'skipped'; -
What every
turn.completecarries whatever its reason: the answer, the duration, the interrupt flag, the turn's id and what the turn cost.type TurnCompleteFields = { answer: string; durationMs: number; aborted: boolean; isAborted: boolean; turnId: string; usage?: TurnUsage;}; -
What a model turn, or one response inside it, cost as the API reported it: the four token counts (
$.model.fork's usage shape) and the model's id.type TurnUsage = ModelForkUsage & {export type TurnUsage = ModelForkUsage & { model: string;}; -
The argument of
ui.input: a change of, or a submit from, anInputa render hook drew. Flat and frozen like every event's.type UiInputArgument = {export type UiInputArgument = { plugin: string; element: string; component: RenderComponent; requestId: string; surface: RenderSurface; kind: 'change' | 'submit'; value: string; -
What a
ui.inputhook returns and whatnext(e)resolves to.type UiInputResult = {export type UiInputResult = { element: string; value: string;}; -
The argument of
ui.select: a pick from aSelecta render hook drew. Flat and frozen like every event's.type UiSelectArgument = {export type UiSelectArgument = { plugin: string; element: string; component: RenderComponent; requestId: string; surface: RenderSurface; value: string;}; -
What a
ui.selecthook returns and whatnext(e)resolves to.type UiSelectResult = {export type UiSelectResult = { element: string; value: string;}; -
Options of
$.ui.ask. -
Twith every property read-only to every depth, arrays and tuples kept as declared: how a hook'seis typed. -
What
$.model.forkresolves to when the fork answered: the reply's text and what the fork cost. -
prompt.fill's input as a plugin's$.prompt.fill(args)takes it:originis the engine's to set (the calling plugin's name). -
The input of
prompt.fill(prompt-fill/): a text about to be written into the prompt box as the person's draft, replacing what the box holds. -
Who writes the prompt box at
prompt.fill, as the engine stamps it where the write starts; a closed set a matcher narrows on. -
What a
prompt.fillhook returns and whatnext(e)resolves to: whether the text went into the prompt box. -
prompt.suggest's input as a plugin's$.prompt.suggest(args)takes it:originis the engine's to set (the calling plugin's name). -
The input of
prompt.suggest(prompt-suggest/): a text about to be shown dim in the empty prompt box, for Tab (or the right arrow) to take. -
Who proposes the text at
prompt.suggest, as the engine stamps it where the proposal starts; a closed set a matcher narrows on. -
What a
prompt.suggesthook returns and whatnext(e)resolves to: whether the text is now the box's dim suggestion. -
What
$.session.authorize()answers: an opaque handle for the session's Anthropic credential and its kind, or null when there is none to hold. -
The argument of
ui.press: a press on aButtona render hook drew. Flat and frozen like every event's.
46 docs only: reworded, same shape
$.agent.spawnverbSpawns a subagent: the event
agent.spawn, the same call the engine makes when the Agent tool starts one; the engine fills the rest.$.audio.playverbPlays one audio clip, starting now; clips are not queued, so two calls play together (a bed under speech).
$.audio.speakverbSpeaks
textwith the platform's own synthesizer (sayon macOS). Plain text.$.command.runverbRuns a slash command as if the person typed
/command args: the eventcommand.run, queued and run once the session is idle.$.http.fetchverbFetches
urlthrough the host (never the plugin's own network) and resolves{ status, ok, headers, text }once the body is read.$.model.classifyverbPicks one of
labelsfortextwith one completion over$.model.completeand a fixed classifier prompt.$.promptnounSubmitting a prompt the model reads as a user turn, and putting a text in the person's prompt box, written or proposed.
$.prompt.submitverbSubmits a prompt: the event
prompt.submit, the same call the engine makes for a typed prompt;input.textruns when the session is idle.$.session.compactverbCompacts the conversation: the event
session.compactwithtriggerplugin, the same call/compactmakes, between turns.$.session.surfaceverbReturns where the session draws:
terminalunder the REPL,desktopormobileonce a remote surface has asked; null where nothing draws.$.storenounThis plugin's own key-value store, kept between sessions and hot reloads; values are JSON data.
$.tool.callverbCalls a tool: the event
tool.call, the same call the engine makes for the model's tool calls, under atool_use_idof its own.$.ui.invalidateverbRe-runs an event whose results the engine caches:
ui.renderdraws the instances this plugin may draw again; the others drop the cached answers.agent.offereventFires when the engine offers an agent type to the model, in the agent listing and again at dispatch;
next(e)resolves to{ isOffered: true }.agent.offerresult{ isOffered }.AgentOfferInputtypeThe input of
agent.offer: one agent type, at the moment the engine offers it to the model.AgentSpawnInputtypeThe input of
agent.spawn: what the Agent tool decided about the subagent it is about to start, before its model is resolved.AudioCliptypeWhat
$.audio.playplays: a URL the engine fetches, or the bytes.BoxPropstypeThe props of
Box: the layout, margin, padding and border props of Ink's Box a tree may set, and the two of hover.BuiltinToolNametypeThe names of the built-in tools.
ClassicResulttypeEverything a classic hook event's answer can carry, named as the classic hook's JSON output names it; each event reads its subset (ClassicResultOf).
ClientElementstypeThe element table a surface module draws with,
surface.elements: the terminal's constructors (Elements) lessClient(none nests).ClientPropstypeThe props of
Client: which export of the plugin's surface module draws here, under what key, with what data, in how much room.CodePropstypeThe props of
Code, source text every surface draws with the engine's own highlighter: coloured tokens, a line gutter on request, or a unified diff.CoreEventNametypeThe name of an event the engine defines itself (a key of CoreEventOf); EventName adds the declared plugin nouns' events.
ElementChildrentypeThe
childrenfield every element constructor's props carry, appended beside its own props type: one child, or a list that may nest.ElementConstructortypeAn element as
$.ui.resolve(e)hands it out: a constructor from props to the frozen plain-data element,childrenamong the props as JSX passes.EngineCreateInputtypeThe input of
engine.create: the fold that builds$, once per load, core innermost.LinkPropstypeThe props of
Link, a hyperlink every surface draws: an OSC 8 span on the terminal (else its text then the URL in dim), an anchor on desktop.MatcherOnetypeWhat matches one value of type
V, by the runtime's kinds: a scalar leaf takes the value or a RegExp; an object, a partial of it.NarrowDepthtypeHow many object or array levels a matcher narrows
ethrough, counted as a tuple's length: the runtime's own limit, which refuses a deeper matcher.PlayOptionstypeHow
$.audio.playplays a clip: looped untilsignalaborts, or once.PluginNountypeThe nouns a plugin declared on
$by merging into EngineInterface; never one the engine's own events are under (tool,session,ui).PromptOrigintypeWhere a
prompt.submitsubmission came from, as the engine knows it at the site it was queued from; a closed set, never a text prefix.PromptSubmitInputtypeThe input of
prompt.submit: the prompt as typed, after the input became a user message and before the turn starts.PromptSubmitResulttypeWhat a
prompt.submithook returns and whatnext(e)resolves to: the prompt that proceeds,{ text, context?, origin? }, or{ drop: reason }.RenderComponenttypeEverything
ui.rendercan draw: one name per component that has a render site; a matcher narrows on it.RenderElementtypeWhat a render hook returns, and what
next(e)resolves to: a plain-data tree of elements, strings allowed as children of Text and Box.RenderInputOftypeOne
ui.renderinput, for a component narrowed to one surface.RenderViewporttypeThe size of what a surface draws into, in character cells of the surface's monospace metric: on the terminal, the screen's columns and rows; on a remote surface, the pane's width and height divided by the advance and line height of its code font. A pixel-sized companion arrives with the first element that lays out in pixels; until then every element on every surface is cell-based, and so is this.
SessionMessagetypeOne message of the transcript as
$.session.messages()returns it.SpeakRequesttypeThe argument of
$.audio.speak(text, options)as the event carries it.SpeakResulttypeWhat
$.audio.speakresolves with once the utterance has ended.TextPropstypeThe props of
Text: the color and style props of Ink's Text a tree may set. Colors are a theme key or a raw color.ToolCallReservedtypeThe keys
tool.call's input carries beside the tool's own arguments, none of which the tool sees (the engine strips them before the tool runs).ToolCallResulttypeWhat a
tool.callhook returns and whatnext(e)and$.tool.call(input)resolve to: the tool's result ({ result, context? }) or{ deny }.