Follow Discord
Sweep 25 Sep 2026 · 19:33Z Build v2.1.283 504 read Stable v2.1.274 Latest v2.1.283 Next v2.1.283 Feeds RSS JSON llms.txt llms-full.txt Unofficial
Mods API changes

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.

Releases22 since 2.1.259
Newest2.1.283+0 added · 0 removed · 2 changed · 2 docs only
Machine readablechanges.jsonin pages: counts, and each release's items

v2.1.272

No change to the surface since 2.1.271

v2.1.271

+77 added · 0 removed · 20 changed · 16 docs only since 2.1.270

The engine

  • changed $.clock.now verb may break

    Resolves milliseconds since the epoch, now.

    () => number() => Promise<number>
  • changed $.session.usage verb may break

    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>
  • added $.ui.blit verb

    Repaints a Raster this plugin's own render hook drew, still mounted, with new cells, without the redraw invalidate asks for.

  • added $.ui.focus verb

    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.

  • added $.ui.scroll verb

    Scrolls something into view as the DOM's scrollIntoView would: a render instance by requestId, an element by key, a site's edge.

Events

  • changed session.usage event may break

    The argument of $.session.usage({ breakdown, columns }).

    NoArgsSessionUsageArgs
  • added clock.after event

    The argument of $.clock.after(ms, fn): the wait before fn, which stays in the plugin's environment and runs once the dispatch resolves.

  • added clock.every event

    The argument of $.clock.every(ms, fn), dispatched once per period: fn runs each time a dispatch resolves, and the next period is asked.

  • added clock.now event

    The argument of $.clock.now().

  • added clock.sleep event

    The argument of $.clock.sleep(ms, { signal }); the signal does not cross, it aborts the dispatch.

  • added ui.blit event

    The argument of $.ui.blit({ requestId, key, cells }); a hook above the painter may repaint the cells with next, or refuse with { deny }.

  • added ui.focus event

    Fires before a site's focus ring moves: the person's Tab, arrows or click in a Pane or the band; an autoFocus element taking it; $.ui.focus.

  • added ui.focus result

    {} once the ring moved, or { deny }.

  • added ui.scroll event

    Fires before a site's window moves: the person's wheel or scroll keys on a Pane body or the AbovePrompt band, at its edges too; $.ui.scroll.

  • added ui.scroll result

    {} once the window moved, or { deny }.

