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

No change to the surface since 2.1.290

v2.1.290

+8 added · 0 removed · 11 changed · 29 docs only since 2.1.289

Events

  • added prompt.mention event

    Fires once per path a prompt names after an @, a directory aside, before the engine reads it; next(e) reads it and resolves { type }.

  • added prompt.mention result

    { type, context? } (null when nothing was attached) or { deny }.

Types

  • changed AgentTeammateRecord type may break

    What an Agent call that started a teammate answers as result at tool.call: the started teammate's two ids, its name and its model.

    export type AgentTeammateRecord = {    status: 'teammate_spawned';    agentId?: string;    agent_id: string;    teammate_id: string;    agent_id: string;    name: string;    team_name?: string;    agent_type?: string;    resolvedModel?: string;    model?: string;    prompt: string;};
  • changed BoxHoverProps type may break

    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.

    export type BoxHoverProps = {    scope?: string;    borderStyle?: string;    borderColor?: string;    borderColor?: Color;    borderDimColor?: boolean;    backgroundColor?: string;    backgroundColor?: Color;    display?: 'flex';    top?: number;    left?: number;
  • changed BoxProps type may break

    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.

        paddingLeft?: number;    paddingRight?: number;    borderStyle?: string;    borderColor?: string;    borderColor?: Color;    borderDimColor?: boolean;    backgroundColor?: string;    backgroundColor?: Color;    overflow?: 'visible' | 'hidden';    display?: 'flex' | 'none';};
  • 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.

            section: (input: PromptSectionInput) => Promise<PromptSectionResult>;        context: (input: PromptContextInput) => Promise<PromptContextResult>;        attachment: (input: PromptAttachmentInput) => Promise<PromptAttachmentResult>;        mention: (input: PromptMentionInput) => Promise<PromptMentionResult>;        compose: (input?: PromptComposeArgs) => Promise<PromptComposeResult>;    };    skill: {
  • changed Frozen type may break

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

    export type Frozen<T> = T extends (...args: never[]) => unknown ? T : T extends readonly unknown[] ? {export type Frozen<T> = T extends string | ((...args: never[]) => unknown) ? T : T extends readonly unknown[] ? {    [K in keyof T]: Frozen<T[K]>;} : T extends object ? {    readonly [K in keyof T]: Frozen<T[K]>;
  • 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 }).

        AssistantMessage: {        text: string;        isFirstOfReply: boolean;        isSummary?: true;        onScreen?: OnScreen | null;    };    ToolUse: {
  • changed TextHoverProps type may break

    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;    color?: Color;    backgroundColor?: Color;    dimColor?: boolean;    bold?: boolean;    italic?: boolean;
  • changed TextProps type may break

    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.

    export type TextProps = {    hover?: TextHoverProps;    color?: string;    backgroundColor?: string;    color?: Color;    backgroundColor?: Color;    dimColor?: boolean;    bold?: boolean;    italic?: boolean;
  • changed ToolCheckInput type extended

    The input of tool.check: the tool, its arguments, the organization's ceiling if it set one, and on a real call its id and the loop's agentId.

        tool: string;    input: unknown;    tool_use_id?: string;    agentId?: string;    ceiling?: ToolCheckDecision;};
  • changed ToolCheckResult type extended

    What a tool.check hook returns and what next(e) resolves to: the verdict, why, and the rule, classic hook or ceiling behind it, if any.

        reason?: string;    rule?: string;    hook?: string;    ceiling?: ToolCheckDecision;};
  • changed TurnStepResult type extended

    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.

        index: number;    answer: string;    toolUses: readonly TurnStepToolUse[];    serverToolUses?: readonly TurnStepServerToolUse[];    stopReason: TurnStopReason;    usage: TurnUsage | null;};
  • added Color type

    What a prop that paints may hold: a theme key, which follows the person's theme, or any other string, a raw color (a name such as "red", or hex).

  • How the engine attached a mentioned file, in the names prompt.attachment gives its type.

  • The input of prompt.mention: one file a prompt names after an @, as the engine resolved it and before it is read for the model.

  • What a prompt.mention hook returns and what next(e) resolves to: how the file was attached ({ type, context? }), or { deny: reason }.

  • added ThemeKey type

    The theme keys named for what a color means: text, status, the prompt box and its modes, and diffs, as the custom theme reference lists them.

  • One tool call of a step that the API ran itself, inside the request (the advisor is one): the engine ran nothing for it.

