Follow Discord
Sweep 06 Nov 2026 · 01:32Z Build v2.1.319 537 read Stable v2.1.311 Latest v2.1.318 Next v2.1.319 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.

Releases55 since 2.1.259
Newest2.1.319+9 added · 4 removed · 3 changed · 3 docs only
Machine readablechanges.jsonin pages: counts, and each release's items

v2.1.275

+35 added · 0 removed · 19 changed · 12 docs only since 2.1.274

The engine

  • changed $.prompt.fill verb may break

    Puts input.text in the prompt box as the draft, by mode: replace (the default) over it, append after it, insert at the cursor.

    EventCalls['prompt']['fill'](input: PromptFillArgs) => Promise<PromptFilled>
  • changed $.ui.log verb may break

    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
  • added $.prompt.read verb

    Returns the prompt box as it stands, the draft typed so far and the cursor's offset into it, so a fill can keep what the person typed.

  • added $.session.root verb

    Returns the session's project root, absolute: where it started, or where /cd, a host's directory change or a worktree move took it.

  • added $.ui.panes verb

    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

  • added prompt.read event

    The argument of $.prompt.read().

  • added session.end event

    Fires once when the session ends (exit, /clear, resume, logout, signal, a -p run done), after its SessionEnd settings hooks; e.reason says which.

  • added session.end result

    { sessionId }.

  • added session.measure event

    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.

  • added session.measure result

    { changed }.

  • added session.root event

    The argument of $.session.root().

  • added ui.panes event

    The argument of $.ui.panes().