Types

  • changed BoxHoverProps type extended

    The Box props a hover may override, none of which moves layout, and scope, which names the hover group the Box joins instead of a style.

    export type BoxHoverProps = {    scope?: string;    borderStyle?: string;    borderColor?: string;    borderDimColor?: boolean;
  • changed ButtonProps type extended

    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;};
  • changed ClientElements type may break

    The element table a surface module draws with, surface.elements: the terminal's (Elements) less Client (none nests) and Raster (needs $).

    export type ClientElements = Omit<Elements['terminal'], 'Client'>;export type ClientElements = Omit<Elements['terminal'], 'Client' | 'Raster'>;
  • changed CommandRunArgs type may break

    command.run's input as a plugin's $.command.run takes it: args may be left out (/command, bare); origin and presentation the engine sets.

    export type CommandRunArgs = Omit<CommandRunInput, 'origin' | 'args'> & {export type CommandRunArgs = Omit<CommandRunInput, 'origin' | 'args' | 'presentation'> & {    args?: string;};
  • changed CommandRunInput type extended

    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;};
  • changed Elements type extended

    The element constructors each surface draws, by e.surface: what $.ui.resolve(e) returns and a ui.resolve hook passes on; no globals.

            Link: ElementConstructor<LinkProps>;        Code: ElementConstructor<CodeProps>;        Client: ElementConstructor<ClientProps>;        Raster: ElementConstructor<RasterProps>;    };    desktop: {        Box: ElementConstructor<BoxProps>;
  • changed EventCalls type extended

    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>;    };};
  • changed InputProps type extended

    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;};
  • changed OpValueOf type extended

    What each call on $ answers (the value of 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;
  • changed PaneOpenArgs type extended

    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;};
  • changed RenderComponent type may break

    Everything ui.render can 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';
  • changed RenderElement type may break

    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;};
  • changed RenderPropsOf type extended

    The plain-data props of each renderable component, as ui.render sees them under e.props; a hook rewrites them with next({ ...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;    };};
  • changed SelectProps type extended

    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;};
  • changed SessionContextUsage type extended

    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;};
  • changed TextHoverProps type extended

    The Text props a hover may override (its colors and styles, not its wrapping) and scope, the hover group it joins; a Button's label too.

    export type TextHoverProps = {    scope?: string;    color?: string;    backgroundColor?: string;    dimColor?: boolean;
  • changed TurnStepInput type extended

    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 toEqual and its kin (expect.any, expect.objectContaining), known by its text in a failure.

  • added AsyncMatchers type

    The same checks on what a promise received settles with, each resolving once the promise has settled and the check passed.

  • added ClockWait type

    The argument of the $.clock waits (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.

  • added Constructor type

    A class, as toThrow, toBeInstanceOf and expect.any take it.

  • added ContextAgent type

    One custom agent whose description the Agent tool's prompt carries; built-in agents are left out.

  • added ContextApiUsage type

    The token counts the last API response of the live window reported, as the API spells them; the breakdown's Messages row is reconciled to it.

  • How a context breakdown is counted: full with the token-count API per category, summary from the last response's usage and local estimates.

  • added ContextCategory type

    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.

  • added ContextMcpTool type

    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).

  • added ContextSkill type

    One skill whose listing the context carries.

  • added ContextSkills type

    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 window line off this.

  • added Engine type

    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.

  • added EngineCall type

    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.

  • added EngineNoun type

    One noun of the engine's $: each of its events as the engine calls it, tool.call and ui.render typed per tool and component, ui.resolve out.

  • added EngineNounEvent type

    The events of one noun a test's $ carries: every one but ui.resolve, which a render hook calls on its own $ and the engine never raises.

  • added EnginePress type

    The terminal pressing a Button a test rendered: the ui.press chain over every plugin hooked on it, the Button's own onPress at the bottom.

  • added Expect type

    The checks on a value (expect(received)), and with them the matchers that stand inside an expected value (expect.any(Number)).

  • added Expectation type

    What expect(received) answers: the checks, their negation, and the checks on what a promise received resolves or rejects with.

  • added Expecting type

    expect(received, message?): the checks on a value, a message of the test's own leading a failure's.

  • added Matchers type

    The checks expect(received) offers; each throws an AssertionError when it fails, naming what was expected and what was received.

  • added Matching type

    The matchers that stand inside an expected value, each matching received there by a rule instead of by equality.

  • added Mock type

    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.

  • added MockClock type

    The clock mock.clock hands back: the time its hooks answer, and the only ways it moves.

  • added MockClockOptions type

    Where a mocked clock starts: now, in milliseconds (0 when not given).

  • added Negatable type

    A set of checks and, under not, the same set passing where they fail.

  • added Plugin type

    Written inline in a test and loaded as a plugin folder is: its name, the tier it loads in (user when not given), and its hooks module's register.

  • added PluginStamp type

    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.

  • added PluginTier type

    A tier a plugin loads in: every tier but the engine's own.

  • added PressTarget type

    What $.ui.press takes: the plugin whose ui.render hook drew the Button, the key it gave it, and the instance when it drew one in several.

  • added RasterProps type

    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 in cells.

  • 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_usage shape.

  • added SessionUsageArgs type

    What $.session.usage(args) takes: nothing for the status line's figures alone; breakdown to have the window broken down as /context breaks it.

  • added SiteView type

    Which transcript the person has on screen where a site draws: the main conversation's, or one agent's, opened from the tasks list.

  • added StyledElement type

    The shape a Box and a Text share in a render tree: allowlisted props, an optional hover, the group stamp a hover.scope earns, and children.

  • added TestBody type

    A test: the engine's $, and on, a plugin's registrar, whose hooks sit beneath every plugin; beneath them the bottom hook throws, naming its event.

  • added TestOptions type

    What test takes beside its name: the inline plugins it loads beside the one under test, and how long it may run (5000 ms when not given).

  • added TestRest type

    What follows a test's name: its body, or its options then its body.

  • added ThrowExpectation type

    What toThrow compares the thrown error with: a substring or pattern of its message, its class, a value carrying the whole message, or nothing.

  • added UiBlitArgs type

    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.

  • added UiBlitResult type

    What $.ui.blit resolves to and what a ui.blit hook's { value } holds: {} once the cells are the Raster's next frame, or why not.

  • added UiFocusArgs type

    What a plugin's $.ui.focus(args) takes: one of its own elements, by the key it drew it under, in one of its sites that holds the keyboard now.

  • added UiFocusComponent type

    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.

  • added UiFocusInput type

    The input of ui.focus: a site's focus ring about to move onto one of the elements a hook drew in it (a Button, Input or Select), or off them.

  • added UiFocusOrigin type

    Who moves the ring at ui.focus, as the engine stamps it where the move starts; a closed set a matcher narrows on.

  • added UiFocusResult type

    What a ui.focus hook returns, what next(e) resolves to, and what $.ui.focus hands back: {} once the ring moved, or why it did not.

  • added UiScrollArgs type

    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.

  • added UiScrollBlock type

    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.

  • added UiScrollInput type

    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).

  • added UiScrollOrigin type

    Who moves the window at ui.scroll, as the engine stamps it where the move starts; a closed set a matcher narrows on.

  • added UiScrollPointer type

    The cell the pointer was over when the person's wheel raised ui.scroll, in the site's body: the box its ui.render hook draws into, as painted.

  • added UiScrollResult type

    What a ui.scroll hook returns, what next(e) resolves to, and what $.ui.scroll hands back: {} once the window moved, or why it did not.

  • added UiScrollTarget type

    What $.ui.scroll brings into view: never a row number, always a thing drawn somewhere.

  • added WithMessage type

    An error-like value toThrow compares by its whole message.

  • added describe const

    A group of tests: its name leads the title of each test declared inside, and its body runs at once, while the file loads.

  • added expect const

    Checks a value: expect(received).toEqual(expected) throws an AssertionError naming both sides when it fails, a message given leading.

  • added mock const

    The world beneath the plugins, mocked noun by noun: mock.clock, mock.store and mock.env.

  • added test const

    One test: it passes when its body returns or resolves, and fails when it throws, rejects or outlasts its time (5000 ms, or timeoutMs).

  • added tier const

    Says which tier the plugin under test loads in, once, at the top of the file: prepend, user (when unsaid), append or builtin.