29 docs only: reworded, same shape
  • Asks the engine's permission decision for a tool call now: the event tool.check, resolved to { decision, reason?, rule?, ceiling? }.

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

  • Pins text as this plugin's status line under the prompt, beside the engine's own pinned notices, until the next call replaces it.

  • Shows text for a few seconds under the plugin's name: a small box on the stack of plugin toasts over the transcript's top right corner.

  • Runs while $ is being built, once per load or reload of this plugin and before any other hook of it; next(e) resolves to $ built so far.

  • The argument of $.process.spawn(request): the request itself.

  • Fires when a prompt is submitted, before the turn starts. next(e) runs the hooks beneath and the UserPromptSubmit settings hooks, then it enters.

  • tool.call event

    Fires when the engine is about to run a tool. Each next(e) runs the hooks beneath, then core (the permission prompt, the tool itself).

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

  • tool.check result

    { decision, reason?, rule?, hook?, ceiling? }.

  • turn.step result

    The response: { turnId, index, answer, toolUses, stopReason, usage }, and serverToolUses when the API ran tools of its own in the request.

  • One agent loop of this session as $.agent.list() returns it: a subagent or a teammate.

  • The props of Client: which of the plugin's surface modules 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 argument of $.fs.ancestors: the file names to look for in each directory, the file to walk down to, and the directory to walk beneath.

  • Why a hook failed, as its .catch handler reads it on next.error: plain frozen data.

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

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

  • Who authored the text an injected attachment carries, as the engine knows it from the attachment itself; a closed set, pinned on the event.

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

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

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

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

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

  • tool.check's input as $.tool.check takes it: the tool and its arguments; the call's id, agentId and the ceiling are the engine's to set.

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

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

  • The argument of ui.message: what a Client instance's surface module posted (surface.post(data)), addressed by where the instance is drawn.

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

v2.1.289

+7 added · 0 removed · 5 changed · 10 docs only since 2.1.288

Events

  • added ui.fault event

    Fires when a Client THIS plugin drew failed on a surface: its module did not load, its drawing failed, or its code failed after it had drawn.

  • added ui.fault result

    {}: the fault was heard.

Types

  • changed AgentInfo type may break

    One agent loop of this session as $.agent.list() returns it: a subagent or a teammate.

    export type AgentInfo = {    id: string;    teammateId?: string;    description: string;    type: string;    status: string;    status: AgentStatus;    parentId?: string;    spawnedBy?: string;    name?: string;
  • changed AgentSpawnInput type extended

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

        permissionMode?: string;    background: boolean;    fork: boolean;    isTeammate?: true;    name?: string;    cwd?: string;};
  • changed AgentSpawnResult type extended

    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;    agentId?: string;    teammateId?: string;    deny?: undefined;} | {    deny: string;    model?: undefined;    agentId?: undefined;    teammateId?: undefined;};
  • changed ToolCheckResult type extended

    What a tool.check hook returns and what next(e) resolves to: the verdict, why, and the settings rule or classic hook behind it, if any.

        decision: ToolCheckDecision;    reason?: string;    rule?: string;    hook?: string;};
  • changed ToolResultOf type may break

    The structured result of the tool named Name: its BuiltinToolResults entry for a built-in tool, else unknown.

    export type ToolResultOf<Name extends string> = string extends Name ? unknown : Name extends keyof BuiltinToolResults & string ? BuiltinToolResults[Name] | (Name extends 'Agent' ? AgentCallRecord : never) : unknown;export type ToolResultOf<Name extends string> = string extends Name ? unknown : Name extends keyof BuiltinToolResults & string ? BuiltinToolResults[Name] | (Name extends 'Agent' ? AgentCallRecord | AgentTeammateRecord : never) : unknown;
  • added AgentStatus type

    Where an agent's loop stands: pending (not started), running a turn, waiting (held), idle (between turns, until a message wakes it), or ended.

  • What an Agent call that started a teammate answers as result at tool.call: the started teammate's address, its name and its model.

  • added UiFaultInput type

    The input of ui.fault: a Client this plugin drew failed on a surface, addressed by where the instance is drawn.

  • added UiFaultPhase type

    When a Client failed, as ui.fault names it; a closed set a matcher narrows on.

  • added UiFaultResult type

    What a ui.fault hook returns and what next(e) resolves to: {}, the fault was heard.

