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.
Persist your own data in the session file. Never sent to the model.
Add completions for a sigil such as #.
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.
Drop the conversation the model replays. The transcript is untouched.
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 to a width, counting what the terminal counts: graphemes, not chars.
Terminal width. Anything wider than this wraps, so measure before drawing.
Register a slash command the user can type.
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.
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");
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.
BetaentryRender one kind of extension-owned session entry.
Not covered by the 1.0.0 stability promise: may change in a minor.
A bus for extensions to talk to each other.
Run a shell command in the project root.
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.
Register a CLI flag: glrs --name value.
Draw extra rows above the status line. Return [] to show nothing.
BetaforkFork this session after lifecycle gates approve it.
Not covered by the 1.0.0 stability promise: may change in a minor.
False outside the TUI: nothing can be asked and nothing can be drawn.
BetahistoryMessages currently carried into the next model call.
Not covered by the 1.0.0 stability promise: may change in a minor.
Is nothing running and nothing queued?
What is loaded: commands, skills, extensions.
Bind a key. Only fires when the composer has focus and no overlay is up.
Transform assistant markdown before it is rendered. Display only.
BetamessageRender durable transcript messages before the default renderer.
Not covered by the 1.0.0 stability promise: may change in a minor.
"tui" when a terminal is attached, "print" for a headless -p run.
The active model, or null when nothing has been chosen yet.
Every model the catalogue knows, each carrying what its provider is missing.
Subscribe to a lifecycle event.
How many turns are waiting behind the running one.
Write into the transcript. Pass Line[] when you want it styled.
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.
Register a model provider, including providers with their own OAuth flow.
Re-read skills, commands, and extensions from disk.
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.
The project root every path is resolved against.
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.
This session: id, file on disk, title, event count.
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.
BetasetLabel an event for tree/bookmark UIs.
Not covered by the 1.0.0 stability promise: may change in a minor.
Switch model, as "provider/model-id". Takes effect on the next turn.
Rename the session, as the resume picker shows it.
Change reasoning effort without changing the active model.
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.
Quit glrs.
Contribute a segment to the status line. Return null to show nothing.
BetaswitchSwitch the active session after lifecycle gates approve it.
Not covered by the 1.0.0 stability promise: may change in a minor.
The system prompt exactly as the model receives it.
Register a tool the model can call.
The tools the model can currently call.
BetatruncateKeep 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.
Prompts, pickers and the composer. Throws in print mode.
Tokens, cache hits and cost: the last call and the session total.
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.
Interrupt the running turn. True if there was one.