magi-code 0.95.2

Repository-aware CLI coding agent for terminal work
Documentation
# Sessions, context, and cache

[Feature docs index](README.md) · [Repository README](../../README.md)

Resume work, shorten provider context without losing local history, export a session, or remove old sessions. Paths use `~/.magi-code` by default; `MC_HOME` relocates that directory.

## Resume or start fresh

Use `magi-code --continue` for the latest eligible session, `--resume <SESSION_ID>` for a specific session, or `/new` for a fresh one. `--no-session` disables persistence and cannot be combined with attachment flags.

Sessions are JSONL files under `~/.magi-code/sessions`. They store prompts, responses, diagnostics, tool calls/results, context/cache events, rewind events, and subagent summaries. Slash-command errors become diagnostics when a session is active.

Provider requests replay the ordered conversation until a valid compaction checkpoint. User turns, assistant text, provider response items, tool calls, and results remain distinct. Failed or cancelled partial assistant text remains provider-visible. Replay includes all entries, but historical tool outputs over 24,000 characters keep only their first and last 6,000 characters with omission markers. Failed-turn recovery may use bounded summaries instead of exact structured replay. Raw durable history remains unchanged.

Local-only events (`hook_diagnostic`, `hook_lifecycle`, `context_cache`, `session_title`, and `diagnostic`) stay out of provider replay. Hook lifecycle records preserve sanitized start/success/failure history for local audit and TUI replay without rerunning hooks. They also stay out of recent-context helpers, budget accounting, and cache keys.

### Provider cache affinity and diagnostics

Codex requests send stable `session-id` and `thread-id` values for each conversation. Child sessions have separate identities. A bounded server-issued `x-codex-turn-state` value persists only within one execution turn, including tool continuations and retries. New turns and account changes do not inherit it. This improves routing consistency but does not guarantee cache hits.

Codex `provider_stream_trace` records include `request_sequence` and `response_identity.cache`: attempt timing, turn identifier, salted fingerprints of instructions/tools/input/configuration, routing-header presence, and whether the previous attempt preserved its complete input prefix and configuration. Fingerprints are comparable only within that turn. Salts and raw routing values are never saved. These diagnostics remain local-only. Join sequence data to finalized usage from the same run to separate prefix changes from unexplained cache losses. Retries count as attempts, not extra successful requests.

### Compact a long session

Run `/compact [custom instructions]` to summarize an active persisted session. It uses the active provider/model unless both `agent.compaction.provider` and `agent.compaction.model` are nonblank. A partial or blank override, missing session, disabled persistence, auth/config failure, or oversized request fails without creating a checkpoint.

Instructions come from bundled `prompts/compact.md` or `$MC_HOME/prompts/compact.md`. The request contains current structured replay, including historical tool calls/results, but no tools or tool definitions.

After success, compaction copies current JSONL byte-for-byte to an immutable `.history/<session-id>/` generation. It then atomically replaces the active file with a checkpoint plus events appended after the bounded snapshot. Future requests use only the latest valid summary and later provider-visible events. Archives keep raw audit history but do not supply normal replay, listing, or title reads. Repeated compaction rotates the active generation; `/new` starts a separate session.

Compaction separately checkpoints structured `execution_effects`. Dispatched tool results record bounded mutation-path evidence, including partial edits. Counters and call/path samples survive restores and repeated compaction. Summarizers and resumed agents receive a recorded-evidence note: a clean working tree does not prove no edits occurred. This is an audit record, not permission enforcement or a filesystem sandbox. Shell calls are counted, but their side effects and complete reversal are not independently verified. Invalid evidence is marked incomplete, never treated as proof of no mutations. Full tool-call/result records remain in `.history`.

### Configure automatic compaction

Automatic compaction is enabled by default, including when `agent.compaction.auto` is absent. It triggers at 80% of the effective context window, with no configured fixed token threshold. Set `agent.compaction.auto.enabled` to `false` to disable it, except for `claude-subscription`, which always enables automatic compaction for eligible sessions. The defaults are:

