glrs
    Preparing search index...

    Type Alias Glrs

    type Glrs = {
        abort: () => boolean;
        activity: (render: (state: Activity) => Line[] | null) => void;
        appendEntry: (type: string, data: unknown) => void;
        autocomplete: (provider: AutocompleteProvider) => { dispose: () => void };
        available: () => readonly FirstPartyExtension[];
        clear: () => "cleared" | "busy" | "empty";
        cli: (name: string, spec: CliSpec) => void;
        clip: (text: string, limit: number) => string;
        columns: () => number;
        command: (name: string, spec: CommandSpec) => void;
        compact: (
            options?: { instruction?: string; keep?: number },
        ) => Promise<Compaction>;
        config: () => unknown;
        entries: (type: string) => readonly unknown[];
        entryRenderer: (type: string, renderer: EntryRenderer) => void;
        events: {
            emit: (name: string, payload?: unknown) => void;
            on: (name: string, handler: (payload: unknown) => void) => void;
        };
        exec: (command: string, args?: readonly string[]) => Promise<ShellResult>;
        filterTools: (keep: (name: string) => boolean) => { lift: () => void };
        flag: (name: string, spec: FlagSpec) => void;
        footer: (render: () => Line[]) => void;
        forkSession: (at?: number) => Promise<SessionInfo>;
        hasUI: boolean;
        history: () => readonly ModelMessage[];
        idle: () => boolean;
        inspect: () => Loaded;
        key: (spec: KeySpec) => void;
        markdown: (transform: (text: string) => string) => void;
        messageRenderer: (renderer: MessageRenderer) => void;
        mode: "tui" | "print" | "cli";
        model: () => ModelInfo | null;
        models: () => Promise<readonly ModelInfo[]>;
        on: <E extends EventName>(event: E, handler: Handler<E>) => void;
        pending: () => number;
        print: (content: string | Line[], tone?: Tone) => void;
        prompt: (text: string | (() => string)) => void;
        provider: (provider: ExtensionProvider) => { dispose: () => void };
        reload: () => Promise<void>;
        rememberModel: () => Promise<WriteOutcome>;
        root: string;
        send: (text: string, options?: { label?: string; steer?: boolean }) => void;
        session: () => SessionInfo;
        setExtension: (name: string, on: boolean) => Promise<ExtensionChoice>;
        setLabel: (event: number, label: string) => void;
        setModel: (label: string, variant?: string) => Promise<void>;
        setSessionName: (title: string) => void;
        setThinkingLevel: (level: string) => Promise<void>;
        settings: () => Readonly<Settings>;
        shutdown: () => void;
        status: (render: () => string | null) => void;
        switchSession: (id: string) => Promise<boolean>;
        systemPrompt: () => string;
        tool: <Schema extends z.ZodType>(spec: ToolSpec<Schema>) => void;
        tools: () => readonly string[];
        truncateHead: (text: string, limit: number) => string;
        ui: Ui;
        usage: () => Usage;
        z: typeof z;
    }
    Index
    abort: () => boolean

    Interrupt the running turn. True if there was one.

    activity: (render: (state: Activity) => Line[] | null) => void

    Replace the activity row — what the turn is doing, how long it has been doing it, and how to stop it. Return null to leave glrs's own. The first extension to return lines wins, so a project can override a personal one the same way it overrides a command.

    appendEntry: (type: string, data: unknown) => void

    Persist your own data in the session file. Never sent to the model.

    autocomplete: (provider: AutocompleteProvider) => { dispose: () => void }

    Add completions for a sigil such as #.

    available: () => readonly FirstPartyExtension[]

    First-party extensions, and whether each is on, off, or has never been decided. The three states come from config: named in extensions.load, named in extensions.disable, or in neither.

    clear: () => "cleared" | "busy" | "empty"

    Drop the conversation the model replays. The transcript is untouched.

    cli: (name: string, spec: CliSpec) => void

    Add a subcommand to the glrs executable: g.cli("wt", …) makes glrs wt … work. It runs without a session, so g.print writes to stdout and the members needing a model or a screen throw rather than pretend.

    clip: (text: string, limit: number) => string

    Clip to a width, counting what the terminal counts: graphemes, not chars.

    columns: () => number

    Terminal width. Anything wider than this wraps, so measure before drawing.

    command: (name: string, spec: CommandSpec) => void

    Register a slash command the user can type.

    compact: (
        options?: { instruction?: string; keep?: number },
    ) => Promise<Compaction>

    Summarise the older part of the conversation and carry the brief forward, so a session can outlive its context window. keep is roughly how many tokens of recent turns to leave verbatim.

    config: () => unknown

    This extension's own config, from extensions.settings.<name> in any of the three scopes, merged. undefined when nothing configured it. glrs never looks inside, so the shape is yours to define and yours to validate.

    const settings = g.config() as { greeting?: string } | undefined;
    g.print(settings?.greeting ?? "hello");
    entries: (type: string) => readonly unknown[]

    Everything this session has recorded under type, oldest first — including entries written before a --resume, since a resumed session replays them.

    appendEntry had no counterpart, so an extension could write to the session file and never read it back: storage you cannot read is not storage, and the only way to recover your own data was to open session().file and parse it yourself.

    entryRenderer: (type: string, renderer: EntryRenderer) => void

    Render one kind of extension-owned session entry.

    Not covered by the 1.0.0 stability promise: may change in a minor.

    events: {
        emit: (name: string, payload?: unknown) => void;
        on: (name: string, handler: (payload: unknown) => void) => void;
    }

    A bus for extensions to talk to each other.

    exec: (command: string, args?: readonly string[]) => Promise<ShellResult>

    Run a shell command in the project root.

    filterTools: (keep: (name: string) => boolean) => { lift: () => void }

    Narrow what the model can call, from the next turn onward. Return false for a tool to withhold it. Withholding beats instructing: a tool that is absent cannot be talked into being used.

    Every extension's filter has to agree, so restrictions compose and can only narrow. This replaced a setTools(names) that set one global list — a read-only extension and a no-network extension would each call it, the second would silently undo the first, and neither could see the other.

    Returns a handle that lifts your own filter and nobody else's.

    flag: (name: string, spec: FlagSpec) => void

    Register a CLI flag: glrs --name value.

    footer: (render: () => Line[]) => void

    Draw extra rows above the status line. Return [] to show nothing.

    forkSession: (at?: number) => Promise<SessionInfo>

    Fork this session after lifecycle gates approve it.

    Not covered by the 1.0.0 stability promise: may change in a minor.

    hasUI: boolean

    False outside the TUI: nothing can be asked and nothing can be drawn.

    history: () => readonly ModelMessage[]

    Messages currently carried into the next model call.

    Not covered by the 1.0.0 stability promise: may change in a minor.

    idle: () => boolean

    Is nothing running and nothing queued?

    inspect: () => Loaded

    What is loaded: commands, skills, extensions.

    key: (spec: KeySpec) => void

    Bind a key. Only fires when the composer has focus and no overlay is up.

    markdown: (transform: (text: string) => string) => void

    Transform assistant markdown before it is rendered. Display only.

    messageRenderer: (renderer: MessageRenderer) => void

    Render durable transcript messages before the default renderer.

    Not covered by the 1.0.0 stability promise: may change in a minor.

    mode: "tui" | "print" | "cli"

    "tui" when a terminal is attached, "print" for a headless -p run.

    model: () => ModelInfo | null

    The active model, or null when nothing has been chosen yet.

    models: () => Promise<readonly ModelInfo[]>

    Every model the catalogue knows, each carrying what its provider is missing.

    on: <E extends EventName>(event: E, handler: Handler<E>) => void

    Subscribe to a lifecycle event.

    pending: () => number

    How many turns are waiting behind the running one.

    print: (content: string | Line[], tone?: Tone) => void

    Write into the transcript. Pass Line[] when you want it styled.

    prompt: (text: string | (() => string)) => void

    Contribute a line to the per-turn preamble. Pass a function to have it rendered fresh each turn — that is how a contribution reflects something that happened during the session rather than only what was true at load. Return "" to say nothing this turn.

    provider: (provider: ExtensionProvider) => { dispose: () => void }

    Register a model provider, including providers with their own OAuth flow.

    reload: () => Promise<void>

    Re-read skills, commands, and extensions from disk.

    rememberModel: () => Promise<WriteOutcome>

    Write the active model and variant into the project's config, so the next session starts on it. Returns "not-allowed" unless agentConfigAllowlist names "model", or when no model has been chosen and there is nothing to record; "already" when the file already says this. Separate from setModel on purpose: switching for one turn and choosing for good are different acts, and only the second is worth writing to disk.

    root: string

    The project root every path is resolved against.

    send: (text: string, options?: { label?: string; steer?: boolean }) => void

    Start a turn. label is what the transcript shows instead of the text. steer joins the turn already running, at its next step boundary, so the model reads it before it chooses its next action; without it the message waits until the agent has finished all its work. With nothing running the two are the same thing — a turn.

    session: () => SessionInfo

    This session: id, file on disk, title, event count.

    setExtension: (name: string, on: boolean) => Promise<ExtensionChoice>

    Record that one should or should not load, by writing extensions.load or extensions.disable in the project's config. Returns "not-allowed" unless agentConfigAllowlist names "extensions" — config is hand-edited unless you have said otherwise.

    setLabel: (event: number, label: string) => void

    Label an event for tree/bookmark UIs.

    Not covered by the 1.0.0 stability promise: may change in a minor.

    setModel: (label: string, variant?: string) => Promise<void>

    Switch model, as "provider/model-id". Takes effect on the next turn.

    setSessionName: (title: string) => void

    Rename the session, as the resume picker shows it.

    setThinkingLevel: (level: string) => Promise<void>

    Change reasoning effort without changing the active model.

    settings: () => Readonly<Settings>

    This session's resolved settings, merged from every config file that applied. Provider blocks are absent: they hold API keys, and an extension that wants them can read the files itself rather than be handed them.

    shutdown: () => void

    Quit glrs.

    status: (render: () => string | null) => void

    Contribute a segment to the status line. Return null to show nothing.

    switchSession: (id: string) => Promise<boolean>

    Switch the active session after lifecycle gates approve it.

    Not covered by the 1.0.0 stability promise: may change in a minor.

    systemPrompt: () => string

    The system prompt exactly as the model receives it.

    tool: <Schema extends z.ZodType>(spec: ToolSpec<Schema>) => void

    Register a tool the model can call.

    tools: () => readonly string[]

    The tools the model can currently call.

    truncateHead: (text: string, limit: number) => string

    Keep the tail of a long value and mark the omitted head.

    Not covered by the 1.0.0 stability promise: may change in a minor.

    ui: Ui

    Prompts, pickers and the composer. Throws in print mode.

    usage: () => Usage

    Tokens, cache hits and cost: the last call and the session total.

    z: typeof z

    Zod, for describing a tool's input. Handed over rather than imported: an extension in ~/.config/agents/extensions has no node_modules of its own to resolve it from, and one that works in your home directory but not in a project is not a working extension. An extension needs no imports at all.