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

+41 added · 0 removed · 2 changed · 6 docs only since 2.1.280

The engine

  • Returns the version of the engine the session runs on, the release it is built from, and when it was built.

  • added $.state noun

    Named values held by the host for the session, each with a version: plain data that survives a hot reload of the plugin's code.

  • added $.state.get verb

    Resolves the value under ref and the version it stands at; a value never written is undefined at version 0.

  • added $.state.set verb

    Writes value under ref, which must be this plugin's own; the sites that read it while drawing are drawn again, at the redraw rate.

Events

  • added session.version event

    The argument of $.session.version().

  • added state.get event

    The argument of $.state.get(ref): the reference itself, plugin, key and a family member's id; identity, pinned.

  • added state.set event

    The argument of $.state.set(ref, value, { ifVersion }): the reference, the value, the condition, and previous, what stood there (the host's).

Types

  • changed OpValueOf type extended

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

        'session.surfaces': readonly RenderSurface[];    'session.authorize': SessionAuthorization;    'session.usage': SessionUsage;    'session.version': SessionVersion;    'turn.abort': void;    'prompt.read': PromptBox;    'tool.list': ToolInfo[];…    'store.set': void;    'store.delete': void;    'store.keys': string[];    'state.get': StateRead;    'state.set': StateSetResult;    'clock.now': number;    'clock.sleep': void;    'clock.after': void;
  • changed PluginRegisterUses type extended

    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.

            reads: readonly string[];        writes: readonly string[];    };    state?: {        reads: readonly StateName[];        writes: readonly StateName[];    };};
  • added Atom type

    A named value with its initial, as atom(ref, initial) makes it: read, it is never undefined; while nothing is written it reads as the initial.

  • added AtomFunction type

    atom(ref, initial): a named value with its initial, so a read is never undefined; given { shape }, for a key declared Shaped<T>.

  • added AtomOptions type

    The options of atom: shape, a tag the value is kept under, so a reload of the plugin's code that names another tag finds the value absent.

  • added DeclaredEvents type

    The state events of each declared value in a union of [plugin, key] pairs, one variant per pair (it distributes), so a matcher narrows e.

  • added DeclaredEventsOf type

    e of state.get and of state.set for one declared value: its typed reference, and for a write the change, of the declared type.

  • added DeclaredPair type

    Every named value the enabled contracts declare, as one union of [plugin, key] pairs; never while PluginState is empty.

  • What a state.set on one declared value carries beside its reference: the value being written and the one that stood there, of the declared type.

  • added DeriveFunction type

    derive(sources, fn): a value computed from atoms and references, cached by their versions: read runs fn again only when one moved.

  • added Derived type

    A value computed from other values, as derive(sources, fn) makes it: read runs fn again only when a source's version moved.

  • added MemberOfFunction type

    memberOf(family, e): the member of a family for the instance being drawn, keyed by e.requestId; of an atom over a family, that member's.

  • added PluginState interface

    The named values plugins keep in the session ($.state), by plugin name then key, for declaration merging; empty by default.

  • added ReadFunction type

    read($, source): the value of an atom (its initial while absent), of a derived value, or under a plain reference; one $.state.get per value.

  • added SessionVersion type

    What $.session.version() answers: the version of the engine the session runs on, the release that version is built from, and when it was built.

  • added Shaped type

    A value kept with a shape tag, as an atom given { shape } keeps it: a reload whose code names another tag reads the value as absent.

  • added ShapedValue type

    What an atom given a shape reads and takes for a key declared Shaped<T>: T; never for a key declared otherwise, so that atom does not compile.

  • added SourceValues type

    The values derive's function receives for its sources, in their order: an atom's or a derived value's own, a plain reference's or undefined.

  • added StateAddress type

    Which named value a $.state call is about, as it crosses to the host: the owning plugin, the key, and a family member's id.

  • added StateDollar type

    What the state library's read and update take of $: its state noun, on which they make the calls a hook would make itself.

  • added StateFamily type

    A key of PluginState that holds one value of type T per id (one per drawn row, per worker): its reference must carry id: string.

  • added StateGetEvent type

    e of state.get: one variant per value a contract declares, so a matcher on plugin and key narrows it; the untyped address while none does.

  • added StateName type

    Which named value: the plugin that owns it and its key there, both literals where a contract declares the value.

  • added StateRead type

    What $.state.get answers: the value and the version it stands at; a value never written is undefined at version 0.

  • added StateRef type

    A typed reference to one named value: the owning plugin and the key, both literals, and for a StateFamily key the member's id.

  • added StateSetEvent type

    e of state.set: one variant per value a contract declares, so a matcher on plugin and key narrows e.value; the untyped write while none does.

  • added StateSetOptions type

    The options of $.state.set: ifVersion makes the write conditional on the value still standing at that version (compare-and-set).

  • added StateSetResult type

    What $.state.set answers: whether the write landed, and the version the value stands at now (a landed write's own, a missed one's the current).

  • added StateValue type

    The type of the value under key K of plugin P, as its contract declares it in PluginState; a StateFamily's member type for a family key.

  • added StateWrite type

    A $.state.set as it crosses to the host and as its hooks see it when no contract declares the value: the address, the value, and the condition.

  • added UpdateFunction type

    update($, target, fn): reads the value, applies fn here in the plugin's environment, writes with ifVersion, and tries again on a miss.

  • added atom const

    A named value with its initial: read answers the initial while nothing is written, so never undefined. Pure; runs in the plugin's environment.

  • added derive const

    A value computed from atoms and references, cached by their versions.

  • added memberOf const

    A family's member for the instance being drawn, keyed by e.requestId.

  • added read const

    Reads an atom, a derived value or a reference through $.state.get; while a ui.render hook draws, that subscribes the drawing.

  • added update const

    Reads, applies fn in the plugin's environment, writes with ifVersion, and tries again on a miss: what a handler closure calls.