```json
{
  "agent": { "compaction": {
    "auto": {
      "enabled": true,
      "max_compactions_per_run": 4,
      "threshold_percent": 80,
      "threshold_tokens": null
    }
  } }
}
```

| Setting | Rule |
| --- | --- |
| `threshold_percent` | Default `80`; `1` to `100`, projected next-request tokens as a percentage of the active model maximum. `null` disables this trigger. |
| `threshold_tokens` | Default `null` (unset); accepts a positive fixed projected token count. |
| `max_compactions_per_run` | `0` to `255`, default `4`; `0` removes only the per-run count cap, not provider, tool, context, or cancellation bounds. |

At least one trigger is required while enabled. With both, the first threshold reached applies: `min(ceil(max_tokens * percent / 100), threshold_tokens)`. For only a fixed threshold, set `threshold_percent` to `null`. This differs from the hard usable budget (`max_tokens - reserve_tokens`), though scheduling still requires context budgeting.

Automatic compaction applies to persisted primary and child sessions at successful completed-turn or settled tool-continuation boundaries, after required writes and cancellation checks. It excludes active tools, incomplete-stream/reasoning-only recovery, cancelled/failed/partial runs, unsafe tool-progress recovery, `--no-session`, title/vision/tool-internal jobs, and compaction requests. Child compaction changes only that child's file in `sessions/subagents/`.

At tool boundaries, runtime projects the pending continuation, including observed steering for that primary or child run without acknowledging it. At completed turns, it projects pending steering or literal lowercase `continue`. At or above cutoff, it compacts before the next request under manual compaction rules, then confirms the compacted request falls below the same cutoff. Another compaction requires new provider-visible growth and remaining count allowance. Hard-budget preflight counts toward a finite cap.

After compaction, pending steering for that run takes precedence and is submitted in collapsed order. Otherwise runtime appends and sends `continue` with `origin: "automatic_compaction"`; CLI/TUI shows `you [automatic]: continue`. Manual `/compact` does not add this continuation merely because auto mode is enabled.

Failure stops continuation. Before checkpoint commit, the old active file remains authoritative; afterward, the new checkpoint does. No request is sent without durable continuation input, and steering is acknowledged only after append succeeds. Fix the bounded, sanitized error, then retry primary input or child task. `/compact` and `/new` recover primary sessions, not child sessions.

Selected-subagent steering in Mission Control uses the same child session and continuation path. Unpersisted input remains recallable after failure or cancellation but is not durable until appended. The in-memory control registry holds up to 64 active or pending child entries and refuses new controls rather than dropping accepted input. Completed children reject new steering, but `Alt-C` can recall pending input in the viewer. Pending child input must be recalled before a new primary run.

### Compaction visibility and authority

Mission Control shows one primary transcript card per compaction: progress becomes the full sanitized checkpoint summary, without truncation. Child compaction activity retains the same summary with bounded display/truncation metadata. Reopening a session rebuilds the summary card from its checkpoint. Cancellation or a later continuation failure does not discard a committed checkpoint.

### Handle context limits

| Setting | Default |
| --- | ---: |
| `agent.context.enabled` | `true` |
| `agent.context.max_tokens` | `128000` |
| `agent.context.reserve_tokens` | `16384` |
| `agent.context.keep_recent_tokens` | `20000`; only bounded non-provider helpers, not active replay |

Budget resolution starts with global/default context settings, uses cached model-catalog context-window metadata when available, then applies exact `agent.context.model_overrides["provider/model"]`. Overrides affect normal runs, context display, and compaction fit checks. They cannot increase the provider's actual limit.

For `claude-subscription`, every model uses a 202,000-token input ceiling instead of catalog or fallback capacity. Lower model overrides still apply. `agent.compaction.claude_subscription` controls separate thresholds: defaults are 100% and 202,000 tokens, capped at the effective conversation maximum. When the compaction provider is also `claude-subscription` (inherited or explicitly selected), `reserve_tokens` reduces that maximum; default 16,384 leaves 185,616 tokens. Compaction requests retain the full 202,000-token ceiling. The generic output reserve is not subtracted from this input-only limit.

