glrs
    Preparing search index...

    sessions

    a session is one conversation. it has an id, and it is stored as a log of events.

    $XDG_DATA_HOME/glrs/sessions/<id>.json, else ~/.local/share/glrs/sessions/. prompt history is prompts.json beside them.

    {
    "schema": 2,
    "id": "3f9a1c2b",
    "createdAt": "",
    "updatedAt": "",
    "cwd": "",
    "events": [],
    "contextTokens": 0
    }

    .../glorious/sessions/ is read, never written. a session resumed from there is saved to the new path.

    a session is a log. each record in it is an entry. the extension API calls them entries too (g.appendEntry, g.entries).

    these are not lifecycle events, which are announcements an extension hooks while glrs runs. entries are what is on disk.

    entry recorded when
    user you send a message. carries steer when it joined a running turn
    assistant the model answers
    tool a tool runs. carries its input and result, so an extension can redraw it
    reasoning the model reasons, kept in full
    usage a model call reports tokens and cost
    turn a turn ends, carrying the raw messages
    notice, error glrs says something
    cleared, compacted the replay boundary moves
    custom an extension's own data. never sent to the model

    the file is written on usage and turn, at turn end, and at idle. a notice reaches disk on the next of those.

    action effect
    glrs --resume <id> reopen that session
    glrs --resume pick from a list, newest first
    /fork copy the whole session to a new id
    /fork 42 copy the session up to entry 42 into a new id

    a fork leaves the original untouched. the copy is on disk immediately, so glrs --resume <new-id> opens it.

    the context is what the model is working from: the system prompt, the conversation so far, and what rode along with this turn. the status line shows how much of the model's window it fills.

    /clear drops what the model replays and keeps the transcript on screen.

    past 75% of the window the older part of the conversation is summarised and replaced by one message. compactAt moves that fraction, and 0 turns it off while leaving /compact working:

    { "compactAt": 0.5 }
    

    on a million-token model 75% is 787,500 tokens, which is both late and expensive on every turn that reaches it. a smaller fraction is often the better trade.

    the window it plans against is the smaller of the model's and compactWindow, 256,000 by default. a million-token model is compacted as if it had 256k, because every turn past there re-sends all of it at full price; a model whose window the catalogue does not know is assumed to have 256k rather than never being compacted. providers.<id>.models.<id>.metadata.context still wins.

    compactModel names who writes the brief, as provider/model-id. the session's own model when unset. summarising suits something cheaper and faster, provided its window is at least compactWindow:

    { "compactModel": "azure/gpt-5.4-nano" }
    

    a turn that would pass the same line stops at its next step rather than taking another, says (compacting to make room: send "continue" to resume), and compaction follows. before that, a turn could go from under the threshold to past the window inside itself and be refused outright with Your input exceeds the context window of this model: idle is too late to look, and the check before a new message is too early.

    the brief is written from a snapshot, while the session is idle or while a turn is running: the check runs on every step, because an agentic turn is where the context grows.

    started at idle, it holds the queue. anything you type waits, then runs on the compacted history, because a turn that started anyway would pay exactly what the compaction was there to save. esc abandons it; the queue stays held, as it does whenever esc lands with messages waiting, and sending releases it.

    started mid-turn, it holds nothing: the turn is already running. a turn only appends, so the brief lands once the turn does and nothing the turn added is lost. esc stops the turn and leaves the brief to finish.

    the brief is lossy by design. the messages it replaced are written beside the session, unchanged, one file per compaction:

    <data>/glrs/sessions/artifacts/<session id>/2026-09-06T14-02-11-000Z.md
    
    ---
    label: fixed three failing auth tests
    createdAt: 2026-09-06T14:02:11.000Z
    messages: 244
    note:
    ---
    [user]
    the login redirect test is failing
    [tool-call read]
    { "path": "src/auth/redirect.ts" }
    [tool-result read]
    export const redirect = (url) => url.split('?')[0];
    …
    

    the label is the first line of the brief. the compaction-artifacts extension gives the agent compaction_list, compaction_read, compaction_annotate and compaction_delete over them, and /artifacts lists them for you. the agent is told they exist only once one does. disable the extension and the files still land.

    <earlier-conversation>
    …
    </earlier-conversation>
    

    a tool result separated from the call it answers is an invalid request, so the cut walks back to the newest user message that still leaves about 20k tokens of recent work. everything after it survives verbatim. everything before it is the brief.

    /compact forces it early. /compact <instruction> steers what the brief keeps.

    see also: turns, a turn, resume and fork