6 docs only: reworded, same shape
  • 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.

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

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

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

  • The size of what a surface draws into, in character cells of the surface's monospace metric, and whether its layout docks a pane.

  • What $.ui.open resolves to and what a ui.open hook's { value } holds.

v2.1.280

+40 added · 2 removed · 21 changed · 27 docs only since 2.1.278

The engine

  • changed $.model.complete verb may break

    Runs one text completion through the session's own API client and resolves a result: the reply's text and cost, or why there is no text.

    (request: ModelCompleteRequest) => Promise<string>(request: ModelCompleteRequest) => Promise<ModelCompleteResult>
  • changed $.model.fork verb may break

    Runs one tool-less completion over the session's OWN transcript as the main thread last sent it, so the API serves that prefix from its cache.

    (request: ModelForkRequest) => Promise<ModelForkResult | null>(request: ModelForkRequest) => Promise<ModelForkResult>
  • changed $.session.messages verb may break

    Returns the transcript so far, one SessionMessage per user or assistant message; progress rows, $.ui.log lines and notices are not messages.

    () => Promise<SessionMessage[]>SessionMessagesCall
  • changed $.ui.open verb may break

    Opens a pane, a framed region the surface places and this plugin draws by hooking ui.render for { component: "Pane" }; says if it is drawn.

    (pane: PaneOpenArgs) => Promise<void>(pane: PaneOpenArgs) => Promise<UiOpenResult>
  • added $.process.spawn verb

    Starts a command on the host by its argument vector (no shell) and streams what it writes, piece by piece, then how it ended.

  • added $.session.send verb

    Sends a plain-text message to another agent or session: the event session.send, the model's SendMessage tool's own call and delivery.

  • added $.ui.copy verb

    Puts text on the clipboard of a surface the session draws on, as the DOM's navigator.clipboard.writeText, and says whether it took.

Events

  • changed session.messages event may break

    The argument of $.session.messages(args): {} for the main conversation, { agentId } for one of its agents, as for the form.

    NoArgsSessionMessagesArgs
  • added process.spawn event

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

  • added session.send event

    Fires when a plain-text message is about to leave this conversation for another agent or session (the SendMessage tool, or $.session.send).

  • added session.send result

    { isDelivered: true }, or { isDelivered: false, reason }.

  • added ui.copy event

    The argument of $.ui.copy({ text, surface }), surface filled with the session's first when left out; rewritable, deniable, answerable.

