Skip to content

Releases: cortexkit/magic-context

v0.22.0

03 Jun 11:51

Choose a tag to compare

v0.22.0 — 🎊Historian v2🎊, a self-tuning history cache, and node:sqlite

This is the largest release since Magic Context launched. The history engine has been rebuilt from the ground up, the SQLite backend no longer needs a native module, two recall features are now on by default, and the Pi plugin reaches full behavioral parity with OpenCode.

Upgrading an existing session? Sessions compacted by the old historian keep working, but you'll be prompted once to upgrade them to the new format for better fidelity and cache stability. See Upgrading below.

Headline: Historian v2 and a self-tuning history cache > pure magic...

The old design summarized history into a single flat block and ran a separate LLM "compressor" pass to keep it small. That's gone. The new engine is deterministic, cheaper, and far more cache-friendly.

Tiered compartments. Every compartment the historian writes now carries four paraphrase tiers — from a verbose P1 (treated like "the last 12 hours," kept near-verbatim) down to a P4 anchor (just enough to recognize and re-find it). The historian also scores each compartment's importance as a decay rate: how long this needs to stay in high-fidelity memory.

Deterministic decay rendering — no more compressor LLM. Instead of paying a model to re-compress old history, a math function picks the right tier for each compartment on every render, from its age, its importance, and how much history budget you currently have. As a compartment ages or as budget tightens, it gracefully demotes P1 → P2 → P3 → P4, oldest-first. When your model's context window is large, history renders richer; when it's tight, it renders leaner — automatically, with zero LLM cost.

A two-slot history layout that keeps your cache warm. History now renders into two synthetic message slots:

  • A stable baseline holding project docs, your user profile, and the decayed compartment history — treated like a frozen prefix that does not change on routine turns, so its prompt-cache bytes persist.
  • A small volatile delta holding only what's new since the last baseline refresh — new compartments, new memories, and your pinned key files.

The practical effect: on a steady working day, the large stable prefix stays cached until TTL expires or system promopt changes, and only the small delta moves. Fewer surprise cache-misses, much lower cost on long sessions.

Memory edits no longer bust your cache. When the agent (or you) edits, archives, or merges a memory mid-session, that change now surfaces as a compact correction in the volatile delta instead of forcing the entire stable baseline to re-render. The agent sees the corrected state immediately; the expensive prefix stays put until the next natural refresh.

No more native SQLite module

The non-Bun runtimes (Pi on Node, OpenCode Desktop on Electron) used to depend on better-sqlite3 — a native module that needed a per-platform prebuild and, on Desktop, a runtime binary download with an ABI probe. That whole path is gone. Magic Context now uses the built-in node:sqlite on Node and Electron, and bun:sqlite under Bun.

No native module, no prebuild, no download, nothing to go wrong on install. If you ever hit better_sqlite3.node load failures or Electron ABI mismatches, those are eliminated.

Two recall features now on by default

Both were previously opt-in experiments and are now stable and on by default. Each can be turned off independently.

  • Temporal awareness — the agent sees elapsed-time markers (e.g. +2h 15m) between messages and dated compartments, so it understands when things happened. Opt out with temporal_awareness: { enabled: false }.
  • Auto-search hints — each turn, a background ctx_search quietly whispers a compact "vague recall" when something relevant exists in your memories, past conversation, or git history. No full content is injected — just a nudge to look. Opt out with memory: { auto_search: { enabled: false } }.

Experimental config graduated

The experimental.* namespace is retired. Settings moved to stable homes, and doctor migrates your existing config automatically (your opt-ins and opt-outs are preserved):

Old New Default
experimental.temporal_awareness temporal_awareness on
experimental.auto_search memory.auto_search on
experimental.git_commit_indexing memory.git_commit_indexing off
experimental.caveman_text_compression caveman_text_compression off

Collapsible sidebar

The TUI sidebar can now be collapsed (click the header). Collapsed, it keeps the context progress bar plus three compact summary lines — Historian state, Memories, and Status (compartment / queued-op / note counts) — for a glanceable view that takes minimal vertical space.

Pi reaches full parity with OpenCode