16 docs only: reworded, same shape
  • $.clock noun

    The time and timers, each an event through the host: clock.now reads the time; clock.sleep, after and every wait until it has passed.

  • Calls fn once after ms milliseconds; cancel() before then stops it.

  • Calls fn every ms milliseconds (at least 1) until cancel().

  • $.ui noun

    Display: 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.

  • Closes one of the open panes; an id that is not open is left alone.

  • Re-runs an event whose results the engine caches: ui.render draws the instances this plugin may draw again; the others drop the cached answers.

  • Opens a pane: a framed region the surface places, whose body this plugin draws by hooking ui.render for { component: "Pane" }.

  • turn.step event

    Fires 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.

  • The input of agent.spawn: what the Agent tool decided about the subagent it is about to start, before its model is resolved.

  • The props of Box: the layout, margin, padding and border props of Ink's Box a tree may set, and the two of hover.

  • One /config row as $.config.list() returns it: what the menu would draw now, after every config.describe hook, a hidden row left out.

  • Why a pane closes, as the engine stamped it at ui.close.

  • A plugin's options as register(on, options) receives them: the values of the fields its manifest's userConfig declares, defaults filled in.

  • The 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.

  • The 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.

  • What every turn.complete carries 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.269

v2.1.269

+60 added · 0 removed · 16 changed · 22 docs only since 2.1.268

The engine

  • added $.config noun

    Every row of the settings menu (/config), the panel's own and each enabled plugin's userConfig fields alike: listing and changing them.

  • added $.config.list verb

    Returns the rows the /config menu would draw now, in its order, each with its current value, its kind, its owner and its lock.

  • added $.config.set verb

    Changes one row as if the person did in the menu: the event config.set with origin { kind: 'plugin', name }, then the writer.

  • Returns every surface the session draws on, each once: terminal under the REPL first, then desktop and mobile in the order they attached.

  • added $.tool.check verb

    Asks the engine's permission decision for a tool call now: the event tool.check, resolved to { decision, reason?, rule? }.