Set `allow_compaction` to `false` and select another provider's **Compaction model** under `/settings` → **Agent settings** to keep the full 202,000-token conversation capacity. Saving without an explicit alternative is rejected. Context checks and automatic compaction remain enabled; general `agent.compaction.auto` settings do not apply to Claude subscription. Primary, side, and child runs use the same limits. The prompt border's `Current Ctx`, percentage bar, and `Compact` threshold, plus `magi_control`'s `context_usage` percentage, use the effective capacity. Saving refreshes the displayed policy; subsequent runs use the updated settings.

Claude subscription runs have no per-run compaction-count cap; safe-boundary restrictions still apply. The hard budget checks both the local estimate and the usage-calibrated estimate before continuation, allowing eligible runs to compact before the transport rejects an oversized estimate. Neither estimate guarantees acceptance by Claude CLI's own prompt checks. Keep headroom for estimation error, CLI-added content, and request growth. If existing history is already too large to summarize through Claude CLI, select a compaction provider/model with a larger usable budget, such as `anthropic` with separate API-key billing, or start `/new`. Increasing a Claude-subscription model override cannot bypass the ceiling.

If Claude CLI rejects a prompt as too long despite local estimates, eligible persisted runs attempt one automatic compaction and resume with saved input and tool work included in the summary. Compaction uses the configured compaction provider/model and respects cancellation and persistence checks. A second rejection stops the run rather than compacting repeatedly. If the summary request also exceeds its provider's limit, compaction stops without replacing session history; choose a larger compaction model or start `/new`.

Initial counts are local estimates: supported Codex model families use embedded `tiktoken-rs` tables; other providers use character estimates. Anthropic and Claude subscription continuations use reported input usage plus the estimated change in provider-visible content. Skill reads rebuild the complete projected request before that comparison, preserving duplicate-skill references. Code Mode's inner audit results are excluded; returned outer content and explicit context injections count. These continuation counts remain estimates, not exact tokenizer results. Catalog budgets use explicit context/input metadata only, never output-token limits.

If the full request exceeds `max_tokens - reserve_tokens`, eligible persisted primary/child runs can automatically compact before recording or sending the current input, independently of the post-turn trigger. This preflight preserves expanded prompt injections, checks fit, and sends the original input once without an automatic `continue`. It requires enabled auto compaction, a session, no active cancellation, and input plus static request content that fits without history. Child preflight rotates only that child's session.

If preflight cannot help, use `/compact` for a primary session, choose a larger compaction model/context override, shorten the input, or use `/new`.

### Recover an incomplete stream

Primary and child loops allow one ephemeral continuation for recoverable partial assistant text or parser-only partial tool-call progress, provided no completed tool call or provider function-response item entered agent state. This includes transport/body failures. Incomplete arguments are abandoned, never executed or reconstructed.

Recovery adds available partial assistant text plus `Continue` only to in-memory replay and emits `AutomaticUserPrompt`; it does not persist synthetic `user_input`. Completed tool/protocol items, cancellation, or a second failure remain terminal.

### Export a session

`/export` creates `$MC_HOME/exports/<session-id>-<UTC>[-N].zip` for the active persisted session on Unix. It accepts no arguments or custom destination, never overwrites, and provides no import command. It does not change the session or call a provider.

The ZIP contains byte-for-byte session JSONL, optional primary metadata, immutable compaction generations, referenced child JSONL/metadata/history, and `manifest.json` with sizes, SHA-256 digests, child relationships, and completeness warnings. Missing or unsafe optional descendants are omitted with bounded warnings; missing or unsafe primary data aborts. Session locks remain held through publication.