The Pi plugin went through an extensive parity sweep and now mirrors OpenCode's behavior across the board: the two-slot history layout, deterministic decay rendering, memory supersede-delta, the upgrade flow, detached (non-blocking) recomp/upgrade, model-fallback chains, and stable message-identity handling. A tracked PARITY.md now documents every intentional difference between the two harnesses so they don't drift.

Performance

  • Transform hot path. A per-pass work-metrics computation was scanning the full assistant-message history on every turn; on large sessions that alone cost ~250ms per pass. It's now lazy and incremental — computed only when the sidebar asks for it. On a large session the post-transform phase dropped from ~240ms to a few milliseconds.
  • Dashboard. Database and filesystem reads moved off the UI thread, the project dropdown is cached for instant History re-entry, and the session list no longer scans the full message table just to show a count. Navigating the dashboard is now snappy even on large databases.
  • Tunable SQLite. New optional sqlite.cache_size_mb and sqlite.mmap_size_mb knobs, plus a periodic PRAGMA optimize.

Dashboard

  • Compartment view upgraded to the v2 model — per-tier (P1P4) inspection, importance, and episode-type badges.
  • New expandable Memory Changes drill-down on dreamer runs — see exactly which memories were written, archived, or merged.
  • Token breakdown corrected to measure the actual injected bytes (Docs and User Profile are now their own categories).

Security and correctness hardening

This release folded in a large multi-round audit sweep across both harnesses and the dashboard. Highlights:

  • Memory config bypass fixed — disabling the memory store no longer leaks memories into the prompt via a fallback path.
  • Local RPC server now requires a per-process bearer token and drops wildcard CORS, so a stray local process can't drive the side-effecting endpoints.
  • Resumed-session project resolution — note nudges and auto-search now resolve the session's project, not the launch directory, so opencode -s from another repo behaves correctly.
  • More than 50 additional bugfixes across the plugin, Pi, and dashboard — migration collision handling, the upgrade flow, key-file selection, dashboard memory editing, and many more.

Upgrade

This release adds database migrations that apply automatically on first start. Your data is migrated in place.

# OpenCode
npx @cortexkit/magic-context@latest doctor

# Pi (requires Pi >= 0.74)
npx @cortexkit/magic-context@latest setup --harness pi

Upgrading old compartments. Sessions that were compacted by the previous historian remain fully usable, but their compartments are in the old flat format. When you open such a session you'll be prompted once to upgrade it — this reprocesses its history with the new historian into the tiered format (it can take a while on large sessions, and runs without blocking your work). You can also trigger it manually:

/ctx-session-upgrade

Upgrading is optional but recommended — un-upgraded sessions render in a degraded single-tier mode.

Dashboard dashboard-v0.5.0

03 Jun 12:07

Choose a tag to compare

Dashboard v0.5.0 — Historian v2 support, faster navigation, richer Dreamer insight

This release brings the dashboard in line with the Historian v2 architecture shipped in plugin v0.22.0, makes navigation noticeably snappier on large databases, and adds new visibility into what the Dreamer actually changed.

Historian v2 support

  • Compartment viewer understands the new tiered model. Compartments now display their importance score and episode types, with an expandable P1–P4 tier view that mirrors the runtime renderer's tier-resolution logic. Legacy v1 compartments are clearly marked.
  • Memory mutation parity. The dashboard mirrors the plugin's memory supersede-delta behavior: editing, archiving, merging, or deleting a memory records the same mutation-log rows and epoch handling as the plugin, so the cache stays consistent across both. Memory content editing now surfaces a friendly conflict message instead of a raw SQLite error when a duplicate exists.
  • Token breakdown corrected for v2. The session token view extracts the actual <session-history> slice that's on the wire instead of over-counting full compartment text, and the retired "Facts" category is gone.

Faster navigation

  • DB and filesystem reads run off the UI thread. All 52 SQLite/FS commands moved to background worker threads, so opening sessions, switching tabs, and loading large projects no longer freeze the window.
  • Instant History re-entry. The project dropdown is cached, and the session list no longer scans the entire message table just to show a per-session count — navigating back into History is immediate.

