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.275
+35 added · 0 removed · 19 changed · 12 docs only since 2.1.274The engine
-
Puts
input.textin the prompt box as the draft, bymode:replace(the default) over it,appendafter it,insertat the cursor.EventCalls['prompt']['fill'](input: PromptFillArgs) => Promise<PromptFilled> -
Appends one line to the transcript, drawn like a system notice (dim; not sent to the model), or with
{ to: "debug" }to the debug log alone.(text: string) => void(text: string, options?: UiLogOptions) => void -
Returns the prompt box as it stands, the draft typed so far and the cursor's offset into it, so a
fillcan keep what the person typed. -
Returns the session's project root, absolute: where it started, or where
/cd, a host's directory change or a worktree move took it. -
Lists this plugin's own open panes (UiPane): each one's id and title, and whether it is shown, holds the keyboard, and is placed.
Events
-
The argument of
$.prompt.read(). -
Fires once when the session ends (exit, /clear, resume, logout, signal, a
-prun done), after its SessionEnd settings hooks;e.reasonsays which. -
{ sessionId }. -
Fires when the engine measures the session and a unit moved: after each main-thread turn, and when a rate-limit window moves a whole point.
-
{ changed }. -
The argument of
$.session.root(). -
The argument of
$.ui.panes().
Types
-
The element table a surface module draws with,
surface.elements: the terminal's (Elements) lessClient(none nests),RasterandImage.export type ClientElements = Omit<Elements['terminal'], 'Client' | 'Raster'>;export type ClientElements = Omit<Elements['terminal'], 'Client' | 'Raster' | 'Image'>; -
The element constructors each surface draws, by
e.surface: what$.ui.resolve(e)returns and aui.resolvehook passes on; no globals.Markdown: ElementConstructor<MarkdownProps>; Client: ElementConstructor<ClientProps>; Raster: ElementConstructor<RasterProps>; Image: ElementConstructor<ImageProps>; }; desktop: { Box: ElementConstructor<BoxProps>; -
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 : EngineNoun<N>; [N in keyof EventCalls]: N extends 'ui' ? EngineNoun<N> & EnginePress & EngineMount : EngineNoun<N>;}; -
The engine's own events as calls on
$, one signature each:$.<noun>.<event>(input)resolves to its result, or to its stream.compact: (input?: SessionCompactArgs) => Promise<SessionCompactResult>; attach: (input: SessionAttachInput) => Promise<SessionAttachResult>; detach: (input: SessionDetachInput) => Promise<SessionDetachResult>; measure: (input: SessionMeasureInput) => Promise<SessionMeasureResult>; end: (input: SessionEndInput) => Promise<SessionEndResult>; }; turn: { start: (input: TurnStartInput) => Promise<TurnStartResult>; -
One file
$.fs.ancestorsfound: the directory it stands in, the name it was asked for by, and its text as the engine's memory loader reads it.dir: string; name: string; content: string; parts: readonly FsAncestorPart[];}; -
nextin a hook on a glob or a negation: an overload per selected event, then one over their union for anenot yet narrowed.readonly event: N; readonly origin: Origin; readonly trace: readonly TraceEntry<N, Args<N>, GlobNextResult<N>>[]; readonly budget: NextBudget;}; -
The rest of the chain, as one hook receives it: made once per dispatch per hook, frozen;
next(e)resolves to the downstream result.readonly event: N; readonly origin: Origin; readonly trace: readonly TraceEntry<N, E, O>[]; readonly budget: NextBudget;}; -
What each call on
$answers (thevalueof its event's result), by event name.'audio.speak': SpeakResult; 'mcp.call': McpToolResult; 'session.cwd': string; 'session.root': string; 'session.model': string; 'session.turns': number; 'session.id': string;… 'session.authorize': SessionAuthorization; 'session.usage': SessionUsage; 'turn.abort': void; 'prompt.read': PromptBox; 'tool.list': ToolInfo[]; 'tool.register': { tool: string;… 'ui.invalidate': void; 'ui.open': void; 'ui.close': void; 'ui.panes': readonly UiPane[]; 'ui.blit': UiBlitResult; 'fs.read': string; 'fs.write': void; -
The input of
prompt.context: the context blocks the engine prepends to a conversation's first user message, and the files behindclaudeMd.export type PromptContextInput = PromptContextBlocks;export type PromptContextInput = { blocks: readonly PromptContextBlock[]; instructionFiles?: readonly InstructionFile[];}; -
What a
prompt.contexthook returns: the blocks the conversation carries, in order; one left out is not sent.export type PromptContextResult = PromptContextBlocks;export type PromptContextResult = { blocks: readonly PromptContextBlock[]; instructionFiles?: readonly InstructionFile[];}; -
prompt.fill's input as a plugin's$.prompt.fill(args)takes it: noorigin(the engine sets the calling plugin's),modeoptional.export type PromptFillArgs = Omit<PromptFillInput, 'origin'>;export type PromptFillArgs = { text: string; mode?: PromptFillMode;}; -
The input of
prompt.fill(prompt-fill/): a text about to be put in the prompt box as the person's draft, over it, after it, or at the cursor.export type PromptFillInput = { text: string; mode: PromptFillMode; origin: PromptFillOrigin;}; -
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.}; children?: undefined;} | { type: 'Image'; props: ImageProps; 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 }).isExpanded: boolean; task?: UserMessageTask; from?: UserMessageFrom; onScreen?: OnScreen | null; }; AssistantMessage: { text: string; isFirstOfReply: boolean; onScreen?: OnScreen | null; }; ToolUse: { tool_use_id: string;… isErrored: boolean; isInterrupted: boolean; output?: unknown; onScreen?: OnScreen | null; }; ToolResult: { tool_use_id: string; tool: string; output: unknown; isErrored: boolean; onScreen?: OnScreen | null; }; ToolGroup: { calls: ReadonlyArray<ToolGroupCall>; isActive: boolean; isExpanded: boolean; onScreen?: OnScreen | null; }; CommandOutput: { command: string; args: string; text: string; isErrored: boolean; onScreen?: OnScreen | null; }; Spinner: { word: string;… TurnDuration: { word: string; durationMs: number; onScreen?: OnScreen | null; }; InfoNotice: { text: string; command: string | null; onScreen?: OnScreen | null; }; SessionMode: { modes: readonly string[]; -
The size of what a surface draws into, in character cells of the surface's monospace metric, and whether its layout docks a pane.
export type RenderViewport = { columns: number; rows: number; isFullscreen?: boolean;}; -
nextin a*hook: the set of events is open at runtime, soeisunknownuntilnext.is(pattern, e)narrows it to events it knows.readonly event: EventName; readonly origin: Origin; readonly trace: readonly TraceEntry<EventName, unknown, unknown>[]; readonly budget: NextBudget;}; -
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.[K in N]?: unknown;} = { [K in N]: Args<K>;}> = Pick<Next<N, E, O, S>, 'signal' | 'is' | 'event' | 'origin'> & {}> = Pick<Next<N, E, O, S>, 'signal' | 'is' | 'event' | 'origin' | 'budget'> & { (e: E): HookStream<Chunk<N>, O>; readonly to: (e: E, tier: TargetTier) => HookStream<Chunk<N>, O>; readonly trace: readonly TraceEntry<N, E, O>[]; -
The terminal mounting a
Clienta test rendered: its surface module read, loaded and drawn as a region does it, then driven by hand. -
One file of an ancestor entry: the file itself or one it imported.
-
The time bounds every hook runs under, in milliseconds: the engine's own constants are typed by these members, and
next.budgetreads the live one. -
Every tier an instruction file can belong to, for checking a hook's answer; the kind type is derived from this list.
-
The props of
Image, the terminal surface's picture leaf: pixels over a box of cells where the terminal can (kitty, Ghostty), thealttext elsewhere. -
The picture an
Imageshows, as bytes the plugin already holds. -
One instruction file behind the
claudeMdblock: where it was read, its tier, its text as loaded, and the file that@-imported it if one did. -
What tier an instruction file belongs to: the organization's managed policy, the person's own, the project's checked-in or private ones, memory.
-
What
$.ui.mounttakes: whoseClient, thekeyits hook gave it, the drawing when it drew several, and the region's size in cells. - added
MountedClienttypeA
Clientthe test mounted: what its surface module drew, and the ways the terminal reaches it, each settling the event loop before it resolves. -
The budget the code reading
next.budgetruns under: the whole allowance and what is left of it now, plain data read fresh on each access. -
The part of a transcript message the surface that drew it has on screen: units
firsttolastof the message'sof, counted from its start. -
The person's prompt box as it stands: the draft and where the cursor is in it; what
$.prompt.read()resolves and$.prompt.fillhands back. -
Where a
prompt.fillputs its text: over the whole draft, after it, or into it at the cursor. -
What
$.prompt.fillresolves to: whether the box took the text, and the box afterwards (PromptBox) as the caller's own$.prompt.read()reads it. -
The input of
session.end: the session is ending, why, and how to come back to it. -
Why the session ended: the classic SessionEnd hook's own
reason, word for word. -
What a
session.endhook returns and whatnext(e)resolves to:{ sessionId }, echoed by core; a hook's own value changes nothing. -
The input of
session.measure: what$.session.usage()answers at this moment, and which of its units moved since the last measurement a hook saw. -
What a
session.measurehook returns and whatnext(e)resolves to:{ changed }, echoed by core; a hook's own value changes nothing. -
How to come back to the session that ended: what
claude --resumetakes. -
Options of
$.ui.log. -
Where a
$.ui.logline goes:transcript, a dim row of its own (and the debug log, as every line);debug, the debug log alone, nothing on screen. -
One 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. -
One unit of what
$.session.usage()answers, by its key there: the context window's fill, the rate-limit windows, the session's cost.
12 docs only: reworded, same shape
$.promptnounSubmitting a prompt the model reads as a user turn, and the person's prompt box: read as it stands, written, or proposed into.
$.uinounDisplay: a line under an open dialog, a redraw or a repaint, a transcript or debug line, panes the surface places, a window or ring.
prompt.filleventFires when a text is about to be put in the prompt box as the person's draft (a plugin's
$.prompt.fill);next(e)writes it bye.mode.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.CommandPresentationtypeWhere 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.
ModelCompleteRequesttypeWhat
$.model.completetakes.PromptSubmitInputtypeThe input of
prompt.submit: the prompt as typed, after the input became a user message and before it enters the session.RegistrationtypeWhat
on(...)returns for a hook of typeF: the registration, which takes one.catch(CatchHandler); without it a failed hook is absent.RenderInputOftypeOne
ui.renderinput, for a component narrowed to one surface.SessionAttachInputtypeThe input of
session.attach: a surface joined the session's roster of attached clients (a phone opened the session; the desktop app connected).SessionRateLimittypeOne rate-limit window as the rate-limit notices read it.
ToolCallResulttypeWhat a
tool.callhook returns and whatnext(e)and$.tool.call(input)resolve to: the tool's result ({ result, context? }) or{ deny }.
v2.1.274
+9 added · 0 removed · 14 changed · 4 docs only since 2.1.273The engine
-
Defines an agent type the Agent tool dispatches from the next turn on, named
<plugin>:<name>: the eventagent.register.
Events
-
The argument of
$.agent.register(spec): the agent type as the plugin defined it. A hook above rewrites any of it; the type stays the caller's.
Types
-
The
Boxprops ahovermay override, none of which moves the Box's siblings, andscope, which names the hover group the Box joins.borderDimColor?: boolean; backgroundColor?: string; display?: 'flex'; top?: number; left?: number; right?: number; bottom?: number;}; -
The props of
Box: the layout, position, margin, padding and border props of Ink's Box a tree may set, and the two of hover.export type BoxProps = { key?: string; hover?: BoxHoverProps; position?: 'relative' | 'absolute'; top?: number; left?: number; right?: number; bottom?: number; flexDirection?: 'row' | 'column' | 'row-reverse' | 'column-reverse'; flexGrow?: number; flexShrink?: number; -
What a
command.runhook returns and whatnext(e)and$.command.runresolve to: the command's output text and the notes it leaves the model.export type CommandRunResult = { text?: string; context?: readonly string[]; ref?: number;}; -
The element constructors each surface draws, by
e.surface: what$.ui.resolve(e)returns and aui.resolvehook passes on; no globals.Select: ElementConstructor<SelectProps>; Link: ElementConstructor<LinkProps>; Code: ElementConstructor<CodeProps>; Markdown: ElementConstructor<MarkdownProps>; Client: ElementConstructor<ClientProps>; Raster: ElementConstructor<RasterProps>; };… Svg: ElementConstructor<SvgProps>; Link: ElementConstructor<LinkProps>; Code: ElementConstructor<CodeProps>; Markdown: ElementConstructor<MarkdownProps>; Client: ElementConstructor<ClientProps>; }; mobile: {… Svg: ElementConstructor<SvgProps>; Link: ElementConstructor<LinkProps>; Code: ElementConstructor<CodeProps>; Markdown: ElementConstructor<MarkdownProps>; }; vscode: { Box: ElementConstructor<BoxProps>;… Svg: ElementConstructor<SvgProps>; Link: ElementConstructor<LinkProps>; Code: ElementConstructor<CodeProps>; Markdown: ElementConstructor<MarkdownProps>; };}; -
What each call on
$answers (thevalueof its event's result), by event name.}; 'config.list': ConfigRow[]; 'agent.list': AgentInfo[]; 'agent.register': { agent: string; }; 'ui.toast': void; 'ui.status': void; 'ui.log': void; -
tool_input: unknown; tool_use_id: string; reason: string; mcp_server?: McpServerProvenance;}; -
tool_name: string; tool_input: unknown; permission_suggestions?: PermissionUpdate[]; mcp_server?: McpServerProvenance;}; -
error: string; is_interrupt?: boolean; duration_ms?: number; mcp_server?: McpServerProvenance;}; -
tool_response: unknown; tool_use_id: string; duration_ms?: number; mcp_server?: McpServerProvenance;}; -
tool_name: string; tool_input: unknown; tool_use_id: string; mcp_server?: McpServerProvenance;}; -
What
$.ui.presstakes: the plugin whoseui.renderhook drew the element, thekeyit gave it, the instance when several, and a Markdown'slink.plugin: string; key: string; requestId?: string; link?: PressedLink;}; -
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.props: CodeProps; children?: undefined;} | { type: 'Markdown'; props: MarkdownLeafProps; children?: undefined;} | { type: 'Markdown'; props: MarkdownLeafProps; press: { plugin: string; handle: number; }; children?: undefined;} | { type: 'Client'; props: ClientProps; client: { -
The plain-data props of each renderable component, as
ui.rendersees them undere.props; a hook rewrites them withnext({ ...e, props }).UserMessage: { text: string; origin: PromptOrigin; isExpanded: boolean; task?: UserMessageTask; from?: UserMessageFrom; }; AssistantMessage: { text: string; -
The argument of
ui.press: a press on aButtona render hook drew, or on an answeredMarkdownlink. Flat and frozen like every event's.component: RenderComponent; requestId: string; surface: RenderSurface; link?: PressedLink;}; -
What
$.agent.registertakes: an agent type this plugin defines, spelled as an agent definition in settings JSON is, plus itsname. -
What a
Markdowncarries across the boundary: its address, text, dimness and which links it answers;onLinkPressstays behind, apressinstead. -
The props of
Markdown, a block of markdown every surface draws as it draws an assistant reply's text: its own renderer, links, tables, fences. -
The MCP server serving this tool, for
mcp__*tools:nameis the server's config key (forsource: "sdk", exactly the name the SDK host registered insdkMcpServers/mcp_set_servers; for any other source, the key as authored in that configuration - untrusted text, the same valuemcp_statusand system/init report, to be escaped before display),sourceis where its definition came from -sdk(an in-process server the SDK host runs; only the host can register one, so a configured server of the same name never readssdk),plugin(a server a plugin ships or registers at runtime), or a config scope (user,project,local,dynamicfor --mcp-config /mcp_set_serversprocess servers,managed,enterprise,claudeai,agent). Key trust onsource, not on the name or the tool-name prefix. Absent for non-MCP tools. -
The link a press landed on: one a
Markdowndrew, pressed where the surface reports presses (a plain click in the fullscreen terminal). -
Who sent the message a
UserMessagerow carries, when someone other than the person did: another agent, a teammate, another session, a channel. -
The background task a
UserMessagenotification row reports on: a subagent, a background shell, a workflow, a remote agent, a monitor.
4 docs only: reworded, same shape
AgentOfferInputtypeThe input of
agent.offer: one agent type, at the moment the engine offers it to the model.ClientElementstypeThe element table a surface module draws with,
surface.elements: the terminal's (Elements) lessClient(none nests) andRaster(needs$).EnginePresstypeThe terminal pressing a Button a test rendered, or a Markdown's link: the
ui.presschain over every plugin hooked on it, its own closure last.StyledElementtypeThe shape a
Boxand aTextshare in a render tree: allowlisted props, an optionalhover, the group stamp ahover.scopeearns, and children.
v2.1.273
+0 added · 0 removed · 2 changed · 4 docs only since 2.1.272Types
-
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>; }; vscode: { Box: ElementConstructor<BoxProps>; Text: ElementConstructor<TextProps>; Button: ElementConstructor<ButtonProps>; Input: ElementConstructor<InputProps>; Select: ElementConstructor<SelectProps>; Svg: ElementConstructor<SvgProps>; Link: ElementConstructor<LinkProps>; Code: ElementConstructor<CodeProps>; };}; -
Where a render event's component is drawn:
terminalis Ink, which draws the hook's whole tree; the rest are remote surfaces drawing it themselves.export type RenderSurface = 'terminal' | 'desktop' | 'mobile';export type RenderSurface = 'terminal' | 'desktop' | 'mobile' | 'vscode';
4 docs only: reworded, same shape
$.session.surfacesverbReturns every surface the session draws on, each once:
terminalunder the REPL first, then the remote ones in the order they attached.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.RenderElementtypeWhat 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.SvgPropstypeThe props of
Svg, the remote surfaces' vector leaf: the markup is the element's data, as a string is a Text's, drawn isolated.
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.