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.277
+32 added · 2 removed · 23 changed · 29 docs only since 2.1.276The engine
-
Reads a file and returns its text, or with
{ as: "bytes" }its bytes as{ base64 }.(path: string) => Promise<string>FsReadCall -
Returns
{ kind, size, mtimeMs, isLink }of the path: what it leads to, and whether it is itself a symbolic link. Rejects when missing.(path: string) => Promise<FsStat>(path: string, options?: FsStatOptions) => Promise<FsStat>
Events
-
Fires once per message the engine injects for the model on its own (a reminder, a mode transition, a mentioned file), as a request carries it.
-
{ text }(null leaves the attachment out). -
Fires when the person edits the main prompt box: a key the editor took as an edit, or a paste;
next(e)resolves the box the editor shows. -
{ text, cursor }, the box the editor shows next.
Types
- removed
MountedClienttype breakingA
Clientthe test mounted: what its surface module drew, and the ways the terminal reaches it, each settling the event loop before it resolves. - removed
PromptAttachmenttype breakingA pasted or attached non-text item of a prompt; its kind, never its bytes.
-
One pointer event over a
Client's region, assurface.onPointerhands it: region-relative cells, and the sub-cell position where known.type: ClientPointerType; x: number; y: number; fine?: { x: number; y: number; }; button?: 'left' | 'middle' | 'right'; shift?: true; alt?: true; -
A surface drawing a component instance through the plugins, then driven by key through a handle typed by that surface (Mounted).
export type EngineMount = { mount: (target: MountTarget) => Promise<MountedClient>; mount: <P extends RenderSurface, C extends RenderComponent>(target: MountTarget<P, C>) => Promise<Mounted<P, C>>;}; -
The engine's own events as calls on
$, one signature each:$.<noun>.<event>(input)resolves to its result, or to its stream.suggest: (input: PromptSuggestArgs) => Promise<PromptSuggestResult>; section: (input: PromptSectionInput) => Promise<PromptSectionResult>; context: (input: PromptContextInput) => Promise<PromptContextResult>; attachment: (input: PromptAttachmentInput) => Promise<PromptAttachmentResult>; }; skill: { prompt: (input: SkillPromptInput) => Promise<SkillPromptResult>; -
The argument of
$.fs.ancestors: the file names to look for in each directory, the file to walk down to, and the directory to walk beneath.export type FsAncestorsRequest = { names: readonly string[]; of?: string; below?: string;}; -
One entry of
$.fs.list: the entry itself, a link not followed.name: string; kind: 'file' | 'dir' | 'other'; size: number; isLink: boolean;}; -
What
$.fs.statresolves with: what the path leads to, whether the path itself is a symbolic link, and where it lands when asked.kind: 'file' | 'dir' | 'other'; size: number; mtimeMs: number; isLink: boolean; realPath?: string;}; -
Options of
$.http.fetch.headers?: Record<string, string>; body?: string; auth?: string; socketPath?: string;}; -
The props of
Image, the terminal surface's picture leaf: pixels over a box of cells where the terminal can (kitty, Ghostty), thealtelsewhere.export type ImageProps = { key?: string; source: ImageSource; columns: number; rows: number; -
The picture an
Imageshows: base64 bytes the plugin holds (at most 2 MiB decoded), or the name of a file or POSIX shared-memory object it does not.rgba: string; width: number; height: number;} | { file: string; format: 'png'; generation?: number;} | { file: string; format: 'rgba' | 'rgb'; width: number; height: number; generation?: number;} | { shm: string; format: 'rgba' | 'rgb'; width: number; height: number; generation?: number;}; -
What
$.ui.invalidatetakes: a render event, or one of the six events whose answers the engine caches for the session.export type InvalidatableEventName = RenderEventName | 'prompt.section' | 'prompt.context' | 'tool.describe' | 'command.describe' | 'config.describe';export type InvalidatableEventName = RenderEventName | 'prompt.section' | 'prompt.context' | 'prompt.attachment' | 'tool.describe' | 'command.describe' | 'config.describe'; -
What
$.ui.mounttakes: whose elements the test will act on, the surface that draws, and the component instance the engine asks the plugins for.export type MountTarget = {export type MountTarget<P extends RenderSurface = RenderSurface, C extends RenderComponent = RenderComponent> = { plugin: string; key: string; surface: P; component: C; props: RenderPropsOf[C]; requestId?: string; columns?: number; rows?: number; viewport?: RenderViewport;}; -
What each call on
$answers (thevalueof its event's result), by event name.'ui.close': void; 'ui.panes': readonly UiPane[]; 'ui.blit': UiBlitResult; 'fs.read': string; 'fs.read': string | FsBytes; 'fs.write': void; 'fs.list': FsEntry[]; 'fs.exists': boolean; -
The argument of
$.ui.open: which pane, its title, whether it asks the person's keyboard, its dialog manners, its size: rows inline, columns docked.closeOnEscape?: true; holdToasts?: true; rows?: number; columns?: number;}; -
What
$.ui.presstakes: the plugin whoseui.renderhook drew the element, thekeyit gave it, the instance and surface when several, alink.plugin: string; key: string; requestId?: string; surface?: RenderSurface; link?: PressedLink;}; -
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[]; attachments?: readonly PromptSubmitAttachment[]; context?: readonly string[]; turnId?: string; wait: boolean; -
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' | 'CommandOutput' | 'Spinner' | 'TurnDuration' | 'InfoNotice' | 'SessionMode' | 'PromptHint' | 'AbovePrompt' | 'Pane';export type RenderComponent = 'AskUserQuestion' | 'UserMessage' | 'AssistantMessage' | 'ToolUse' | 'ToolResult' | 'ToolGroup' | 'ToolProgress' | '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.} | { type: 'Image'; props: ImageProps; image: { plugin: string; }; children?: undefined;} | { type: 'engine'; -
The plain-data props of each renderable component, as
ui.rendersees them undere.props; a hook rewrites them withnext({ ...e, props }).isErrored: boolean; onScreen?: OnScreen | null; }; ToolProgress: { tool_use_id: string; kind: 'background_hint'; hint: string; }; Spinner: { word: string; message: string | null; suffix: string; mode: 'requesting' | 'responding' | 'thinking' | 'tool-input' | 'tool-use'; }; TurnDuration: { -
The input of
tool.describe: one tool's description, at the moment the engine first renders the tool's schema for the model.export type ToolDescribeInput = { tool: string; description: string; isDeferred?: true; provider: Origin;}; -
What a
tool.describehook returns: the description the model sees for that tool and, when the hook moves it, where the tool waits (ToolDeferral).export type ToolDescribeResult = { description: string; isDeferred?: ToolDeferral;}; -
What a plugin's
$.ui.blit(args)takes: a Raster's nextcells(RasterBlitArgs) or a keyed Image's nextsource(ImageBlitArgs).export type UiBlitArgs = { requestId: string; key: string; cells: string; columns?: number; rows?: number;};export type UiBlitArgs = RasterBlitArgs | ImageBlitArgs; -
Which
Clientof a mounted drawing an act or a read means, by thekeyits element carries; optional while the drawing holds exactly one. -
The element each surface-dependent act of a mounted drawing reaches: a handle carries the act only where the surface's table has the element.
-
What a mounted drawing's
findandfindAllmatch an element on, every field given at once: its tag, itskey, and the text it shows. -
One element of a mounted drawing as
findreturns it: the description the plugin's hook (or aClient's module) built, read as plain data. -
What
$.fs.read(path, { as: "bytes" })resolves with: the file's bytes, base64, since only plain data crosses into a plugin's environment. -
How
$.fs.readanswers:text(UTF-8, the default) orbytes(base64). -
The options of
$.fs.readthat ask for the bytes: the call answers{ base64 }. -
$.fs.read: the file's text, or with{ as: "bytes" }its bytes as{ base64 }. -
The options of
$.fs.read. -
The options of
$.fs.stat. -
A
$.ui.blitargument swapping one of the caller's mounted keyed Images to its next picture; every call sends it, so a stream needs no generation. -
What a mounted drawing's
inputtakes: the Input's key, the text, which of the two inputs it is (submitwhen unsaid), another plugin's name. -
What a mounted drawing's
keytakes: the key as aClient'sonKeylistener receives it (ClientKeyEvent), and whichClientwhen several. -
What a mounted drawing's
pointertakes: the event as aClient'sonPointerlistener receives it, in its region's cells, and which one. -
What a mounted drawing's
presstakes: the Button's key, another plugin's name when the Button is not the mounted plugin's, a link. -
What a mounted drawing's
resizetakes: aClientregion's size in cells, as the surface measuring it hands it, and whichClient. -
What a mounted drawing's
selecttakes: the Select's key, the picked option's value, another plugin's name when the Select is not its own. -
A drawing of component
Cthe test mounted on surfaceP: reads over its description, acts on its elements by key,Clientacts wherePhas one. -
Every member a mounted drawing of component
Ccan have;Mounted<P, C>keeps the ones surfacePhas the element for (ElementOfAct). -
The input of
prompt.attachment: one message the engine injects into the conversation for the model on its own, as a request is about to carry it. -
Who authored the text an injected attachment carries, as the engine knows it from the attachment itself; a closed set, pinned on the event.
-
What a
prompt.attachmenthook returns: the text the model reads for that attachment, or null to leave the attachment out of the request. -
The input of
prompt.edit(prompt-edit/): one edit the person makes in the prompt box, as the draft before it and the splice the editor made of it. -
Who edits the prompt box at
prompt.edit, as the engine stamps it where the edit starts; a closed set a matcher narrows on. -
What a
prompt.edithook returns and whatnext(e)resolves to: the box after the edit (PromptBox), which the editor then shows. -
A pasted or attached non-text item of a submitted prompt; its kind, never its bytes.
-
A
$.ui.blitargument repainting one of the caller's mounted Rasters. -
Where a
tool.describeanswer places the tool:truebehind ToolSearch (its schema loads when the model asks for it),falsein the prompt's list.
29 docs only: reworded, same shape
$.fsnounThe file system as the engine's own process reaches it; a relative path is under the session's working directory, and text is UTF-8.
$.fs.ancestorsverbReads the named instruction files in every directory above the session's original working directory, the way the engine reads CLAUDE.md.
$.fs.existsverbReturns whether the path exists; rejects only a network location as spelled, which no
fscall reaches.$.fs.listverbLists a directory:
{ name, kind, size, isLink }per entry, by name, each entry as it stands (a symbolic link isotherwithisLink).$.http.fetchverbFetches
urlthrough the host (never the plugin's own network) and resolves{ status, ok, headers, text }once the body is read.$.mcp.callverbCalls
toolon one of the engine's connected MCP servers with the engine's own connection and credentials.$.ui.blitverbRepaints a mounted
Rasterthis plugin's own render hook drew with new cells, or swaps a keyedImageit drew to a new source; no redraw.$.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" }.$.ui.statusverbPins
textas this plugin's status line under the prompt, beside the engine's own pinned notices, until the next call replaces it.$.ui.toastverbShows
texton the notification bar under the prompt for a few seconds, the way the engine's own "context left" notice appears.fs.ancestorseventThe argument of
$.fs.ancestors({ names, of, below }).session.starteventFires once per process for each loaded plugin, before the first prompt, then once per fresh load of one (never
/clear);next(e)is{ cwd }.tool.describeeventFires once per tool, when the engine first renders the tool's schema in a session;
next(e)resolves to{ description, isDeferred? }.tool.describeresult{ description, isDeferred? }.ui.bliteventThe argument of
$.ui.blit(...): a Raster'scellsor a keyed Image'ssource; a hook above may rewrite either withnext, or{ deny }.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.ClientElementstypeThe element table a surface module draws with,
surface.elements: the terminal's (Elements) lessClient(none nests),RasterandImage.ClientModuletypeThe component a surface module exports (default, or its one PascalCase export): from props and surface to the tree drawn (no nested
Client).ClientSurfacetypeWhat a surface module's function receives as its second argument: its elements, the instance's local state, its region, input, clock and port.
ElementstypeThe element constructors each surface draws, by
e.surface: what$.ui.resolve(e)returns and aui.resolvehook passes on; no globals.EnginetypeWhat 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.EngineCreateInputtypeThe input of
engine.create: the fold that builds$, once per load, core innermost.EnginePresstypeA surface pressing a Button a test rendered, or a Markdown's link: the
ui.presschain over every plugin hooked on it, its own closure last.McpToolCallInputtypeThe MCP branch of a
tool.callhook'se(and of$.tool.call's input): one variant per declared tool, else the loose McpToolCallInputFallback.-
The
eatool.call(orclassic.PreToolUse) hook receives for an MCP tool while no MCP tool is declared: everymcp__*name, loose arguments. ToolSpectypeWhat
$.tool.registertakes.UiBlitResulttypeWhat
$.ui.blitresolves to and what aui.blithook's{ value }holds:{}once the cells or source are the next frame's, or why not.hconstThe JSX factory (classic runtime,
@jsx h; the engine prepends the pragma): a plain-data element from a string tag or a component.
v2.1.276
No change to the surface since 2.1.275v2.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.