The unencrypted archive contains raw, potentially sensitive session, project, and tool data. Owner-private permissions do not make sharing safe. Mission Control exports off the UI loop while idle; see [TUI export behavior](mission-control-tui.md#switch-or-export-a-session).

### Delete old sessions

`/prune-sessions` uses 30 days; `/prune-sessions 7` uses seven. The argument must be a positive integer. Deletion is permanent for resume purposes. Mission Control rejects pruning during an active prompt/tool run.

Manual pruning considers only regular top-level `*.jsonl` files with valid IDs. Age comes from the latest valid event timestamp, or mtime when valid timestamps are unavailable. Files at or newer than the cutoff and live writer leases stay. It ignores directories, nested files, symlinks, other extensions, caches, auth/settings, and non-session data.

After deleting primary data, pruning attempts its metadata sidecar, validated `.history` archive, checkpoint ledger, and unreferenced checkpoint blobs. Other ledgers' blobs stay. It continues after individual failures, reporting deleted/skipped-active/failed counts with bounded categories such as `permission_denied` or `not_found`, never raw paths, content, or OS error chains.

Background cleanup uses `sessions.retention_days`; see [Configuration](configuration.md) to set or disable it. It runs before TUI entry on an unjoined thread, may overlap startup, and never blocks readiness or fails startup. It reuses manual primary pruning, then removes expired subagent JSONL and associated artifacts. Fresh sessions, the active primary, and live writers stay; filesystem cleanup is best effort.

### Repair permissions

```sh
magi-code sessions repair-permissions --dry-run
magi-code sessions repair-permissions
```

The command resolves `MC_HOME` first. Default mode prompts on a TTY; `--yes` applies non-interactively and conflicts with `--dry-run`. It repairs only recognized session objects, never recurses or follows links, and fails closed on unknown or unsafe entries. Inspect those manually. Windows permission repair is unsupported.

On Unix, session roots must be non-symlink, owner-private directories (`0700` or stricter). Primary JSONL and metadata must be owner-private regular files (`0600` or stricter) named from validated IDs. Opens use no-follow protection and bind objects to expected paths; unsafe owners, permissions, links, directories, or replacements are rejected rather than followed.

### File checkpoints

`/changes` reads per-session ledgers under `~/.magi-code/checkpoints`. File rewind records sanitized target turns, relative paths, statuses, and counts, without file bytes, diffs, blob hashes, secret-looking paths, or denied paths. See [restore controls and limits](commands-and-interfaces.md#maintain-sessions-and-restore-files).

Conversation rewind writes a new JSONL session containing the prefix before the selected prompt; it never truncates the source. A local diagnostic records the source session and selected prompt for restoring the unsent draft on load. These fields are excluded from provider replay. Earlier checkpoint references are copied to the fork, sharing existing blobs. Session history and its usage records before the target are inherited; no provider request is made. If checkpoint copying or result recording fails, the error identifies the preserved fork; do not assume files were restored. Ordinary retention rules apply to both sessions.

Each ledger is ordered JSONL with serialized durable appends. Blobs synchronize before their records; complete records flush and synchronize before success, including the directory on first creation. A final sync failure after visible bytes reports committed-but-undurable, avoiding blind retries. Readers retain valid records before an incomplete final record and report that tail; malformed committed middle records are corruption. Pruning shares the checkpoint mutation lock and cannot pass an in-progress blob/record publication.

### Local diagnostics and cache

OpenAI Responses keeps bounded local metadata per HTTP attempt: requested model, optional reported `response.model` and `x-request-id`, attempt sequence, and outcome. It is excluded from replay, recent-context text, and cache keys. A normal first-attempt success is silent. Successful retry recovery emits one informational diagnostic, or one warning if any attempt reported a model mismatch; it is also persisted. Failed requests display only the terminal provider error. Reported models may be absent or differ across attempts and are not proof of routing correctness.

Normal runs keep token counting and replay reuse in memory rather than writing diagnostic conversation snapshots under `~/.magi-code/cache`. This is separate from provider-side prompt caching, whose hits remain opportunistic.

Codex and custom-provider catalogs live at `cache/model-catalog/<provider>.json`. They contain sanitized model IDs/display metadata, never API keys, OAuth tokens, bearer headers, account IDs, or raw provider responses.