Types

  • changed ClientElements type may break

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

    export type ClientElements = Omit<Elements['terminal'], 'Client' | 'Raster'>;export type ClientElements = Omit<Elements['terminal'], 'Client' | 'Raster' | 'Image'>;
  • 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.

            Markdown: ElementConstructor<MarkdownProps>;        Client: ElementConstructor<ClientProps>;        Raster: ElementConstructor<RasterProps>;        Image: ElementConstructor<ImageProps>;    };    desktop: {        Box: ElementConstructor<BoxProps>;
  • changed Engine type may break

    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>;};
  • 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.

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

    One file $.fs.ancestors found: 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[];};
  • changed GlobNext type extended

    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.

        readonly event: N;    readonly origin: Origin;    readonly trace: readonly TraceEntry<N, Args<N>, GlobNextResult<N>>[];    readonly budget: NextBudget;};
  • changed Next type extended

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

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

    The input of prompt.context: the context blocks the engine prepends to a conversation's first user message, and the files behind claudeMd.

    export type PromptContextInput = PromptContextBlocks;export type PromptContextInput = {    blocks: readonly PromptContextBlock[];    instructionFiles?: readonly InstructionFile[];};
  • changed PromptContextResult type may break

    What a prompt.context hook 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[];};
  • changed PromptFillArgs type may break

    prompt.fill's input as a plugin's $.prompt.fill(args) takes it: no origin (the engine sets the calling plugin's), mode optional.

    export type PromptFillArgs = Omit<PromptFillInput, 'origin'>;export type PromptFillArgs = {    text: string;    mode?: PromptFillMode;};
  • changed PromptFillInput type extended

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

    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;};
  • 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 }).

            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[];
  • changed RenderViewport type extended

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

    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.

        readonly event: EventName;    readonly origin: Origin;    readonly trace: readonly TraceEntry<EventName, unknown, unknown>[];    readonly budget: NextBudget;};
  • changed StreamNext type may break

    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>[];
  • added EngineMount type

    The terminal mounting a Client a test rendered: its surface module read, loaded and drawn as a region does it, then driven by hand.

  • added FsAncestorPart type

    One file of an ancestor entry: the file itself or one it imported.

  • added HookBudget type

    The time bounds every hook runs under, in milliseconds: the engine's own constants are typed by these members, and next.budget reads 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.

  • added ImageProps type

    The props of Image, the terminal surface's picture leaf: pixels over a box of cells where the terminal can (kitty, Ghostty), the alt text elsewhere.

  • added ImageSource type

    The picture an Image shows, as bytes the plugin already holds.

  • added InstructionFile type

    One instruction file behind the claudeMd block: 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.

  • added MountTarget type

    What $.ui.mount takes: whose Client, the key its hook gave it, the drawing when it drew several, and the region's size in cells.

  • added MountedClient type

    A Client the test mounted: what its surface module drew, and the ways the terminal reaches it, each settling the event loop before it resolves.

  • added NextBudget type

    The budget the code reading next.budget runs under: the whole allowance and what is left of it now, plain data read fresh on each access.

  • added OnScreen type

    The part of a transcript message the surface that drew it has on screen: units first to last of the message's of, counted from its start.

  • added PromptBox type

    The person's prompt box as it stands: the draft and where the cursor is in it; what $.prompt.read() resolves and $.prompt.fill hands back.

  • added PromptFillMode type

    Where a prompt.fill puts its text: over the whole draft, after it, or into it at the cursor.

  • added PromptFilled type

    What $.prompt.fill resolves to: whether the box took the text, and the box afterwards (PromptBox) as the caller's own $.prompt.read() reads it.

  • added SessionEndInput type

    The input of session.end: the session is ending, why, and how to come back to it.

  • added SessionEndReason type

    Why the session ended: the classic SessionEnd hook's own reason, word for word.

  • added SessionEndResult type

    What a session.end hook returns and what next(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.measure hook returns and what next(e) resolves to: { changed }, echoed by core; a hook's own value changes nothing.

  • added SessionResume type

    How to come back to the session that ended: what claude --resume takes.

  • added UiLogOptions type

    Options of $.ui.log.

  • added UiLogSink type

    Where a $.ui.log line goes: transcript, a dim row of its own (and the debug log, as every line); debug, the debug log alone, nothing on screen.

  • added UiPane type

    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.

  • added UsageUnit type

    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
  • Submitting a prompt the model reads as a user turn, and the person's prompt box: read as it stands, written, or proposed into.

  • $.ui noun

    Display: a line under an open dialog, a redraw or a repaint, a transcript or debug line, panes the surface places, a window or ring.

  • Fires 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 by e.mode.

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

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

  • What $.model.complete takes.

  • The input of prompt.submit: the prompt as typed, after the input became a user message and before it enters the session.

  • What on(...) returns for a hook of type F: the registration, which takes one .catch (CatchHandler); without it a failed hook is absent.

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

  • The input of session.attach: a surface joined the session's roster of attached clients (a phone opened the session; the desktop app connected).

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

  • What a tool.call hook returns and what next(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.273

The engine

  • added $.agent.register verb

    Defines an agent type the Agent tool dispatches from the next turn on, named <plugin>:<name>: the event agent.register.

Events

  • added agent.register event

    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

  • changed BoxHoverProps type extended

    The Box props a hover may override, none of which moves the Box's siblings, and scope, which names the hover group the Box joins.

        borderDimColor?: boolean;    backgroundColor?: string;    display?: 'flex';    top?: number;    left?: number;    right?: number;    bottom?: number;};
  • changed BoxProps type extended

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

    What a command.run hook returns and what next(e) and $.command.run resolve to: the command's output text and the notes it leaves the model.

    export type CommandRunResult = {    text?: string;    context?: readonly string[];    ref?: number;};
  • 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.

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

    What each call on $ answers (the value of 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;
  • changed PermissionDeniedHookInput type extended
        tool_input: unknown;    tool_use_id: string;    reason: string;    mcp_server?: McpServerProvenance;};
  • changed PermissionRequestHookInput type extended
        tool_name: string;    tool_input: unknown;    permission_suggestions?: PermissionUpdate[];    mcp_server?: McpServerProvenance;};
  • changed PostToolUseFailureHookInput type extended
        error: string;    is_interrupt?: boolean;    duration_ms?: number;    mcp_server?: McpServerProvenance;};
  • changed PostToolUseHookInput type extended
        tool_response: unknown;    tool_use_id: string;    duration_ms?: number;    mcp_server?: McpServerProvenance;};
  • changed PreToolUseHookInput type extended
        tool_name: string;    tool_input: unknown;    tool_use_id: string;    mcp_server?: McpServerProvenance;};
  • changed PressTarget type extended

    What $.ui.press takes: the plugin whose ui.render hook drew the element, the key it gave it, the instance when several, and a Markdown's link.

        plugin: string;    key: string;    requestId?: string;    link?: PressedLink;};
  • changed RenderElement type extended

    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: {
  • 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 }).

        UserMessage: {        text: string;        origin: PromptOrigin;        isExpanded: boolean;        task?: UserMessageTask;        from?: UserMessageFrom;    };    AssistantMessage: {        text: string;
  • changed UiPressArgument type extended

    The argument of ui.press: a press on a Button a render hook drew, or on an answered Markdown link. Flat and frozen like every event's.

        component: RenderComponent;    requestId: string;    surface: RenderSurface;    link?: PressedLink;};
  • added AgentSpec type

    What $.agent.register takes: an agent type this plugin defines, spelled as an agent definition in settings JSON is, plus its name.

  • What a Markdown carries across the boundary: its address, text, dimness and which links it answers; onLinkPress stays behind, a press instead.

  • added MarkdownProps type

    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: name is the server's config key (for source: "sdk", exactly the name the SDK host registered in sdkMcpServers / mcp_set_servers; for any other source, the key as authored in that configuration - untrusted text, the same value mcp_status and system/init report, to be escaped before display), source is 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 reads sdk), plugin (a server a plugin ships or registers at runtime), or a config scope (user, project, local, dynamic for --mcp-config / mcp_set_servers process servers, managed, enterprise, claudeai, agent). Key trust on source, not on the name or the tool-name prefix. Absent for non-MCP tools.

  • added PressedLink type

    The link a press landed on: one a Markdown drew, pressed where the surface reports presses (a plain click in the fullscreen terminal).

  • added UserMessageFrom type

    Who sent the message a UserMessage row carries, when someone other than the person did: another agent, a teammate, another session, a channel.

  • added UserMessageTask type

    The background task a UserMessage notification row reports on: a subagent, a background shell, a workflow, a remote agent, a monitor.

4 docs only: reworded, same shape
  • The input of agent.offer: one agent type, at the moment the engine offers it to the model.

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

  • The terminal pressing a Button a test rendered, or a Markdown's link: the ui.press chain over every plugin hooked on it, its own closure last.

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

v2.1.273

+0 added · 0 removed · 2 changed · 4 docs only since 2.1.272

Types

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

    Where a render event's component is drawn: terminal is 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
  • Returns every surface the session draws on, each once: terminal under the REPL first, then the remote ones in the order they attached.

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

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

  • The props of Svg, the remote surfaces' vector leaf: the markup is the element's data, as a string is a Text's, drawn isolated.

v2.1.272

No change to the surface since 2.1.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.

Feedback