Richer Dreamer insight

  • Memory Changes drill-down. Each Dreamer run is now expandable to show exactly which memories were written, archived, or merged during that run.
  • Honest token costs. Dreamer and subagent token usage is shown as input: X · output: Y (the meaningful fresh tokens) instead of a cache-inflated total that double-counted re-read context across turns. The full breakdown remains in the row tooltip.
  • Correct project names. The Dreamer panel resolves real project names instead of showing bare git:<hash> identifiers.

Fixes & hardening

  • Project-identity resolution between the dashboard (Rust) and plugin (TypeScript) is now byte-equivalent, including the git-error fallback policy, so projects group consistently across both.
  • Key-files and smart-notes panels resolve symlinked / legacy project paths correctly.
  • Cache Hit Timeline caps to the most-recent N steps (200/400/600 selectable) instead of rendering every step.
  • Several correctness fixes from the full-codebase audit sweep (path normalization, fail-closed identity handling, mutation-log integrity).

Upgrade

The Tauri auto-updater handles this release. Existing installations should pick it up on next launch or via Help → Check for Updates.

v0.21.8

22 May 11:08

Choose a tag to compare

v0.21.8 — See how much work Magic Context is doing for you

What's New

  • Total tokens metric, per session. The TUI sidebar and the dashboard's session Meta tab now show a "Total tokens" number: the cumulative prompt size Magic Context has processed for this session over its lifetime, summed across every turn. It's the simplest way to see how much aggregate context Magic Context has been managing without having to read the live percentage on every turn.

  • Per-historian-run cost visibility in the dashboard. The dashboard Session Viewer has a new Historian tab that lists every historian, compressor, recomp, dreamer, sidekick, and user-memory-review invocation that ran for this session, with the model and token usage for each. No more guessing how much background work the plugin is doing for you — every child-session compaction call is now individually attributable. Dreamer cards in the Dreamer page also surface per-task token totals.

  • TUI sidebar context bar fills the actual sidebar width. Previously the breakdown bar was hard-pinned at 24 characters, leaving empty space on wide sidebars and clipping on narrow ones. The bar now resizes itself proportionally to whatever width the sidebar is rendered at.

What's Fixed

  • Work-metrics on every transform pass, not just execute passes. The new lifetime Total-tokens metric was initially gated on the same internal trigger as the actual work-doing passes — which meant low-pressure sessions sitting below their execute threshold would show 0 forever, even after many turns. The metric is a pure database read and write with no impact on context bytes, so it now updates on every pass and reflects real cumulative work immediately.

Under the hood

The plugin now records every Magic Context child-session invocation (historian, compressor, recomp, dreamer, sidekick, user-memory-review, plus their Pi equivalents) into a new subagent_invocations table in the Magic Context database, along with their token usage and model. This is what powers the new Historian tab and Dreamer cost columns, and is the foundation for upcoming work on per-session cost attribution and benchmarking.

Schema additions (migrations v20 and v21) are strictly additive — no existing data is rewritten, and downgrading to an older Magic Context version simply leaves the new columns/table unread.

Upgrade

npx @cortexkit/magic-context@latest doctor --force

The --force flag clears OpenCode's cached plugin install so v0.21.8 takes effect on next launch.

No config or behavior changes — strictly additive release.

v0.21.7

21 May 17:10

Choose a tag to compare

v0.21.7 — Compressor finally fires on busy sessions, cleaner agent disable, startup release announcements