Types

  • removed ContextApiUsage type breaking

    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.

  • removed ModelForkUsage type breaking

    What one fork cost, as the API counted it: the four token counts of the fork's completions summed.

  • changed ChunkOf type extended

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

    export type ChunkOf = {    'turn.step': TurnStepChunk;    'process.spawn': ProcessSpawnChunk;};
  • 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 & EngineMount : EngineNoun<N>;    [N in keyof EventCalls]: N extends 'ui' ? EngineNoun<N> & EnginePress & EngineInput & EngineSelect & EngineMount : EngineNoun<N>;} & {    classic: EngineClassic;};
  • 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.

        session: {        start: (input: SessionStartInput) => Promise<SessionStartResult>;        receive: (input: SessionReceiveInput) => Promise<SessionReceiveResult>;        send: (input: SessionSendArgs) => Promise<SessionSendResult>;        compact: (input?: SessionCompactArgs) => Promise<SessionCompactResult>;        attach: (input: SessionAttachInput) => Promise<SessionAttachResult>;        detach: (input: SessionDetachInput) => Promise<SessionDetachResult>;
  • changed ModelCompleteRequest type extended

    What $.model.complete takes.

        prompt: string;    system?: string;    maxTokens?: number;    effort?: ModelEffort;    timeoutMs?: number;};
  • changed ModelForkResult type may break

    What $.model.fork resolves to: a completion's result (ModelCompleteResult) or that there was nothing to fork yet.

    export type ModelForkResult = {    text: string;    usage: ModelForkUsage;export type ModelForkResult = ModelCompleteResult | {    isAnswered: false;    reason: 'nothing-to-fork';};
  • 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.complete': ModelCompleteResult;    'model.classify': string | undefined;    'model.fork': ModelForkResult | null;    'model.fork': ModelForkResult;    'audio.play': void;    'audio.speak': SpeakResult;    'mcp.call': McpToolResult;…    'session.model': string;    'session.turns': number;    'session.id': string;    'session.messages': SessionMessage[];    'session.messages': SessionMessagesValue;    'session.repo': SessionRepo | null;    'session.surface': RenderSurface | null;    'session.surfaces': readonly RenderSurface[];…    'ui.log': void;    'ui.notice': void;    'ui.invalidate': void;    'ui.open': void;    'ui.open': UiOpenResult;    'ui.close': void;    'ui.panes': readonly UiPane[];    'ui.copy': UiCopyResult;    'ui.blit': UiBlitResult;    'fs.read': string | FsBytes;    'fs.write': void;…    'clock.every': void;    'http.fetch': HttpResponse;    'process.run': ProcessRunResult;    'process.spawn': ProcessSpawnResult;    'settings.read': Settings;    'env.get': string | undefined;    'env.set': void;
  • changed SessionCompacted type extended

    A compaction that stands: the conversation as it reads afterwards, and the counts and request usage the engine recorded when it was the one compacting.

        messages: readonly SessionMessage[];    tokensBefore?: number;    tokensAfter?: number;    usage?: ModelUsage;    skip?: undefined;};
  • changed SessionContextBreakdown type may break

    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.

        skills?: ContextSkills;    autoCompactThreshold?: number;    isAutoCompactEnabled: boolean;    apiUsage: ContextApiUsage | null;    apiUsage: ModelUsage | null;};
  • changed SessionReceiveInput type extended

    The input of session.receive: one inbound delivery, sanitized, before it is queued (a relay's event, a peer's message, a message for an agent).

        origin: SessionReceiveOrigin;    text: string;    event?: SessionReceiveEvent;    agentId?: 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 = {    kind: 'bridge' | 'task-notification' | 'scheduled-trigger' | 'peer' | 'peer-send-message' | 'projects-relay' | 'slack-ping' | 'unclassified';    kind: 'bridge' | 'task-notification' | 'scheduled-trigger' | 'peer-send-message' | 'projects-relay' | 'slack-ping' | 'unclassified';} | {    kind: 'peer' | 'coordinator';    plugin?: string;} | {    kind: 'peer' | 'coordinator';    plugin?: string;    teammate: string;    isVerified: boolean;};
  • changed SessionUsage type extended

    What $.session.usage() answers: when the session began, the context window's fill, the account's rate-limit windows and the session's cost.

    export type SessionUsage = {    startedAt: number;    context: SessionContextUsage;    rateLimits: SessionRateLimit[];    cost?: SessionCost;
  • 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.

    export type StreamNext<N extends StreamingEventName = StreamingEventName, E = Args<N>, O = NextResult<N>, S extends {export type StreamNext<N extends StreamingEventName = StreamingEventName, E = Args<N>, O = EventResult<N>, S extends {    [K in N]?: unknown;} = {    [K in N]: Args<K>;
  • changed StreamingEventName type may break

    The events that stream: their hooks are async generators, next(e) is the stream of everything beneath, and the result is what it returns.

    export type StreamingEventName = 'turn.step';export type StreamingEventName = 'turn.step' | 'process.spawn';
  • changed ToolCallResult type extended

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

        ref?: undefined;    text?: undefined;    isError?: undefined;    isReadOnly?: undefined;} | {    result: ToolResultOf<Name>;    context?: readonly string[];    ref?: number;    text?: string;    isReadOnly?: true;    isError?: undefined;    deny?: undefined;} | {…    text?: string;    ref?: number;    context?: readonly string[];    isReadOnly?: true;    deny?: undefined;};
  • changed ToolUseSummary type extended

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

        result?: unknown;    text?: string;    isError?: true;    agentId?: string;    durationMs?: number;};
  • changed TurnUsage type may break

    What a model turn, or one response inside it, cost as the API reported it: the four token counts (ModelUsage) and the model's id.

    export type TurnUsage = ModelForkUsage & {export type TurnUsage = ModelUsage & {    model: string;};
  • added ApiContentBlock type

    One content block of an ApiMessage: type names its kind (text, tool_use, tool_result, image, document, thinking, ...).

  • added ApiMessage type

    One message of the conversation in Messages API form, as $.session.messages({ as: "api" }) returns it.

  • added ClassicEvent type

    A classic hook event the engine raises on its own, by its own name (SessionStart, Stop): all but PreToolUse, which rides tool.call.

  • added ClassicFields type

    What $.classic.<Event> takes: the event's own fields as its hook sees them on e, less what the engine stamps at every call site.

  • added EngineClassic type

    The classic (settings) hook events as the engine raises them: each a call running the classic.<Event> chain over every plugin hooked on it.

  • added EngineInput type

    A surface typing into an Input a test rendered: the ui.input chain over every plugin hooked on it, the Input's own handler last.

  • added EngineSelect type

    A surface picking an option of a Select a test rendered: the ui.select chain over every plugin hooked on it, the Select's own onSelect last.

  • added InputTarget type

    What $.ui.input takes: the plugin whose hook drew the Input, its key, the field's text, which input it is, instance and surface when several.

  • added ModelApiError type

    Which kind of API failure ended a model call (a completion, a fork), in the word Claude Code classifies every API error with (StopFailure's).

  • What one model call resolves to: the reply when the model answered (isAnswered), else which of three things left it without text (reason).

  • added ModelEffort type

    How hard a request asks the model to think, by the levels the engine and turn.step name: low to max, xhigh between high and max.

  • added ModelUsage type

    What one model call cost, as the API counted it: the four token counts in the API's spelling, summed over the call's responses when it made several.

  • One piece of a spawned child's output as $.process.spawn streams it: which pipe it came from, and the text.

  • The argument of $.process.spawn(request), and the e its hooks see: the command by its argument vector and how the child is started.

  • How a spawned child ended, as the stream of $.process.spawn returns it once every piece has been read: its exit code, or the signal that did it.

  • added SelectTarget type

    What $.ui.select takes: the plugin whose hook drew the Select, its key, the picked option's value, instance and surface when several.

  • A $.session.messages call for the rows (SessionMessage) of the main conversation or of one agent's: agentId alone, no as.

  • A $.session.messages call for the Messages API form (ApiMessage) of the main conversation or, with agentId, of one of this session's agents'.

  • What $.session.messages({ as: "api", agentId }) resolves to: the agent's conversation as ApiMessage, or { deny } (SessionMessagesDeny).

  • What $.session.messages(args) takes and a session.messages hook reads on e: whose conversation (agentId) and in which form (as).

  • $.session.messages: the main conversation's rows with no argument, with { as: "api" } its Messages API form; with agentId an agent's, or deny.

  • What $.session.messages({ agentId }) resolves to when the id names no conversation this session can read: why not, in deny.

  • A $.session.messages({ as: "api" }) call naming no agent: the main conversation, whose answer is always the messages (ApiMessage).

  • What $.session.messages({ agentId }) resolves to: the messages (SessionMessage), or { deny } (SessionMessagesDeny).

  • What a session.messages hook's { value } holds, for any call: the rows (SessionMessage), the Messages API form (ApiMessage), or { deny }.

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

  • added SessionSendArgs type

    session.send's input as a plugin's $.session.send(args) takes it: origin (the calling plugin) and agentId are the engine's to set.

  • added SessionSendInput type

    The input of session.send: one plain-text message about to leave this conversation for another agent or session; the dual of session.receive.

  • Who is sending at session.send: the model through its SendMessage tool, or a plugin through $.session.send; stamped by the engine, pinned.

  • What a session.send hook returns and next(e) and $.session.send resolve to: whether the message was delivered, and why not when not.

  • added UiCopyArgs type

    The argument of $.ui.copy and the input of ui.copy: the text, and which surface's clipboard takes it, the caller's choice.

  • added UiCopyResult type

    What $.ui.copy resolves to and what a ui.copy hook's { value } holds: whether the text reached a clipboard (isCopied), else why not.

  • added UiOpenResult type

    What $.ui.open resolves to and what a ui.open hook's { value } holds.

27 docs only: reworded, same shape
  • Resolves after ms milliseconds; rejects at once when signal aborts.

  • Submits a prompt: the event prompt.submit, the same call the engine makes for a typed prompt; a turn of its own, once the session is idle.

  • The running session, read as plain data; compacting it; and sending a message from it to another agent or session.

  • Holds the session's Anthropic credential on the host and answers an opaque handle and its kind; the secret never reaches the plugin.

  • Returns when the session began, and the context window's fill, the rate-limit windows and the cost as the status line has them, itemized.

  • $.ui noun

    Display: a line under an open dialog, a redraw or a repaint, a log line, panes the surface places, a window or ring, a surface's clipboard.

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

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

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

  • Fires when a delivery reaches the session (a relay's event, a peer's message, a Remote Control prompt), before it is queued; { text }.

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

  • The classic (settings) hook events, one per classic event name: e is the hook's whole stdin input, base fields (transcript_path, cwd) included.

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

  • HookOf type

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

  • What $.model.fork takes.

  • Every member a mounted drawing of component C can have; Mounted<P, C> keeps the ones surface P has the element for (ElementOfAct).

  • Next type

    The rest of the chain, as one hook receives it: made once per dispatch per hook, frozen; next(e) resolves to the downstream result.

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

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

  • The input of session.compact: one compaction of the conversation, about to run; messages is the transcript it runs over.

  • What a session.compact hook returns and what next(e) resolves to: the compaction ({ messages, tokensBefore?, tokensAfter?, usage? }) or a skip.

  • The input of session.end: the session is ending, why, and how to come back to it; every field is the engine's: a hook observes, next(e) passes it on.

  • One tool_result block of a user message.

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

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

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

v2.1.278

No change to the surface since 2.1.277

v2.1.277

+32 added · 2 removed · 23 changed · 29 docs only since 2.1.276

The engine

  • changed $.fs.read verb may break

    Reads a file and returns its text, or with { as: "bytes" } its bytes as { base64 }.

    (path: string) => Promise<string>FsReadCall
  • changed $.fs.stat verb may break

    Returns { kind, size, mtimeMs, isLink } of the path: what it leads to, and whether it is itself a symbolic link. Rejects when missing.

    (path: string) => Promise<FsStat>(path: string, options?: FsStatOptions) => Promise<FsStat>

Events

  • added prompt.attachment event

    Fires once per message the engine injects for the model on its own (a reminder, a mode transition, a mentioned file), as a request carries it.

  • added prompt.attachment result

    { text } (null leaves the attachment out).

  • added prompt.edit event

    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.

  • added prompt.edit result

    { text, cursor }, the box the editor shows next.

Types

  • removed MountedClient type breaking

    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.

  • removed PromptAttachment type breaking

    A pasted or attached non-text item of a prompt; its kind, never its bytes.

  • changed ClientPointerEvent type extended

    One pointer event over a Client's region, as surface.onPointer hands it: region-relative cells, and the sub-cell position where known.

        type: ClientPointerType;    x: number;    y: number;    fine?: {        x: number;        y: number;    };    button?: 'left' | 'middle' | 'right';    shift?: true;    alt?: true;
  • changed EngineMount type may break

    A surface drawing a component instance through the plugins, then driven by key through a handle typed by that surface (Mounted).

    export type EngineMount = {    mount: (target: MountTarget) => Promise<MountedClient>;    mount: <P extends RenderSurface, C extends RenderComponent>(target: MountTarget<P, C>) => Promise<Mounted<P, C>>;};
  • 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.

            suggest: (input: PromptSuggestArgs) => Promise<PromptSuggestResult>;        section: (input: PromptSectionInput) => Promise<PromptSectionResult>;        context: (input: PromptContextInput) => Promise<PromptContextResult>;        attachment: (input: PromptAttachmentInput) => Promise<PromptAttachmentResult>;    };    skill: {        prompt: (input: SkillPromptInput) => Promise<SkillPromptResult>;
  • changed FsAncestorsRequest type extended

    The argument of $.fs.ancestors: the file names to look for in each directory, the file to walk down to, and the directory to walk beneath.

    export type FsAncestorsRequest = {    names: readonly string[];    of?: string;    below?: string;};
  • changed FsEntry type extended

    One entry of $.fs.list: the entry itself, a link not followed.

        name: string;    kind: 'file' | 'dir' | 'other';    size: number;    isLink: boolean;};
  • changed FsStat type extended

    What $.fs.stat resolves with: what the path leads to, whether the path itself is a symbolic link, and where it lands when asked.

        kind: 'file' | 'dir' | 'other';    size: number;    mtimeMs: number;    isLink: boolean;    realPath?: string;};
  • changed HttpInit type extended

    Options of $.http.fetch.

        headers?: Record<string, string>;    body?: string;    auth?: string;    socketPath?: string;};
  • changed ImageProps type extended

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

    export type ImageProps = {    key?: string;    source: ImageSource;    columns: number;    rows: number;
  • changed ImageSource type extended

    The picture an Image shows: base64 bytes the plugin holds (at most 2 MiB decoded), or the name of a file or POSIX shared-memory object it does not.

        rgba: string;    width: number;    height: number;} | {    file: string;    format: 'png';    generation?: number;} | {    file: string;    format: 'rgba' | 'rgb';    width: number;    height: number;    generation?: number;} | {    shm: string;    format: 'rgba' | 'rgb';    width: number;    height: number;    generation?: number;};
  • changed InvalidatableEventName type may break

    What $.ui.invalidate takes: a render event, or one of the six events whose answers the engine caches for the session.

    export type InvalidatableEventName = RenderEventName | 'prompt.section' | 'prompt.context' | 'tool.describe' | 'command.describe' | 'config.describe';export type InvalidatableEventName = RenderEventName | 'prompt.section' | 'prompt.context' | 'prompt.attachment' | 'tool.describe' | 'command.describe' | 'config.describe';
  • changed MountTarget type may break

    What $.ui.mount takes: whose elements the test will act on, the surface that draws, and the component instance the engine asks the plugins for.

    export type MountTarget = {export type MountTarget<P extends RenderSurface = RenderSurface, C extends RenderComponent = RenderComponent> = {    plugin: string;    key: string;    surface: P;    component: C;    props: RenderPropsOf[C];    requestId?: string;    columns?: number;    rows?: number;    viewport?: RenderViewport;};
  • changed OpValueOf type may break

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

        'ui.close': void;    'ui.panes': readonly UiPane[];    'ui.blit': UiBlitResult;    'fs.read': string;    'fs.read': string | FsBytes;    'fs.write': void;    'fs.list': FsEntry[];    'fs.exists': boolean;
  • changed PaneOpenArgs type extended

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

        closeOnEscape?: true;    holdToasts?: true;    rows?: number;    columns?: number;};
  • changed PressTarget type extended

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

        plugin: string;    key: string;    requestId?: string;    surface?: RenderSurface;    link?: PressedLink;};
  • changed PromptSubmitInput type may break

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

    export type PromptSubmitInput = {    text: string;    attachments?: readonly PromptAttachment[];    attachments?: readonly PromptSubmitAttachment[];    context?: readonly string[];    turnId?: string;    wait: boolean;
  • 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' | 'CommandOutput' | 'Spinner' | 'TurnDuration' | 'InfoNotice' | 'SessionMode' | 'PromptHint' | 'AbovePrompt' | 'Pane';export type RenderComponent = 'AskUserQuestion' | 'UserMessage' | 'AssistantMessage' | 'ToolUse' | 'ToolResult' | 'ToolGroup' | 'ToolProgress' | 'CommandOutput' | 'Spinner' | 'TurnDuration' | 'InfoNotice' | 'SessionMode' | 'PromptHint' | 'AbovePrompt' | 'Pane';
  • 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.

    } | {    type: 'Image';    props: ImageProps;    image: {        plugin: string;    };    children?: undefined;} | {    type: 'engine';
  • 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 }).

            isErrored: boolean;        onScreen?: OnScreen | null;    };    ToolProgress: {        tool_use_id: string;        kind: 'background_hint';        hint: string;    };    Spinner: {        word: string;        message: string | null;        suffix: string;        mode: 'requesting' | 'responding' | 'thinking' | 'tool-input' | 'tool-use';    };    TurnDuration: {
  • changed ToolDescribeInput type extended

    The input of tool.describe: one tool's description, at the moment the engine first renders the tool's schema for the model.

    export type ToolDescribeInput = {    tool: string;    description: string;    isDeferred?: true;    provider: Origin;};
  • changed ToolDescribeResult type extended

    What a tool.describe hook returns: the description the model sees for that tool and, when the hook moves it, where the tool waits (ToolDeferral).

    export type ToolDescribeResult = {    description: string;    isDeferred?: ToolDeferral;};
  • changed UiBlitArgs type may break

    What a plugin's $.ui.blit(args) takes: a Raster's next cells (RasterBlitArgs) or a keyed Image's next source (ImageBlitArgs).

    export type UiBlitArgs = {    requestId: string;    key: string;    cells: string;    columns?: number;    rows?: number;};export type UiBlitArgs = RasterBlitArgs | ImageBlitArgs;
  • added ClientScope type

    Which Client of a mounted drawing an act or a read means, by the key its element carries; optional while the drawing holds exactly one.

  • added ElementOfAct type

    The element each surface-dependent act of a mounted drawing reaches: a handle carries the act only where the surface's table has the element.

  • added ElementQuery type

    What a mounted drawing's find and findAll match an element on, every field given at once: its tag, its key, and the text it shows.

  • added FoundElement type

    One element of a mounted drawing as find returns it: the description the plugin's hook (or a Client's module) built, read as plain data.

  • added FsBytes type

    What $.fs.read(path, { as: "bytes" }) resolves with: the file's bytes, base64, since only plain data crosses into a plugin's environment.

  • added FsReadAs type

    How $.fs.read answers: text (UTF-8, the default) or bytes (base64).

  • The options of $.fs.read that ask for the bytes: the call answers { base64 }.

  • added FsReadCall type

    $.fs.read: the file's text, or with { as: "bytes" } its bytes as { base64 }.

  • added FsReadOptions type

    The options of $.fs.read.

  • added FsStatOptions type

    The options of $.fs.stat.

  • added ImageBlitArgs type

    A $.ui.blit argument swapping one of the caller's mounted keyed Images to its next picture; every call sends it, so a stream needs no generation.

  • added MountInputTarget type

    What a mounted drawing's input takes: the Input's key, the text, which of the two inputs it is (submit when unsaid), another plugin's name.

  • added MountKeyEvent type

    What a mounted drawing's key takes: the key as a Client's onKey listener receives it (ClientKeyEvent), and which Client when several.

  • What a mounted drawing's pointer takes: the event as a Client's onPointer listener receives it, in its region's cells, and which one.

  • added MountPressTarget type

    What a mounted drawing's press takes: the Button's key, another plugin's name when the Button is not the mounted plugin's, a link.

  • What a mounted drawing's resize takes: a Client region's size in cells, as the surface measuring it hands it, and which Client.

  • What a mounted drawing's select takes: the Select's key, the picked option's value, another plugin's name when the Select is not its own.

  • added Mounted type

    A drawing of component C the test mounted on surface P: reads over its description, acts on its elements by key, Client acts where P has one.

  • added MountedMembers type

    Every member a mounted drawing of component C can have; Mounted<P, C> keeps the ones surface P has the element for (ElementOfAct).

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

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

  • What a prompt.attachment hook returns: the text the model reads for that attachment, or null to leave the attachment out of the request.

  • added PromptEditInput type

    The input of prompt.edit (prompt-edit/): one edit the person makes in the prompt box, as the draft before it and the splice the editor made of it.

  • added PromptEditOrigin type

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

  • added PromptEditResult type

    What a prompt.edit hook returns and what next(e) resolves to: the box after the edit (PromptBox), which the editor then shows.

  • A pasted or attached non-text item of a submitted prompt; its kind, never its bytes.

  • added RasterBlitArgs type

    A $.ui.blit argument repainting one of the caller's mounted Rasters.

  • added ToolDeferral type

    Where a tool.describe answer places the tool: true behind ToolSearch (its schema loads when the model asks for it), false in the prompt's list.