Events

  • added config.describe event

    Fires once per /config row, when the menu lists it and for $.config.list; next(e) resolves to { label, description, isHidden }.

  • added config.describe result

    { label, description, isHidden }.

  • added config.list event

    The argument of $.config.list().

  • added config.set event

    Fires when a /config row is about to change, from the menu or a plugin's $.config.set; next(e) resolves to { value } once written.

  • added config.set result

    { value } once written, or { deny }.

  • added plugin.register event

    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.

  • added plugin.register result

    { allow: true }, or { refuse }.

  • added session.attach event

    Fires when a remote client joins the session's roster of attached surfaces: it said so (ui_attach), or it first asked to draw.

  • added session.attach result

    { clientId }.

  • added session.detach event

    Fires when a client leaves the roster: it detached, or the session ended with it attached (e.reason). Observe; next(e) echoes { clientId }.

  • added session.detach result

    { clientId }.

  • added session.surfaces event

    The argument of $.session.surfaces().

  • added tool.check event

    Fires when the engine decides whether a tool call may run, after the tool.call and PreToolUse hooks and before the mode settles an ask.

  • added tool.check result

    { decision, reason?, rule? }.

Types

  • changed AgentSpawnArgs type may break

    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'>>;
  • changed AgentSpawnResult type may break

    What an agent.spawn hook returns and what next(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;};
  • changed CatchHandler type may break

    The handler on(...).catch(handler) takes for a hook of type F: 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;
  • changed CommandRunArgs type may break

    command.run's input as a plugin's $.command.run takes it: args may be left out (/command, bare), and origin is the engine's to set.

    export type CommandRunArgs = Omit<CommandRunInput, 'origin'>;export type CommandRunArgs = Omit<CommandRunInput, 'origin' | 'args'> & {    args?: string;};
  • changed EventCalls type may break

    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: {
  • changed Events type may break

    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>>;};
  • changed InvalidatableEventName type may break

    What $.ui.invalidate takes: 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';
  • changed MatchedHook type may break

    The hook on(pattern, matcher, hook) takes: ($, e, next) with e narrowed 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>>;
  • changed OpValueOf type extended

    What each call on $ answers (the value of 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;
  • changed PromptSubmitArgs type may break

    prompt.submit's input as a plugin's call takes it: origin, turnId and wait are the engine's to set, context the hooks' to attach.

    export type PromptSubmitArgs = Omit<PromptSubmitInput, 'origin' | 'turnId' | 'wait'>;export type PromptSubmitArgs = Omit<PromptSubmitInput, 'origin' | 'turnId' | 'wait' | 'context'>;
  • changed PromptSubmitInput type extended

    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;
  • changed RenderPropsOf type extended

    The plain-data props of each renderable component, as ui.render sees them under e.props; a hook rewrites them with next({ ...e, props }).

            title: string;        isFocused: boolean;        bodyColumns: number;        placement: 'dock' | 'inline';        scroll: SiteScroll;    };};
  • changed TraceEntry type extended

    One settled run of a link beneath the caller, as next.trace lists it: data, not a handle.

        readonly outcome: TraceOutcome;    readonly reason?: string;    readonly ms: number;    readonly chunks?: number;    readonly received: E;    readonly returned: O | undefined;};
  • changed TurnCompleteFields type extended

    What every turn.complete carries 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;};
  • changed TurnStepInput type may break

    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;};
  • changed TurnStepResult type may break

    What a turn.step hook returns and what next(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;};
  • added Chunk type

    What a hook on streaming event N yields, and what its next(e) yields to it (ChunkOf by name).

  • added ChunkOf type

    The chunk type of each streaming event, by name: what its stream yields.

  • added ChunkRef type

    What every turn.step chunk 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 /config row presents, at the moment the menu lists it (and for $.config.list).

  • What a config.describe hook returns: the label, help text and hidden flag the menu uses; the key and provider stay as they were.

  • added ConfigKind type

    How a /config row takes its value: boolean toggles, choice picks one of its options, text takes a string, number a number.

  • added ConfigOrigin type

    Where a config.set came from, in prompt.submit's words: the person in the /config menu (composer), the bridge, or a plugin, named.

  • added ConfigRow type

    One /config row as $.config.list() returns it: what the menu would draw now, after every config.describe hook, a hidden row left out.

  • added ConfigSetArgs type

    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.

  • added ConfigSetInput type

    The input of config.set: one /config row about to change, from the menu or a plugin's $.config.set, with what it holds now and who owns it.

  • added ConfigSetResult type

    What a config.set hook returns and what next(e) resolves to: { value } once written, or { deny: reason }, the row left as it was.

  • added ConfigValue type

    A /config row's value as a hook and $.config see it: a toggle's boolean, a choice's or a text's string, a number, or a list of strings.

  • added HookOf type

    The hook event E takes: an async generator over its chunks for a streaming event (turn.step), ($, e, next) => result for every other.

  • added HookStream type

    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, e narrowed by the matcher, next(e) the stream beneath.

  • What a matched streaming hook's next.is(pattern, e) narrows e to: 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.is narrowing 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.register hook returns and what next(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 validate prints 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.attach hook returns and what next(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, and next(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.detach hook returns and what next(e) resolves to: { clientId }, echoed by core; a hook's own value changes nothing.

  • added StreamHook type

    The hook a streaming event takes: async function* ($, e, next) {}, yielding the event's chunks and returning its result.

  • added StreamHookBody type

    What a hook on a streaming event evaluates to: the async generator an async function* makes, yielding C and returning R or nothing.

  • added StreamNext type

    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.

  • added ToolCheckArgs type

    tool.check's input as $.tool.check takes it: the tool and its arguments; tool_use_id is 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.

  • added ToolCheckInput type

    The input of tool.check: the tool, its arguments, and the call's id when the engine is deciding a real call.

  • added ToolCheckResult type

    What a tool.check hook returns and what next(e) resolves to: the verdict, why, and the settings rule behind it when one decided.

  • added TurnStepChunk type

    One piece of a turn.step response as it streams through the chain: what a hook's next(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 tool chunk of the same index.

  • 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 as input chunks of the same index.

  • added TurnStopReason type

    Why the model stopped, as a turn.step result 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
  • Spawns a subagent: the event agent.spawn, the same call the engine makes when the Agent tool starts one; the engine fills the rest.

  • Runs a slash command as if the person typed /command args: the event command.run, queued and run once the session is idle.

  • Returns the first of $.session.surfaces(), or null where nothing draws.

  • Closes one of the open panes; an id that is not open is left alone.

  • Re-runs an event whose results the engine caches: ui.render draws the instances this plugin may draw again; the others drop the cached answers.

  • Opens a pane: a framed region the surface places, whose body this plugin draws by hooking ui.render for { component: "Pane" }.

  • turn.step event

    Fires 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.step result

    The response: { turnId, index, answer, toolUses, stopReason, usage }.

  • ui.close event

    The argument of $.ui.close({ id }) with origin plugin; the engine raises it too, for the person (person) and an unload (unload).

  • The component a surface module exports (default, or its one PascalCase export): from props and surface to the tree drawn (no nested Client).

  • The props of Client: which of the plugin's surface modules draws here, under what key, with what data, in how much room.

  • What a command.run hook returns and what next(e) and $.command.run resolve to: the command's output text, when it has one.

  • The element constructors each surface draws, by e.surface: what $.ui.resolve(e) returns and a ui.resolve hook passes on; no globals.

  • Why a pane closes, as the engine stamped it at ui.close.

  • The argument of $.ui.open: which pane, its title, and whether the plugin asks the person's keyboard for it.

  • What a prompt.submit hook returns and what next(e) resolves to: the prompt that entered, { text, context?, origin? }, or { drop: reason }.

  • What a render hook returns, and what next(e) resolves to: a plain-data tree of elements, strings allowed as children of Text and Box.

  • One ui.render input, for a component narrowed to one surface.

  • What a session.receive hook returns and what next(e) resolves to: the delivery that was queued, { text }, or { consumed: reason }.

  • The input of session.start: the session the process starts with, read the way $.session reads it at that moment.

  • What a turn.complete hook returns and what next(e) resolves to: { text }; a text other than a main-loop answer's is shown beneath it.

  • The argument of ui.message: what a Client instance'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.267