What's New

  • Startup release announcement. On the first session after upgrading, Magic Context now shows a short "what's new" dialog in the OpenCode TUI, an ignored startup message on Desktop/web, and a Pi notification — so you don't have to dig through release notes to learn what changed. The dialog is one-shot per version and includes a persistent Discord invite footer below the version-specific bullets.

  • Single, unified off-switch for hidden agents. Disabling historian, dreamer, or sidekick is now a single field: disable: true on the agent block in magic-context.jsonc. The legacy dreamer.enabled and sidekick.enabled fields are gone — they were confusing because disable: true and enabled: false would have been duplicate inverse meanings of the same intent, and only one (disable) actually unregistered the OpenCode agent.

    • Manual /ctx-dream still works as long as dreamer.disable is not true. To get the old "scheduled dreaming off, manual dreaming still on" behavior, leave disable unset and set schedule: "".
    • Existing configs auto-migrate. dreamer.enabled: falsedreamer.disable: true (this changes manual /ctx-dream from working to disabled — see migration below). enabled: true is silently stripped because it was already the default. The dashboard Config Editor renders the new field directly; legacy values are cleaned when you save.
    • Running npx @cortexkit/magic-context@latest doctor --force rewrites your config on disk to the new shape with comments preserved.

    This change unblocks issue #50: previously, having a stray enabled: true in your historian block triggered a confusing schema error because historian never accepted that field.

  • TUI execute-threshold display: shorter, cleaner. Percentages over 100 (when using token-based thresholds with large windows) and very long fractional formats now round cleanly (14.099783%14.1%) and the sidebar context bar resizes itself to fit narrower terminal widths instead of wrapping. (Fixes GH #90.)

What's Fixed

  • Compressor no longer underfires on busy sessions. Per GH #91, with low execute_threshold_tokens or low overall context pressure, the compressor could go indefinitely without running even while the compartment block grew far past its budget — because the previous gate suppressed the compressor on the exact cache-busting passes when it was structurally safe to fire. The new design:

    • Adds a database-backed cross-process lease (compartment_state_lease) that serializes compartment-state mutators across OpenCode instances, Pi instances, and /ctx-recomp runs. No more silent overwrites when two harnesses share a project.
    • Snapshots cache-busting signals at the start of each transform pass, so a compressor that finishes mid-pass writes its "history needs refresh" signal to the next pass's set — preventing the previous race where the same-pass drain would consume the compressor's own signal and make the compressed state invisible until some unrelated future refresh.
    • Atomicizes compressor publish — compartment writes, fact writes, depth bumps, and cache invalidation all commit in a single BEGIN IMMEDIATE transaction. Holder identity is verified as the first statement inside the transaction, so a stale lease holder can never overwrite a fresh historian publish.
    • Removes the old suppression gate entirely. The compressor now fires on the same execute/cache-busting passes that historian fires on, and the lease keeps them safely serialized.

    Practical effect: sessions with execute_threshold_tokens=30000 and low usage that previously accumulated 70+ compartments before any compression now get compressed on the very next execute pass, with no manual /ctx-flush needed.

  • Auto-search no longer embeds plugin-internal notification messages. The startup-announcement message, conflict warnings, "preparing augmentation" notifications, and other ignored: true plugin messages were being sent to the embedding provider as if they were real user prompts, wasting embedding throughput and polluting the auto-search budget. The latest-meaningful-user-message detection now uses the canonical helper that filters ignored parts, system reminders, and OMO internal markers — matching how every other part of Magic Context already counted "real" user messages.

  • Migration warnings only fire for meaningful changes. If your magic-context.jsonc had dreamer.enabled: true or sidekick.enabled: true (the no-op alias for the new default disable: false), the unified-disable migration in v0.21.7 initially showed a "config warning" suggesting you had something to fix. That warning is now silent for enabled: true (nothing semantically changes — the key is just obsolete) and only fires for enabled: false, which is the case where the migration triggers a real behavior change.

  • Pi parity hardening. Drain-signal correctness, historian parity mirror, and runner/entry anchors received targeted fixes from the 2026-05-20 Pi audit pass, closing the last batch of pre-release Pi-specific findings.

Upgrade

npx @cortexkit/magic-context@latest doctor --force

The --force flag clears OpenCode's cached plugin install so v0.21.7 takes effect on next launch.

Heads up for users with dreamer.enabled: false

The auto-migration rewrites dreamer.enabled: false to dreamer.disable: true, which also disables manual /ctx-dream (the old enabled: false only stopped scheduled dreaming). If you want scheduling off but manual dreaming on, edit magic-context.jsonc after running doctor:

"dreamer": {
  // remove "disable": true
  "schedule": ""    // empty schedule = no scheduled runs, manual /ctx-dream still works
}

This is the only behavior-changing migration in v0.21.7.

v0.21.6

20 May 15:19

Choose a tag to compare

v0.21.6 — Hidden subagent isolation, TUI threshold visibility, doctor report size cap

What's New

  • TUI sidebar and /ctx-status header now show the execute threshold alongside the percentage. The header changes from 47.5% · 475K / 1.0M to a left/right layout: 47.5% / 65% on the left (current usage vs the execute threshold that triggers compaction), 475K / 1.0M on the right (absolute tokens vs the model's context window). Resolved per-model, so users with execute_threshold_percentage or execute_threshold_tokens overrides see the actual value applied to their session.

What's Fixed

  • Historian, dreamer, and sidekick can no longer spawn subagents or run unsafe tools. Each hidden agent now ships with a permission ruleset that denies everything by default and explicitly allows only the tools that agent actually needs:

    • Historian / compressor: read, aft_outline, aft_zoom (state-file offload + lightweight symbol navigation for accurate summaries)
    • Dreamer: read, grep, glob, bash, aft_outline, aft_zoom, ctx_memory, ctx_search, ctx_note (memory CRUD + verification against project source + smart-note evaluation via gh / git / curl). task, edit, write, webfetch, websearch stay denied.
    • Sidekick: ctx_search, ctx_memory, aft_outline, aft_zoom (memory retrieval + symbol-scoped structural context for /ctx-aug)

    Previously these agents inherited the full primary-agent tool surface and historian was occasionally observed dispatching task(subagent_type=explore) for repo-wide fanout, which contradicts its job of summarizing the input it was given. Allow-lists were derived from auditing real tool usage in the local OpenCode DB across hundreds of past historian and dreamer child sessions.

  • doctor --issue reports now respect GitHub's 64KB body limit. When the rendered report exceeds the budget, the main log section is truncated from the top (oldest lines dropped) with a visible [truncated for GitHub 64KB limit — older log lines dropped] marker. A new "Recent errors (last 20, sanitized)" section is always included before the main log so error context survives even when the bulk log gets clipped.

Upgrade

npx @cortexkit/magic-context@latest doctor --force

If OpenCode still loads a cached older plugin after upgrading the CLI, the --force flag clears the cached install so the new version takes effect on next launch.

v0.21.5

20 May 05:45

Choose a tag to compare

What's New

Pi background compaction stops busting cache mid-tool-loop

Pi's historian used to apply the visible-message trim (sessionManager.appendCompaction()) immediately after publishing new compartments. That changed Pi's branch view mid-tool-loop, which meant the very next request to the model sent a different message shape than the one we were trying to cache. Background work was paying the cache cost every time it produced a result.

Pi now stages the marker in a durable queue and applies it on the next materialization pass — the same point where pending tool drops materialize — so a single execute pass covers both changes. Cache survives across background compaction work.

Equivalent to the OpenCode deferred-marker design that shipped in v0.19. Behavior visible to users: noticeably better cache hit rates on long Pi sessions with frequent autonomous tool runs.

What's Fixed

Pi parity with OpenCode

Several invariants OpenCode had but Pi was missing:

  • Pi historian trigger evaluation now uses live session config. Pi was deriving the trigger budget at startup and ignoring execute_threshold_tokens, commit_cluster_trigger, auto_drop_tool_age, protected_tags, clear_reasoning_age, and drop_tool_structure when deciding whether to fire historian. OpenCode threads all these from the live model. Pi now does the same — same inputs, same decisions.

  • Pi historian trigger evaluation now uses the fast tag query. OpenCode switched to getActiveTagsBySession in v0.17 (avoids a full-session tag scan on every pass). Pi was still on the slow path. Pi now uses the same fast path.

  • Pi sticky reminders, auto-search hints, and note nudges survive when extensions wrap messages. When a competing Pi extension clones or re-wraps message objects (e.g. condensed-milk-pi), our reference-based ID lookup could miss those messages and fall through to writing synthetic IDs that don't replay correctly. Added a fingerprint fallback (responseId + timestamp + role + first text hash) so cloned wrappers still resolve to real entry IDs. On strict failure we now replay existing anchors only, never write new ones with synthetic IDs. Direct fix for #81.

  • Pi historian/compressor publish callbacks no longer affect cleared sessions. If you switched sessions while a Pi historian or compressor run was in flight, the publish callback could write deferred refresh signals against the just-cleared session and leak state. Active-session registry now scopes the callbacks; cleared sessions ignore late publication signals.

  • Pi subagent runner respects abort signals before spawning. Aborting a historian/dreamer/sidekick run between request and spawn used to spawn the child process anyway. Now exits cleanly with the abort error.

  • Pi shutdown timers no longer hold the event loop. Shutdown drain timers were keeping the process alive briefly after Pi exited. Now properly unref'd.

  • Pi historian eligibility check cleans up its raw-message provider on every path. Provider was leaking when maybeFireHistorian exited without firing.

Storage atomicity

Four database paths could leave inconsistent state if a SQLite operation failed mid-sequence:

  • Compartment recomp promotion now clears stale memory block IDs. After full recomp, the cached memory block IDs in session_meta were stale until the next memory write — they could reference compartments that no longer existed.
  • deleteTagsByMessageId is now transactional. Tag deletion did two separate DELETEs (composite tool tags + plain tags) without wrapping. A failure between the two left orphan rows.
  • Orphan key-file cleanup is now transactional. Same pattern: two DELETEs without atomicity.
  • Migration race detector now actually validates. The "is this migration version already applied by a sibling process" check had a vestigial return true and skipped its SELECT entirely on the slow path, so concurrent OpenCode/Pi startups could race even though the code claimed to be protected.

Transform replay

  • Errored-tool truncation and processed-image stripping now replay on every pass. Both mutations only ran during cache-busting passes — defer passes saw the un-truncated content. Wire bytes diverged between bust and defer, costing cache. Now both replay on every pass.
  • stripSystemInjectedMessages no longer touches user-role messages. Aggressive cleanup could neutralize user-role placeholders, collapsing user turn boundaries.

Config security

  • {env:VAR} substitutions are now JSON-escaped. A user setting MAGIC_CONTEXT_FOO="bar\"; \"injected_key\": \"injected_value could break out of the JSON string boundary and inject arbitrary config keys. Now properly escaped.
  • Project-level configs no longer expand {env:...} or {file:...}. Only user-level configs do. Previously, a malicious .opencode/magic-context.jsonc checked into a repo could exfiltrate env vars or file contents into config warnings sent over the wire.
  • JSONC comments are stripped before variable substitution. A // {env:SECRET} comment used to expand the env var into the comment text, then the parser stripped the comment — but the substitution warning still surfaced the secret.

ctx_note scope

  • dismiss and update are now scoped to the caller's session and project. Previously they took only a note ID, so an agent in session A could dismiss notes belonging to session B. Now both actions require the caller's project identity to match the note's, and session notes additionally require session ID to match.

Compartment trigger observability

Three skip paths in the historian trigger used to return shouldFire=false with no log line, making it impossible to diagnose why historian wasn't firing at high pressure. All three now log:

  1. Historian already in progress — shows current usage so you can see the trigger was suppressed by an in-flight run rather than by the trigger evaluation itself.
  2. No new raw history past last compartment — dumps nextStartOrdinal, lastCompartmentEnd, rawMessageCount, and protectedTailStart so the missing condition is visible.
  3. Below proactive floor — shows the actual floor for the active session's execute threshold.

Pure observability change. No behavior difference.

Upgrade

npx @cortexkit/magic-context@latest doctor --force

Dashboard dashboard-v0.4.8

20 May 16:43

Choose a tag to compare

Dashboard v0.4.8 — Memories project picker fix

What's Fixed

  • Memories tab project picker showed raw git:<hash> / dir:<hash> identifiers instead of project names. A regression from the v0.4.7 Memories filter fix: when the plugin started writing resolved project identities into memory rows, the dashboard's project picker still tried to resolve those identities as filesystem paths. With no path match, the OpenCode/Pi project lookup was skipped and the dropdown rendered the bare identifier.

    Fixed by normalizing each memory's project value to its identity (handling both already-resolved identifiers and legacy raw paths), then matching against the full enumerated project list from OpenCode/Pi by identity. Picker now shows real project names like "magic-context" or "AFT".

Upgrade

The Tauri auto-updater handles this release. Existing installations should pick it up on next launch or via Help → Check for Updates.

Dashboard dashboard-v0.4.7

20 May 15:31

Choose a tag to compare

Dashboard v0.4.7 — Memories tab project filter fix

What's Fixed

  • Memories tab returned zero results when filtering by project (#87). The frontend sends the resolved project identity (e.g. git:<commit-hash>) as the filter value, but the backend was querying memories WHERE project_path = ? against raw filesystem paths stored on each memory row. The two never matched, so filtering any project showed no memories even when memories existed for that project.

    Fixed by resolving the incoming identity to all stored paths that belong to it (a single git: identity can cover multiple worktrees and clones writing into the same shared memory pool) and querying with an IN (...) clause across the full set. Identical to the path History already used, so both tabs now agree on what "this project" means.

Upgrade

The Tauri auto-updater handles this release. Existing installations should pick it up on next launch or via Help → Check for Updates.

v0.21.4

19 May 15:44

Choose a tag to compare

What's New

Compaction markers are now always on — no longer behind a config flag. They've been default-true since v0.9.0 and there's no scenario where disabling them helps; the knob just let users silently degrade themselves on long sessions. Doctor will quietly remove any stale compaction_markers setting from your config.

What's Fixed

Stuck "compacting history" notification loop

Fixes #85. The ⏳ Context at 95% — Magic Context is compacting history before continuing notification could fire on every turn even though real context usage was tiny (3.7% in the reporter's case).

Root cause: an earlier transient overflow error armed an internal "recovery needed" flag, and the only paths that cleared the flag required a successful historian publication. When historian had nothing eligible to compact — short session, mostly ignored notifications, etc. — it bailed silently before publish, leaving the flag armed. The next turn synthetically bumped pressure back to 95%, fired the notification, ran historian, bailed silently again. Forever.

The runner now disarms recovery when it correctly determines there's nothing to compact (no eligible raw history, or all eligible messages filtered as noise). Diagnostics also surface two previously-silent failure paths (existing-validation, chunk-coverage) so future variants of this bug show up in doctor --issue instead of looking like a clean session.

TUI sidebar

  • Sidebar breakdown no longer disappears on first user prompt. Reopening a project session showed the full context breakdown, then the whole drilldown vanished the moment you sent your first message — until the assistant's first response arrived. Caused by the sticky-cache misclassifying the "user just typed, model hasn't responded" window as a real session reset. The cache now sticks unless compartments and memories also dropped to zero.

  • Conversation row always shows in the legend. When the calibrator rounded Conversation tokens down to zero (heavy tool-call sessions), the entire Conversation row vanished from the legend, leaving the breakdown looking truncated. The row is now always rendered, even at 0%.

  • Breakdown bar respects 0-token segments. A 0-token segment used to consume 1 character of bar width, making the bar non-proportional. Zero-token segments now get zero width; the bar matches real token distribution.

  • Cleaner header line. Dropped the redundant "Context" label and "tokens" suffix from the line above the breakdown bar. Now reads 34.3% · 343K / 1.0M right-aligned.

Key file pinning

  • Prose docs and project-meta files no longer get pinned. README.md, CONTRIBUTING.md, CHANGELOG, LICENSE, lockfiles, and *.md/.mdx/.rst/.txt files were leaking into the key-file candidate pool. Heavily read, but not useful as repeated-reference orientation context — they crowded out real source. Filtered both at candidate collection AND in the LLM prompt; existing pinned doc rows will be replaced on the next Dreamer key-files pass.

Auto-search

  • All XML/HTML markup stripped before embedding. Auto-search previously enumerated specific tags to strip (<instruction>, <ctx-search-hint>, <sidekick-augmentation>, temporal HTML comments, plugin markers). Anything outside that allowlist — pasted code with <Component>, arbitrary custom tags, future plugin markers — reached the embedding endpoint as part of the query. Now strips all HTML comments and all XML/HTML tags generically. System-reminder content is still dropped entirely; text between other paired tags is preserved (e.g. pasted <thing>useful content</thing> keeps "useful content" in the embedding).

Diagnostics report

  • doctor --issue no longer redacts non-secret config fields. Bug reports were showing entries like "pin_key_files": "<REDACTED:pin_key_files>" because the secret-detector substring-matched on key, token, auth, etc. — flagging benign config names like pin_key_files, token_budget, nudge_interval_tokens, injection_budget_tokens as secrets. The detector now requires the field name to actually be a credential (api_key, access_token, client_secret, etc.) rather than just contain a secret-shaped word, while still redacting all real credentials.

Smart notes

  • Tightened guidance to prevent session-context misuse. Smart notes (ctx_note with surface_condition) are evaluated by the dreamer in a separate background process, with read-only access to external signals — GitHub state via gh CLI, web pages, files on disk, git history. The dreamer cannot see your active conversation, cannot detect when the user says something, and has no session memory. Agents were writing smart notes with conditions like "When the user mentions X" or "When we revisit this code path" — unevaluatable. The tool description, parameter description, and dreamer's evaluation prompt now make this boundary explicit with both ✓ GOOD and ✗ BAD examples, and the dreamer now omits unevaluatable conditions from its results rather than marking them met=false, letting the archive-stale task retire them eventually.

Upgrade

npx @cortexkit/magic-context@latest doctor --force

v0.21.2

19 May 10:16

Choose a tag to compare

v0.21.2 — Pi extension compatibility and high-pressure safety

A short patch release fixing real cache-stability and Pi subagent issues found in production over the past week.

What's improved

Pi: extensions adding custom messages no longer break compartment boundaries

Pi extensions that emit customType messages — Magic Context's own /ctx-status output, plus several common Pi extensions like anthropic-auth, pi-http-dump-src, and condensed-milk-pi — add real entries to agent.state.messages that are stored as custom_message (rather than message) branch entries. Our previous walk through getBranch() assumed those two counts were always equal, so any custom messages mixed in shifted every subsequent index by one. Compartment boundary lookups stopped matching, <session-history> injection fell into degraded mode, the visible tail couldn't be trimmed, and context kept growing until the 95% emergency.

The mapping is now resolved by AgentMessage reference identity instead of by array position, so custom messages from any extension can sit anywhere in state.messages without affecting boundary resolution. Resolves the symptom reported in issue #81 and fixes a smaller off-by-one drift around agent_end that we observed in our own sessions.

Pi: subagent spawn works in npm-only installs

PiSubagentRunner was spawning the pi binary from PATH for historian, dreamer, and sidekick child processes. In environments without a globally installed Pi binary (npm-only installs, CI, sandboxed setups) that silently failed, leaving subagent features unusable. The runner now resolves @earendil-works/pi-coding-agent from node_modules and falls back to PATH only when resolution fails, then invokes Pi directly under Node — no Bun dependency.

OpenCode: no infinite loop at high context pressure

At ≥95% pressure during historian work, the "Magic Context is compacting history" notification was being emitted on every transform pass. Each notification persists as a new user message; OpenCode's assistant runLoop break condition compares the latest user and assistant message IDs, so a stream of new user messages kept the loop iterating. Sessions that hit very high pressure could spin through hundreds of identical requests before recovering. The notification now fires at most once per historian run.

OpenCode: bounded session message fetches

Several internal paths (historian, compressor, dreamer, sidekick, key-files, conflict-warning) were calling OpenCode's session.messages endpoint without an explicit limit, which the underlying API treats as "load the entire session into memory." All nine callsites now request at most the latest 50 messages — enough for what they actually need. Reported by an external audit.

Upgrade

This release does not add any database migrations.

# OpenCode
npx @cortexkit/magic-context@latest doctor --force

# Pi (requires Pi >= 0.74)
npx @cortexkit/magic-context@latest setup --harness pi