29 docs only: reworded, same shape
  • $.fs noun

    The file system as the engine's own process reaches it; a relative path is under the session's working directory, and text is UTF-8.

  • Reads the named instruction files in every directory above the session's original working directory, the way the engine reads CLAUDE.md.

  • Returns whether the path exists; rejects only a network location as spelled, which no fs call reaches.

  • Lists a directory: { name, kind, size, isLink } per entry, by name, each entry as it stands (a symbolic link is other with isLink).

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

  • Calls tool on one of the engine's connected MCP servers with the engine's own connection and credentials.

  • Repaints a mounted Raster this plugin's own render hook drew with new cells, or swaps a keyed Image it drew to a new source; no redraw.

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

  • 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 on the notification bar under the prompt for a few seconds, the way the engine's own "context left" notice appears.

  • The argument of $.fs.ancestors({ names, of, below }).

  • Fires once per process for each loaded plugin, before the first prompt, then once per fresh load of one (never /clear); next(e) is { cwd }.

  • Fires once per tool, when the engine first renders the tool's schema in a session; next(e) resolves to { description, isDeferred? }.

  • { description, isDeferred? }.

  • ui.blit event

    The argument of $.ui.blit(...): a Raster's cells or a keyed Image's source; a hook above may rewrite either with next, or { deny }.

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

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

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

  • What a surface module's function receives as its second argument: its elements, the instance's local state, its region, input, clock and port.

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

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

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

  • A surface 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 MCP branch of a tool.call hook's e (and of $.tool.call's input): one variant per declared tool, else the loose McpToolCallInputFallback.

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

  • What $.tool.register takes.

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

  • h const

    The JSX factory (classic runtime, @jsx h; the engine prepends the pragma): a plain-data element from a string tag or a component.

v2.1.276

No change to the surface since 2.1.275
Feedback