The engine

  • removed $.session.turnCount verb breaking

    Returns how many prompts the user has sent this session (user turns in the transcript).

  • changed $.model.fork verb may break

    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>
  • changed $.ui.ask verb may break

    Asks the user question in 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>
  • added $.prompt.fill verb

    Writes input.text into the prompt box as the person's draft, cursor at its end, replacing what it held: the event prompt.fill.

  • added $.prompt.suggest verb

    Proposes input.text as the prompt box's dim suggestion, Tab to take: the event prompt.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.

  • added $.session.turns verb

    Returns how many prompts the user has sent this session (user turns in the transcript).

Events

  • removed session.turnCount event breaking

    The argument of $.session.turnCount().

  • changed ui.press event may break

    Fires when a Button a render hook drew is pressed on a surface; e is { plugin, element, component, surface }, element the button's key.

    UiPressInputUiPressArgument
  • added prompt.fill event

    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.

  • added prompt.fill result

    { isFilled }.

  • added prompt.suggest event

    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.

  • added prompt.suggest result

    { isShown }.

  • added session.authorize event

    The argument of $.session.authorize().

  • added session.turns event

    The argument of $.session.turns().

  • added tool.register event

    The argument of $.tool.register(spec).

Types

  • removed AskProps type breaking

    Options of $.ui.ask.

  • removed ModelForkReply type breaking

    What $.model.fork resolves to when the fork answered: the reply's text and what the fork cost.

  • removed RenderAnswerOptions type breaking

    How a site instance asks for its ui.render answer: the version it is on, whether a static frame is drawing, and whose submit it serves.

  • removed UiPressInput type breaking

    The argument of ui.press: a press on a Button a render hook drew. Flat and frozen like every event's.

  • changed CommandDescribeInput type may break

    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;
  • changed CommandDescribeResult type may break

    What a command.describe hook returns: the description, hint and hidden flag the menu uses; the name, immediate and provider stay as they were.

    type CommandDescribeResult = Omit<CommandDescribeInput, 'command' | 'immediate' | 'provider'>;export type CommandDescribeResult = Omit<CommandDescribeInput, 'command' | 'immediate' | 'provider'>;
  • changed CommandInfo type may break

    One slash command as $.command.list() returns it.

    type CommandInfo = {export type CommandInfo = {    name: string;    description: string;    source: CommandSource;
  • changed CommandRunArgs type may break

    command.run's input as a plugin's $.command.run takes it: origin is the engine's to set (the calling plugin's name).

    type CommandRunArgs = Omit<CommandRunInput, 'origin'>;export type CommandRunArgs = Omit<CommandRunInput, 'origin'>;
  • changed CommandRunInput type may break

    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;
  • changed CommandRunResult type may break

    What a command.run hook returns and what next(e) and $.command.run resolve to: the command's output text, when it has one.

    type CommandRunResult = {export type CommandRunResult = {    text?: string;    ref?: number;};
  • changed CommandSource type may break

    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';
  • changed CommandSpec type may break

    What $.command.register takes: the slash command this plugin serves.

    type CommandSpec = {export type CommandSpec = {    name: string;    description: string;    argumentHint?: string;
  • changed Elements type extended

    The element constructors each surface draws, by e.surface: what $.ui.resolve(e) returns and a ui.resolve hook 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>;    };};
  • changed EventCalls type extended

    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>;    };
  • changed Events type may break

    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>>;};
  • changed GlobHook type may break

    The hook on(pattern, hook) takes for a glob or a negation: one function placed on every selected event, e and 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>>;
  • changed GlobNext type may break

    next in a hook on a glob or a negation: an overload per selected event, then one over their union for an e not 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>>[];
  • changed HttpInit type extended

    Options of $.http.fetch.

        method?: string;    headers?: Record<string, string>;    body?: string;    auth?: string;};
  • changed MatchedHook type may break

    The hook on(pattern, matcher, hook) takes: ($, e, next) with e narrowed 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>>;
  • changed Next type may break

    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>[];
  • changed OpValueOf type may break

    What each call on $ answers (the value of 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[];
  • changed Origin type may break

    Who raised a dispatch, as next.origin holds it: the calling plugin's name and the tier it sits in; the engine reads engine in core.

    type Origin = {export type Origin = {    readonly plugin: string;    readonly tier: Tier;};
  • changed PaneCloseArgs type may break

    The argument of $.ui.close: the pane to close ({ id }). origin is the engine's to set: a plugin's call reads plugin at the hooks.

    type PaneCloseArgs = Omit<PaneCloseInput, 'origin'>;export type PaneCloseArgs = Omit<PaneCloseInput, 'origin'>;
  • changed PaneCloseInput type may break

    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;};
  • changed PaneCloseOrigin type may break

    Why a pane closes, as the engine stamped it at ui.close.

    type PaneCloseOrigin = 'plugin' | 'person' | 'unload';export type PaneCloseOrigin = {    kind: 'plugin' | 'person' | 'unload';};
  • changed PaneOpenArgs type may break

    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;
  • changed ProcessRunInit type may break

    Options of $.process.run.

    type ProcessRunInit = {export type ProcessRunInit = {    cwd?: string;    env?: Record<string, string>;    stdin?: string;
  • changed ProcessRunResult type may break

    What $.process.run resolves with once the child has exited.

    type ProcessRunResult = {export type ProcessRunResult = {    exitCode: number;    stdout: string;    stderr: string;
  • changed RenderChildren type may break

    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[];
  • changed RenderPropsOf type may break

    The plain-data props of each renderable component, as ui.render sees them under e.props; a hook rewrites them with next({ ...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;    };
  • changed RenderSurface type may break

    Where a render event's component is drawn: terminal is Ink, which draws the hook's whole tree; desktop (Claude Code Desktop) and mobile (the Claude mobile app) are remote surfaces that draw the tree themselves.

    export type RenderSurface = 'terminal' | 'desktop';export type RenderSurface = 'terminal' | 'desktop' | 'mobile';
  • changed SDKAssistantMessageError type may break
    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';
  • changed SessionContextUsage type may break

    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;
  • changed SessionCost type may break

    What the session has cost, as /cost and the status line total it.

    type SessionCost = {export type SessionCost = {    usd: number;};
  • changed SessionRateLimit type may break

    One rate-limit window as the rate-limit notices read it.

    type SessionRateLimit = {export type SessionRateLimit = {    kind: string;    percentUsed: number;    resetsAt?: string;
  • changed SessionReceiveOrigin type may break

    Where an inbound delivery came from, as the bridge classified it from the server's stamps: prompt.submit's e.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';};
  • changed SessionStartInput type may break

    The input of session.start: the session the process starts with, read the way $.session reads it at that moment.

    export type SessionStartInput = {    cwd: string;    surface: RenderSurface | null;    interactive: boolean;    isInteractive: boolean;};
  • changed SessionUsage type may break

    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;
  • changed Settings type may break

    What $.settings.read answers: 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>>;
  • changed SettingsReadArgs type may break

    What $.settings.read(args) takes.

    type SettingsReadArgs = {export type SettingsReadArgs = {    source?: SettingsSource;};
  • changed SettingsSource type may break

    One source of settings by the name a plugin gives it, lowest precedence first; the engine's own name is the same word with Settings appended.

    type SettingsSource = 'user' | 'project' | 'local' | 'flag' | 'policy';export type SettingsSource = 'user' | 'project' | 'local' | 'flag' | 'policy';
  • changed SiteScroll type may break

    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;};
  • changed StarNext type may break

    next in a * hook: the set of events is open at runtime, so e is unknown until next.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>[];
  • changed SvgProps type may break

    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;};
  • changed ToolGroupCall type may break

    One tool call of a ToolGroup, as ui.render sees it under calls.

    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;};
  • changed ToolResultSummary type may break

    One tool_result block of a user message.

    export type ToolResultSummary = {    id: string;    tool_use_id: string;    text: string;    isError: boolean;    result?: unknown;
  • changed ToolUseSummary type may break

    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;
  • changed TraceOutcome type may break

    What the chain decided for one link, as next.trace names it.

    type TraceOutcome = 'caught' | 'expired' | 'kept' | 'passed' | 'rejected' | 'returned' | 'skipped';export type TraceOutcome = 'caught' | 'expired' | 'kept' | 'passed' | 'rejected' | 'returned' | 'skipped';
  • changed TurnCompleteFields type may break

    What every turn.complete carries 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;};
  • changed TurnUsage type may break

    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;};
  • changed UiInputArgument type may break

    The argument of ui.input: a change of, or a submit from, an Input a 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;
  • changed UiInputResult type may break

    What a ui.input hook returns and what next(e) resolves to.

    type UiInputResult = {export type UiInputResult = {    element: string;    value: string;};
  • changed UiSelectArgument type may break

    The argument of ui.select: a pick from a Select a 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;};
  • changed UiSelectResult type may break

    What a ui.select hook returns and what next(e) resolves to.

    type UiSelectResult = {export type UiSelectResult = {    element: string;    value: string;};
  • added AskOptions type

    Options of $.ui.ask.

  • added Frozen type

    T with every property read-only to every depth, arrays and tuples kept as declared: how a hook's e is typed.

  • added ModelForkResult type

    What $.model.fork resolves to when the fork answered: the reply's text and what the fork cost.

  • added PromptFillArgs type

    prompt.fill's input as a plugin's $.prompt.fill(args) takes it: origin is the engine's to set (the calling plugin's name).

  • added PromptFillInput type

    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.

  • added PromptFillOrigin type

    Who writes the prompt box at prompt.fill, as the engine stamps it where the write starts; a closed set a matcher narrows on.

  • added PromptFillResult type

    What a prompt.fill hook returns and what next(e) resolves to: whether the text went into the prompt box.

  • prompt.suggest's input as a plugin's $.prompt.suggest(args) takes it: origin is 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.suggest hook returns and what next(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.

  • added UiPressArgument type

    The argument of ui.press: a press on a Button a render hook drew. Flat and frozen like every event's.

46 docs only: reworded, same shape
  • Spawns a subagent: the event agent.spawn, the same call the engine makes when the Agent tool starts one; the engine fills the rest.

  • Plays one audio clip, starting now; clips are not queued, so two calls play together (a bed under speech).

  • Speaks text with the platform's own synthesizer (say on macOS). Plain text.

  • Runs a slash command as if the person typed /command args: the event command.run, queued and run once the session is idle.

  • Fetches url through the host (never the plugin's own network) and resolves { status, ok, headers, text } once the body is read.

  • Picks one of labels for text with one completion over $.model.complete and a fixed classifier prompt.

  • Submitting a prompt the model reads as a user turn, and putting a text in the person's prompt box, written or proposed.

  • Submits a prompt: the event prompt.submit, the same call the engine makes for a typed prompt; input.text runs when the session is idle.

  • Compacts the conversation: the event session.compact with trigger plugin, the same call /compact makes, between turns.

  • Returns where the session draws: terminal under the REPL, desktop or mobile once a remote surface has asked; null where nothing draws.

  • $.store noun

    This plugin's own key-value store, kept between sessions and hot reloads; values are JSON data.

  • Calls a tool: the event tool.call, the same call the engine makes for the model's tool calls, under a tool_use_id of its own.

  • Re-runs an event whose results the engine caches: ui.render draws the instances this plugin may draw again; the others drop the cached answers.

  • Fires when the engine offers an agent type to the model, in the agent listing and again at dispatch; next(e) resolves to { isOffered: true }.

  • { isOffered }.

  • The input of agent.offer: one agent type, at the moment the engine offers it to the model.

  • The input of agent.spawn: what the Agent tool decided about the subagent it is about to start, before its model is resolved.

  • What $.audio.play plays: a URL the engine fetches, or the bytes.

  • The props of Box: the layout, margin, padding and border props of Ink's Box a tree may set, and the two of hover.

  • The names of the built-in tools.

  • Everything a classic hook event's answer can carry, named as the classic hook's JSON output names it; each event reads its subset (ClassicResultOf).

  • The element table a surface module draws with, surface.elements: the terminal's constructors (Elements) less Client (none nests).

  • The props of Client: which export of the plugin's surface module draws here, under what key, with what data, in how much room.

  • The 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.

  • The name of an event the engine defines itself (a key of CoreEventOf); EventName adds the declared plugin nouns' events.

  • The children field every element constructor's props carry, appended beside its own props type: one child, or a list that may nest.

  • An element as $.ui.resolve(e) hands it out: a constructor from props to the frozen plain-data element, children among the props as JSX passes.

  • The input of engine.create: the fold that builds $, once per load, core innermost.

  • The 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.

  • What 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.

  • How many object or array levels a matcher narrows e through, counted as a tuple's length: the runtime's own limit, which refuses a deeper matcher.

  • How $.audio.play plays a clip: looped until signal aborts, or once.

  • The nouns a plugin declared on $ by merging into EngineInterface; never one the engine's own events are under (tool, session, ui).

  • Where a prompt.submit submission came from, as the engine knows it at the site it was queued from; a closed set, never a text prefix.

  • The input of prompt.submit: the prompt as typed, after the input became a user message and before the turn starts.

  • What a prompt.submit hook returns and what next(e) resolves to: the prompt that proceeds, { text, context?, origin? }, or { drop: reason }.

  • Everything ui.render can draw: one name per component that has a render site; a matcher narrows on it.

  • What a render hook returns, and what next(e) resolves to: a plain-data tree of elements, strings allowed as children of Text and Box.

  • One ui.render input, for a component narrowed to one surface.

  • The 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.

  • One message of the transcript as $.session.messages() returns it.

  • The argument of $.audio.speak(text, options) as the event carries it.

  • What $.audio.speak resolves with once the utterance has ended.

  • The 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.

  • The 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).

  • What a tool.call hook returns and what next(e) and $.tool.call(input) resolve to: the tool's result ({ result, context? }) or { deny }.

Feedback