10 docs only: reworded, same shape
  • Returns the session's agents so far, subagents and teammates: the ones the model spawned and the ones plugins did alike.

  • Returns what the person last selected with the mouse: the text as a copy would take it, and the transcript row it lies in.

  • tool.check result

    { decision, reason?, rule?, hook? }.

  • ui.render event

    Fires when the engine is about to draw a component: once per input value (props, viewport width), plugin load or $.ui.invalidate("ui.render").

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

  • The argument of $.ui.open: which pane, its title, whether it asks the person's keyboard, its dialog manners, its size: rows inline, columns docked.

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

  • Whom $.session.send addresses: a recipient as the SendMessage tool names one (a string), or a session or an agent of this session by id.

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

v2.1.288

+3 added · 0 removed · 1 changed · 7 docs only since 2.1.287

The engine

  • added $.ui.selection verb

    Returns what the person last selected with the mouse: the text as a copy would take it, and the transcript row it lies in.

Events

  • added ui.selection event

    The argument of $.ui.selection().

Types

  • changed OpValueOf type extended

    What each call on $ answers (the value of its event's result), by event name.

        'ui.open': UiOpenResult;    'ui.close': void;    'ui.panes': readonly UiPane[];    'ui.selection': UiSelection | undefined;    'ui.copy': UiCopyResult;    'ui.blit': UiBlitResult;    'fs.read': string | FsBytes;
  • added UiSelection type

    What the person has selected on screen, as $.ui.selection() answers it: the text, and the transcript row it lies in when it lies in one.

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

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

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

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

  • Options of $.http.fetch.

  • Who compacts: the person's /compact (manual), the engine at its threshold or on a prompt too long (auto), a plugin, or a precompute.

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

v2.1.287

+10 added · 0 removed · 10 changed · 11 docs only since 2.1.286

Types

  • changed IsDiscriminant type may break

    Whether tag key K selects members of I: it does when each member gives it ONE literal (component: "ToolUse" on the ToolUse variant).

    type IsDiscriminant<I, K> = I extends unknown ? K extends KnownKeys<I> ? IsSingleLiteral<I[K]> : true : never;type IsDiscriminant<I, K> = I extends unknown ? K extends KnownKeys<I> ? IsSingleLiteral<I[K & keyof I]> : true : never;
  • changed KnownKeys type may break

    The declared keys of T, the string and number index signatures left out.

    type KnownKeys<T> = keyof {    [K in keyof T as string extends K ? never : number extends K ? never : K]: 0;};type KnownKeys<T> = keyof (string extends keyof T ? IndexFree<T> : number extends keyof T ? IndexFree<T> : T);
  • changed MatchedNames type may break

    The events a matched registration on P covers: the event named, or for a glob every selected event whose input has each key the matcher names.

    type MatchedNames<P, M = never> = P extends EventName ? P : {type MatchedNames<P, M = never> = (P extends EventName ? P : {    [N in Selected<P & string>]: [M] extends [never] ? N : keyof M extends AnyKeyOf<Args<N>> ? N : never;}[Selected<P & string>];}[Selected<P & string>]) extends infer Names extends EventName ? Names : never;
  • changed Matcher type may break

    What on(event, matcher, hook) takes for an argument of type I: the shape of the e the hook wants, a partial of it at any depth.

    export type Matcher<I, All = I> = I extends unknown ? {    readonly [K in KnownKeys<I>]?: MatcherValue<I[K], MatcherValueOf<All, K>>;    readonly [K in KnownKeys<I>]?: MatcherValue<I[K & keyof I], MatcherValueOf<All, K>>;} & (string extends keyof I ? OpenMatcher<I, All> : unknown) : never;
  • changed MatcherValueOf type may break

    The type of key K across the variants of I that declare it: one read of their table by key (MatcherValues), for a key some variant declares.

    type MatcherValueOf<I, K> = I extends unknown ? K extends KnownKeys<I> ? I[K] : never : never;type MatcherValueOf<I, K> = [I] extends [unknown] ? symbol extends K ? MatcherValueAcross<I, K> : MatcherValues<I>[K & PropertyKey] : never;
  • changed On type may break

    Registers hook on the events pattern selects: one by name, every one under a namespace (classic.*), all (*), or all but some (!tool.*).

    export type On = {    <P extends Pattern>(pattern: P, hook: NoInfer<HookFor<P>>): Registration<HookFor<P>>;    <P extends Pattern, const M extends Matcher<Args<MatchedNames<P>>>>(pattern: P, matcher: M, hook: NoInfer<MatchedHook<P, M>>): Registration<MatchedHook<P, M>>;    <P extends Pattern, const M extends MatcherFor<P>>(pattern: P, matcher: M, hook: NoInfer<MatchedHook<P, M>>): Registration<MatchedHook<P, M>>;};
  • changed OpenMatcher type may break

    The keys a variant with a string index signature (an MCP tool's input) takes beyond its own: another variant's key as typed there; others free.

    type OpenMatcher<I, All> = {    readonly [K in Exclude<MatcherKeys<All>, KnownKeys<I>>]?: MatcherValue<MatcherValueOf<All, K>>;    readonly [K in Exclude<MatcherKeys<All>, keyof IndexFree<I>>]?: MatcherValue<MatcherValueOf<All, K>>;} & Readonly<Record<string, unknown>>;
  • changed PromptAttachmentInput type may break

    The input of prompt.attachment: one message the engine injects into the conversation for the model on its own, as a request is about to carry it.

    export type PromptAttachmentInput = {    type: string;    text: string;    origin: PromptAttachmentOrigin;    agentId?: string;};    [K in keyof PromptAttachmentDetailOf]: DeclaredAttachmentInput<K>;}[keyof PromptAttachmentDetailOf] | UndeclaredAttachmentInput;
  • changed Selection type may break

    The literal each tag key of I is held to by matcher M: one-of arrays flattened, RegExps widened to unknown.

    type Selection<I, M> = {    [K in keyof M & TagKeys<I>]: Literal<M[K] extends readonly (infer One)[] ? One : M[K]>;    [K in keyof M & TagKeys<I, keyof M>]: Literal<M[K] extends readonly (infer One)[] ? One : M[K]>;};
  • changed TagKeys type may break

    The keys among Among a matcher may select variants of I by: valued by literals in every variant, one literal per variant (IsDiscriminant).

    type TagKeys<I> = {    [K in MatcherKeys<I>]: IsLiteralValued<MatcherValueOf<I, K>> extends true ? IsDiscriminant<I, K> extends true ? K : never : never;}[MatcherKeys<I>];type TagKeys<I, Among> = Among extends MatcherKeys<I> ? IsLiteralValued<MatcherValueOf<I, Among>> extends true ? IsDiscriminant<I, Among> extends true ? Among : never : never : never;
  • One prompt.attachment input of a type PromptAttachmentDetailOf names: the attachment's text, and under detail the facts it was rendered from.

  • added IndexFree type

    An object with the declared keys of T and no other: its string and number index signatures are left out. What KnownKeys reads the keys of.

  • added MatcherFor type

    The matcher type per pattern: a Matcher of the e of the event named, or of each event a glob or a negation selects.

  • The type of key K across the variants of I that declare it, read variant by variant: what MatcherValueOf reads for a key as wide as symbol.

  • added MatcherValues type

    The type of each declared key of I across the variants that declare it, as one table by key: made once per I, then read at a key.

  • added PlanModeDetail type

    What the engine knew as it made a plan-mode reminder: which of its two wordings the row carries, where the plan is kept, whether one is there.

  • What the engine knew as it made the note that plan mode has ended: where the plan is kept, whether one is there.

  • What the engine knew as it made the note that plan mode is entered again: where the plan of the earlier planning is kept.

  • The facts prompt.attachment pins under e.detail, by attachment type: what the engine computed for the row, as it rendered the row's text.

  • One prompt.attachment input of every other type, the ones PromptAttachmentDetailOf does not name: the attachment's text alone.

11 docs only: reworded, same shape
  • Plays one audio clip, starting now; clips are not queued, so two calls play together (a bed under speech).

  • Fires when the engine renders a system prompt; next(e) resolves to { sections }, each { id, text, scope }, in the order they are sent.

  • Fires when the person edits the main prompt box: a key the editor took as an edit, or a paste; next(e) resolves the box the editor shows.

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

  • One variant per built-in tool; with none in the table (a plugin author's project with no tools entry laid), one loose variant over every name.

  • The arguments of each built-in tool by name, for declaration merging; empty until a declaration file adds entries, then e.tool === "Bash" narrows e to Bash's arguments.

  • The structured result of each built-in tool by name, for declaration merging; empty until a declaration file adds entries, then after e.tool === "Bash" the result of next(e) is Bash's record.

  • The e a tool.call (or classic.PreToolUse) hook receives for an MCP tool while no MCP tool is declared: every mcp__* name, loose arguments.

  • McpToolInputs interface

    The inputs of the MCP tools this project knows, keyed by full tool name, for declaration merging; empty by default, then every MCP tool is loose.

  • Which side of the prompt cache's boundary a section of the system prompt sits on: shared before it, session after it.

  • One section of the system prompt as prompt.compose answers it: a stable id, the text the model reads, and the side of the cache boundary it is on.

Feedback