Context management
The store has two layers. The first layer is an event log. Glider only adds to this log, and each event has RUNTIME provenance. The second layer is a graph of entities and edges. Each entity has EXTRACTED, INFERRED or RUNTIME provenance. A turn index in memory gives sticky routing.
Why Glider keeps a context store
A Cursor Composer summary message and a subagent message look like new small prompts. Without a memory layer, the router sends them to the local model, which is not correct. The graph tells the router if a message is still part of turn family X. Refer to MITM · sticky-cloud.
The layers
| Layer | Function | Storage |
|---|---|---|
| Event log | Glider only adds events. The event names include RouteDecided, FulfilledLocal, OriginPassthrough, TurnOpened and StickyBound. | ~/.glider/context/events-*.jsonl |
| Entity and edge store | Files, directories, symbols and the relations between them | ~/.glider/context/entities.jsonl |
| Episodes | Short summaries of a session. Glider adds them to a local prompt. | contextkit (rings in memory) |
What Glider keeps, and for how long
| Setting | Default | Function |
|---|---|---|
context.max_events | 4096 | The size of the event ring in memory |
context.retain_days | 14 | How long the events-*.jsonl files stay on disk. POST /api/context/prune uses this value. |
context.warm_load_days | 2 | How many days of JSONL Glider reads again when it starts |
How to query the store
The context_query tool and Store.Query search the two layers:
context_query: <turn_id> [key=clone_path|goal|plan|file-tree] [kind=note|file|dir|symbol] [prov=RUNTIME|EXTRACTED|INFERRED] [path=<from>-><to>] [neigh=id] [explain=id] [communities=1] [limit=N] keyword…
Keywords accept OR or | to match any term. For example, goal OR plan.
Explain(id) gives the neighborhood of an entity, its hubs, and the path to a hub. DetectCommunities finds connected components. It is a first version, and it is not the full Leiden algorithm.
What the local model receives
Glider never sends the full transcript. It sends a pack with a limited size. The pack has the most recent user turn and a maximum of N short episodes. The settings transform.local_context and transform.local_episode_count control the pack. The Overview page of the dashboard shows the episodes from GET /api/context/episodes.
What a delegate receives
This is a different layer from the store above, and it has a different file. Glider keeps one continuity record for each workspace. The record holds what occurred in the calling session: the turns of the user, and what each earlier delegate changed. Glider puts a block from this record at the start of every delegate call. The delegate sees the block with the name "Earlier in the calling session".
How context moves across CLIs
The diagram shows one session with three turns. The person stays in Claude Code for all three. Turn 2 goes to cursor-agent, and turn 3 goes to agy. Neither delegate can see the Claude Code session, and neither can see the other. The continuity record is the only thing that connects them.
Two properties matter, and both are easy to miss:
| Property | Why it is there |
|---|---|
| A turn with no flag is still recorded | Most turns in a session are ordinary chat. If Glider recorded only the delegate turns, a delegate would receive the instruction and nothing that led to it. |
| The outcome returns under the identity of the front CLI | The result belongs to the session that sent the work, and not to the delegate that did it. A later delegate in the same workspace then knows the run occurred. Without this, a second delegate can undo the change the first one made. |
A delegate receives a file, and not a longer prompt. Glider makes a private
directory for each run and writes the context into the file that the vendor already reads
by itself: AGENTS.md for cursor-agent and agy,
glider-context.md for claude. The directory goes away when the run ends.
| Item | Value |
|---|---|
| The file | ~/.glider/continuity/<name>-<hash>.md, one for each workspace |
| The record | A ring of 60 entries |
| The block | A maximum of 20 entries, and a maximum of 20000 tokens |
The record stays in ~/.glider, and not in your project. Glider does the
bookkeeping, and the project does not own that data. A file in your repository would show in
git status permanently.
How Glider selects the entries
Glider does not take the last N entries. Time is not relevance: a person who does five turns about CSS, and then delegates a defect in Go, must not receive five turns about CSS. Three rules control the selection:
| Rule | What it does |
|---|---|
| Ranking | Glider scores each entry against the task of THIS delegate. A rare term has more weight than a frequent one. At equal relevance, the result of an earlier delegate wins against an ordinary turn, because it describes a change that a delegate already made to these files. |
| A protected tail | The 2 most recent entries go in the block with no score. What the user says now is never noise. |
| Middle-out truncation | An entry that is too long loses its MIDDLE. The start gives the objective, and the end gives the condition. |
Three settings control the size. Each one is a ceiling, and not a target:
| Setting | Default | Function |
|---|---|---|
context.background.token_budget | 20000 | The full block |
context.background.max_entries | 20 | The count of entries |
context.background.max_entry_chars | 4000 | One entry, before middle-out truncation |
Know the cost. This block goes with EVERY delegate call. Therefore a large budget gives better orientation, and it makes each delegation more expensive and more slow.
Compaction
A record with more than 40 entries gets compaction: Glider replaces the older entries with
one summary, and keeps a tail of entries with no change. This always occurs. The
context.summary settings only select WHO writes the summary.
Compaction runs in the background. It never runs on the clock of a request. Therefore the list of sources can contain an option as slow as the cold start of a CLI.
| Source | What it uses | What it costs |
|---|---|---|
origin | An installed agent CLI, with no window | The subscription that you have. No API credits. Approximately 20 s. |
cloud | A BYOK cloud backend | Your own API credits |
local | A local model | Nothing |
none | Stops the list here | Nothing |
The default order is [origin, cloud, local]. Glider tries each source until one
gives an answer. A source with no configuration does not cause an error. Glider goes to the
next source.
If each source fails, or if context.summary.enabled is false,
Glider uses a deterministic digest. The digest keeps the first turns and
every delegate outcome, and it counts what it removed. Compaction never fails and leaves
nothing.
Glider puts [session summary] at the start of a compacted entry. A later pass
reads that mark and never makes a summary of a summary. Repeated compaction is where these
systems lose data.
How to examine the store
GET /api/context/recent
GET /api/context/turns · /api/context/turns/{id}
GET /api/context/episodes
GET /api/context/export
POST /api/context/index-tree
POST /api/context/index-symbols
GET /api/context/communities?turn_id=
GET /api/context/explain?turn_id=&id=
POST /api/context/prune
The functions RecordHoopContext and LookupHoopContext in
contextgraph stay in use. The removed stage runner did not use them.
IndexFileTree writes the file-tree key, and the
key= path in QueryWith reads it. But the thread facts
(RecordThreadWave and RecordEpisodeFact) have no caller today.
They are unused library code, not a function of the product.
The full description is in planning/routing_and_context.md.