magi-code 0.77.1

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

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

## Purpose

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.

## Details

### Resume or start fresh

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

Sessions are JSONL files under `~/.magi-code/sessions`. They record 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 full ordered conversation until a valid compaction checkpoint exists. User turns, assistant text, provider response items, tool calls, and results stay distinct. Failed/cancelled partial assistant text remains provider-visible history. History is not silently summarized, recent-sliced, or truncated.

Local-only events (`hook_diagnostic`, `hook_lifecycle`, `context_cache`, `session_title`, and `diagnostic`) are excluded from 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.

### Compact a long session

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

Summary instructions come from bundled `prompts/compact.md` or its user override (`$MC_HOME/prompts/compact.md`). The request includes current structured replay, including historical tool calls/results, but has no tools or tool definitions.

On success, compaction copies the current JSONL byte-for-byte into an immutable `.history/<session-id>/` generation, 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 retain raw audit history but never supply normal replay, listing, or title reads. Repeated compaction rotates each active generation; `/new` instead starts a separate session.

### Enable automatic compaction

Automatic compaction is off when `agent.compaction.auto` is absent or `enabled` is false. To enable it, choose one or both triggers:

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

| Setting | Rule |
| --- | --- |
| `threshold_percent` | `1` to `100`; projected next-request tokens as a percentage of the active model maximum. |
| `threshold_tokens` | 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. With both, the first reached wins: the effective cutoff is `min(ceil(max_tokens * percent / 100), threshold_tokens)`. This differs from the hard usable budget (`max_tokens - reserve_tokens`), but scheduling still requires context budgeting enabled.

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/TTSR recovery, cancelled/failed/partial runs, unsafe tool-progress recovery, `--no-session`, title/vision/tool-internal jobs, and compaction requests. Child compaction affects only that child's file in `sessions/subagents/`.

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

After successful compaction, primary steering takes precedence and is submitted in its existing collapsed order. Otherwise, including every child run, the runtime durably appends and sends `continue` with `origin: "automatic_compaction"`; CLI/TUI show `you [automatic]: continue`. Manual `/compact` does not add this continuation just because auto mode is enabled.

Failure stops continuation. Before checkpoint commit, the prior 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 reported error, then retry the primary input or child task. `/compact` and `/new` are primary-session recovery commands, not child commands.

### Compaction visibility and authority

Mission Control shows one primary transcript card per compaction: progress becomes the sanitized checkpoint summary. Child compaction activity retains the same summary with bounded display/truncation metadata. Classic, plain, and rich CLI output show status only. 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.

Counting is local: `tiktoken-rs` uses embedded `o200k_base`/`cl100k_base` tables selected by model family, without a provider round-trip. 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. It is Unix-only in v1, accepts no arguments or custom destination, never overwrites, and has no import command. It neither changes the active session nor calls 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/unsafe optional descendants are omitted with bounded warnings; missing/unsafe primary data aborts. Session locks remain held through publication.

The archive is unencrypted and contains raw, potentially sensitive session, project, and tool data. Owner-private permissions do not make it safe to share. Mission Control runs export 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 for empty/malformed legacy files. 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 is scheduled before TUI entry on an unjoined thread, may overlap startup, and never blocks readiness or fails startup. It reuses manual primary pruning, then removes old subagent JSONL by mtime and associated artifacts. It also retries old orphan sidecars/history/ledgers and unreferenced blobs. Fresh sessions, the active primary, and live writers stay; filesystem cleanup is best effort.

### Repair legacy 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 legacy objects, never recurses or follows links, and fails closed on unknown/unsafe entries. Inspect unsafe layouts 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. Older sessions without checkpoints still offer conversation rewind. 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 do not read or write diagnostic conversation snapshots under `~/.magi-code/cache`. Token counting and replay reuse stay in memory; old snapshot files are left untouched. 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.