Releases: cortexkit/magic-context
v0.16.3
Critical Electron compatibility fix
OpenCode 1.14.x stable shipped on Electron 41 (NODE_MODULE_VERSION 145), which rejects the better-sqlite3 Node ABI 137 prebuild that ships with Magic Context. Without this fix, Magic Context disables itself on OpenCode Desktop entirely. If you're on Desktop and saw the plugin silently stop working, this release fixes it.
This release also moves the unified CLI fully onto npx, drops a 1.5s-per-transform HTTP round trip on large sessions, and tightens a few install-flow rough edges.
Upgrade
npx @cortexkit/magic-context@latest doctor --force--force clears OpenCode's cached plugin install so it picks up the new bundle on the next launch. Dashboard users should also run this to refresh the cached plugin used by the Magic Context tray.
What's Fixed
-
Electron Desktop:
better-sqlite3ABI mismatch resolved. Magic Context now detects Electron at plugin init, fetches a matching ABI 145 prebuild from the officialWiseLibs/better-sqlite3GitHub release on first run, and caches it under~/.cache/cortexkit/native-bindings/. Subsequent restarts use the cache. The bundlednode_modules/.../better_sqlite3.nodeis never modified — Pi (Node) and OpenCode TUI (Bun) keep using the binary they need. Implementation usesbetter-sqlite3's documentednativeBindingconstructor option, norequire.cacheornode_modulesmanipulation. Verified live on OpenCode 1.14.37 / Electron 41.2.1 with both fresh-download and warm-cache paths. -
Transform latency on large sessions cut by ~1.5s per pass. Magic Context's transform was calling
client.session.get(...)on every pass to resolve the session's project directory — an HTTP round trip through OpenCode's local API that took 1.5s+ for long sessions under Electron. Sincesession.directoryis set at session create time and never changes, the result is now cached in-process for the session's lifetime; subsequent transforms use a sub-microsecond Map lookup. Most visible on Desktop with sessions in the tens of thousands of tagged messages.
What's Changed
-
CLI invocation:
npx-only. The unified CLI now consistently recommendsnpx @cortexkit/magic-context@latest <command>everywhere — install scripts, README,CONFIGURATION.md, doctor self-help text, plugin warnings, TUI sidebar, dashboard, and the bug-report template. Two recurring issues drove this:bunx --bunfroze undercurl | bashbecause Bun's TTY handling doesn't deliver keypress events through a fresh/dev/tty, so the historian-model picker hung on first install.- The plugin auto-update checker was running
bun installeven though OpenCode itself uses npm to manage plugins, generating a parallelbun.lockthat drifted from OpenCode'spackage-lock.json. The checker now runsnpm install --no-audit --no-fund --no-progressand cleans both modern and legacypackage-lock.jsonshapes.
Bun is still fully supported as a runtime —
bunxworks fine, the docs just don't actively recommend it anymore. Node 20.12+ is required (Clack prompts depend onnode:util.styleText).
Notes
- No config changes required; existing
magic-context.jsoncfiles continue to work. - No data-migration changes; the SQLite schema is unchanged.
- The first plugin load on Electron Desktop will spend ~1-2 seconds downloading the matching
better_sqlite3.node(~950 KB) from GitHub. Subsequent launches are instant — they use the cached binary.
v0.16.2
System prompt control + cross-host dreamer fixes
This release adds per-agent control over Magic Context's system-prompt injection, fixes a long-standing bug where the dreamer queue could leak across projects, and stops historian/dreamer/sidekick subagent prompts from rendering as huge visible messages in the TUI.
What's New
-
Per-agent opt-out for system-prompt injection (#53, #42). New top-level
system_prompt_injectionconfig lets you exclude specific agents from receiving the## Magic Contextguidance block.skip_signaturesis just a list of substrings — if any one of them appears anywhere in an agent's system prompt, that agent is opted out for that turn.Two ways to use it:
"system_prompt_injection": { "enabled": true, // set to false to disable injection globally "skip_signatures": [ // Option 1 — match a unique phrase that's already in the agent's prompt // (e.g. opt out the Council orchestrator from omo-slim): "You are the Council agent — a multi-LLM", // Option 2 — drop a marker into your own custom agent's prompt and // match it here. The exact marker text is up to you; this is just // an example convention: "<!-- magic-context: skip -->" ] }
This is useful when you've denied tools for a specific agent (so the LLM isn't told to use tools it can't access) or when you want a clean prompt surface for orchestrators like
council. Empty signature strings are filtered out defensively so a misconfiguration can't silently disable injection globally.
What's Fixed
-
Magic Context guidance no longer injected into OpenCode's internal small-model agents (#52). The
title,summary, andcompactionagents have a fixed single-shot job, no tools, and don't benefit from any of the magic-context block — they were just paying the token cost. Detection is signature-based on each agent's distinctive prompt opener, and the system-prompt hash is no longer updated for these calls so they don't trigger spurious cache busts on subsequent main-agent turns. -
Subagent prompts no longer render as 90k-character visible user messages in TUI (#50 part 2). Historian, dreamer, sidekick, compressor, and user-memory-review all build large internal prompts containing existing-state XML, raw transcripts, and instructions. These were being sent as ordinary text parts and showing up as massive unreadable user messages in OpenCode's subagent pane. The text now uses OpenCode's
synthetic: trueflag so the LLM still receives the full prompt body but the TUI skips rendering — same mechanism OpenCode uses internally for plan-mode prompts and auto-compaction summaries. -
Dreamer no longer runs scheduled cycles for projects you never opened. The shared
dream_queuetable is process-global (OpenCode and Pi both write to it), but each running host only knows about its own registered project's filesystem path and harness-specific runner. Without a project filter, a Pi process running for project A would dequeue queue entries for unrelated projects B, C, D... and try to dream them with Pi's runner — failing every cycle withposix_spawn 'pi': ENOENTbecause the spawn cwd fell back to the literalgit:<sha>identity string. Both ends are now project-scoped:processDreamQueueandcheckScheduleAndEnqueueaccept the calling host's project identity and only operate on entries that belong to it./ctx-dream(manual) is also project-scoped. If you previously saw consistently failed dream runs in the dashboard for projects you never opened in that harness, this is the fix. -
doctorno longer destroys tuple-form plugin entries on save. OpenCode allows plugin entries in two forms: a bare string"@pkg/name"or a tuple["@pkg/name", { ...options }]for plugin-specific config. The unified-CLI'sdoctor-opencode.tswas filteringconfig.pluginto strings only before writing back, silently dropping the tuple options every time it saved the config;setup-opencode.tswas throwing TypeError on tuple entries entirely. Both now use the sharedmatchesPluginEntryhelper from the OpenCode adapter so tuples preserve their options end-to-end. -
Regressions in unified-CLI ports of earlier fixes, all caught when comparing the new
packages/cli/paths against the corresponding plugin-side helpers:- The Windows cache path fix from v0.15.1 (
%LOCALAPPDATA%-vs-~/.cache) was reintroduced in the unified CLI'spaths.ts. Restored here sodoctor --forceagain clears the correct OpenCode plugin cache on Windows. - The dev-path plugin entry detection from v0.16.1 was reintroduced in
doctor-opencode.ts's inline matcher and missed baremagic-contextpaths after the repo rename. Bothdoctorandsetupnow use the shared adapter matcher and leave dev-path entries (file://, absolute, relative) alone end-to-end.
- The Windows cache path fix from v0.15.1 (
-
doctor-pi.tsconflict check no longer hardcodes a "no conflicts detected" pass. The check was unconditionally emitting a green pass with no detection logic. It now actually scans the Piextensionsarray for duplicate magic-context entries and dev-path-plus-npm-entry mismatches, the same shape OpenCode's check has always had. -
GitHub release job now blocks on npm publish success.
release.yml'sgithub-releasejob depended only on the test gates, so a transient npm-publish failure could leave a published GitHub release page with no corresponding npm packages. Nowneeds:includes all three publish jobs (publish-npm,publish-npm-pi,publish-npm-cli) so the release page only goes live after npm has accepted the upload. -
Dashboard release script no longer wipes the entire
gh-pagesbranch on every release. The deploy-updater step hadforce_orphan: true+keep_files: false+publish_dir: .plus aninclude_filesinput that doesn't exist onpeaceiris/actions-gh-pages@v4and was silently ignored. Every dashboard release was force-pushing the whole repo as a single orphan commit. Replaced with a staging directory +keep_files: trueso onlylatest.jsonupdates incrementally. Also replaced the hardcoded 30-secondsleepwith a 20×15s retry loop that fails fast on missing artifacts.
Upgrade
bunx --bun @cortexkit/magic-context@latest doctor --forceForce is recommended once after upgrading from 0.16.1 because the previous release pinned cache state into your OpenCode plugin cache that this release supersedes. Without --force, OpenCode may keep loading the cached 0.16.1 plugin even after npm updates.
v0.16.1
Unified CLI: one command for both harnesses
The setup and doctor commands have been consolidated into a single @cortexkit/magic-context package. Instead of running per-plugin binaries, you now use one CLI that auto-detects which harnesses you have installed (OpenCode, Pi, or both) and dispatches to the right pipeline.
# Auto-detects installed harnesses
bunx --bun @cortexkit/magic-context@latest setup
# Or target a specific harness
bunx --bun @cortexkit/magic-context@latest doctor --harness opencode
bunx --bun @cortexkit/magic-context@latest doctor --harness piThe plugin packages (@cortexkit/opencode-magic-context, @cortexkit/pi-magic-context) are now runtime-only — they no longer ship CLI binaries. About 7,100 lines of duplicated CLI logic across the two plugins were collapsed into a shared adapter pattern.
What's New
-
@cortexkit/magic-context— new unified CLI package withsetup,doctor, anddoctor migratecommands. Auto-detects installed harnesses; pass--harness opencodeor--harness pito target a specific one. The piped install scripts (install.sh,install.ps1) and the in-app conflict warnings now point at this single CLI. -
Doctor checks aligned across both harnesses. OpenCode doctor gained the checks Pi already had: CLI version vs npm latest,
magic-context.jsoncJSONC parse + schema-load validation, shared SQLite DB existence +PRAGMA integrity_check+ per-table row counts. Pi doctor gained the historian-debug-dumps inspection. Both now report aPASS X / WARN Y / FAIL Zsummary line so results scan at a glance. -
Discord — Magic Context now has a Discord server. Drop in for help, feature discussion, or release coordination.
What's Fixed
-
Local dev-path plugin entries are no longer overwritten by
doctor. Previously, an entry like/Users/.../opencode-magic-context/packages/pluginin your OpenCode config would be silently replaced with@cortexkit/opencode-magic-context@latest, swapping the developer's local plugin instance for the published version. Doctor and setup now recognize dev-path entries (file://, absolute paths, relative paths) and leave them alone — even under--force. Affected entries are logged asPlugin registered (dev path: ...)so it's clear they were detected. -
comment-jsonrestored as a plugin runtime dependency. The CLI restructure inadvertently droppedcomment-jsonfrom the OpenCode and Pi plugin packages, even though the TUI config helper, auto-update checker, and Pi config loader still import it at runtime. Local builds masked the regression because workspacenode_modulesstill resolved it; CI and fresh installs hitCannot find module 'comment-json'at typecheck and load. Restored on both plugin packages with version pinned to^4.2.5across the workspace. -
better-sqlite3properly externalized from the CLI bundle so the unified CLI works under Node without trying to bundle a native module. Declared as a runtime dependency on the CLI package and marked external in the build. -
Docker E2E images updated for the unified CLI so the test pipeline exercises the same code path users run. Both Dockerfiles now COPY the CLI dist, install it with build tools available, and symlink the binary into
/usr/local/bin/magic-context.
Upgrade
bunx --bun @cortexkit/magic-context@latest doctor --forceThis installs the new unified CLI and runs doctor against your installed harnesses. The runtime plugin entries in your opencode.json[c] (@cortexkit/opencode-magic-context) and Pi settings (@cortexkit/pi-magic-context) are unchanged — those are the runtime plugin packages, separate from the CLI.
If you previously had bunx --bun @cortexkit/opencode-magic-context@latest setup or magic-context-pi setup aliased anywhere, switch to:
bunx --bun @cortexkit/magic-context@latest setupFull Changelog: v0.16.0...v0.16.1
v0.16.0
Cross-harness Magic Context — Pi support is here
This release introduces support for the Pi coding agent as a second harness. The same SQLite database, project memories, embeddings, dreamer state, and key-file pins are now shared across OpenCode and Pi — write a memory in OpenCode, retrieve it in Pi (and vice versa), all from the same ~/.local/share/cortexkit/magic-context/context.db.
Per-session state (tags, compartments, facts, notes) stays correctly attributed to its originating harness via a new harness column.
Pi support is published as beta. Core flows (tagging, historian, memories, dreamer,
/ctx-aug) are validated end-to-end on both interactivepisessions andpi --print --mode jsonsubagents. Please report issues — every Pi-side rough edge is fixable.
What's New
-
@cortexkit/pi-magic-contextPi extension (beta) — install withpi install npm:@cortexkit/pi-magic-contextor via the setup wizard. Requires Pi>= 0.71.0. Ships with the same five/ctx-*slash commands as the OpenCode plugin (/ctx-status,/ctx-flush,/ctx-recomp,/ctx-dream,/ctx-aug) and the same agent-facing tool surface (ctx_search,ctx_memory,ctx_note). -
Shared cross-harness SQLite database at
~/.local/share/cortexkit/magic-context/context.db. The plugin database moved out of OpenCode's per-plugin storage path so both harnesses can pool memories, embeddings, dreamer runs, and key-file pins by project identity. On first launch after upgrading, the OpenCode plugin auto-copies its existing database (and WAL/SHM sidecars + embedding model cache) to the new path; the legacy location is left untouched as a backup. -
Runtime-detected SQLite backend so the same plugin code runs under Bun (
bun:sqlite) and Node (better-sqlite3). This unblocks the Pi extension (Pi runs on Node) without forking the storage layer or losing the OpenCode/Bun code path. -
Cross-harness scope discipline — memories, embeddings, and dreamer state are scoped by
project_path(resolved git root) so both harnesses see the same project knowledge. Tags, compartments, session facts, and notes are scoped by(harness, session_id)so per-session state stays correctly attributed. -
Dashboard now treats harness as a first-class dimension — sessions, cache events, and per-session stats are keyed by
(harness, session_id). Pi sessions show alongside OpenCode sessions with harness badges and filter chips; the Memories page picks up Pi-originated writes automatically.
What's Fixed
-
Tuple-form plugin entries no longer trigger false conflict warnings (#49). The conflict detector previously assumed every
pluginarray entry was a string and silently failed on tuple form like["@pkg/name", { ...options }]. It now extracts the package name from tuple entries before matching. -
TUI presence detection no longer goes stale (#50). The internal
tuiConnectedflag was set once and never reset, so server-side notifications kept routing through the TUI even after the user closed it. Replaced with a recent-drain timestamp check, plus a fallback so failedshowToastcalls now flow through to the ignored-message path instead of being swallowed. -
/ctx-dreamno longer gets stuck after a crashed dream worker. Manual/ctx-dreaminvocations now force-clear stalestarted_atrows from the dream queue once the lease TTL has passed, so explicit user requests can always proceed. -
Plugin database path uses session directory, not launch directory. Project identity now resolves from the actual session directory (via the session's stored
directoryfield) instead of the plugin's startupcwd. This fixes a class of bugs where launchingopencodefrom outside the project root attached memories/dreamer state to the wrong project.
Upgrade
bunx --bun @cortexkit/magic-context@latest doctor --forceAfter upgrading, your existing OpenCode database is automatically copied to the new shared ~/.local/share/cortexkit/magic-context/ path on first plugin load. The old path is left in place as a backup.
To install the Pi extension:
bunx --bun @cortexkit/magic-context@latest setup --harness piFull Changelog: v0.15.7...v0.16.0
Dashboard dashboard-v0.4.1
Hotfix: auto-update endpoint repaired
The dashboard-v0.4.0 build shipped with a stale auto-updater endpoint pointing at the old repository's GitHub Pages URL (cortexkit.github.io/opencode-magic-context/...). After the repo was renamed to cortexkit/magic-context, GitHub stopped serving anything at the old URL — every dashboard install was silently polling a 404 on every startup, leaving v0.4.0 frozen with no auto-update path.
This release fixes the endpoint to the live URL (cortexkit.github.io/magic-context/...). Once you're on dashboard-v0.4.1, future updates land automatically as usual.
v0.3.4andv0.4.0users need a one-time manual download. The dead URL is baked into those binaries; nothing the server can do reaches them. Downloadv0.4.1from this release page, then auto-update will work for all subsequent versions.
What was actually in v0.4.0 (still ships in v0.4.1)
dashboard-v0.4.0 was deleted before promotion, so this release also delivers everything that was in v0.4.0:
-
Cross-harness Pi support — Pi sessions, cache events, and per-session stats now show alongside OpenCode in every dashboard view, keyed by
(harness, session_id). Harness badges and filter chips throughout. The Memories page picks up Pi-originated writes automatically (memories are project-scoped and shared across both harnesses). -
Cache page polish — toolbar layout fixed, cache-row titles ellipsize properly when long, per-session cache stats correctly resolve to the originating harness.
-
Sessions / Config / Memories cleanup — nine reported polish items: layout corrections, missing harness columns wired through the backend, project-picker filter for memories, and a handful of UI bugs across the cache, sessions, config editor, and memory browser views.
Upgrade
Download from this release page and replace your existing app — the auto-updater can't carry you over from a binary with the dead endpoint.
After v0.4.1 is installed, future dashboard releases auto-update normally.
Full Changelog: dashboard-v0.3.2...dashboard-v0.4.1
v0.15.7
What's Fixed
-
Tagger no longer cascades into repeated cache busts when its internal counter drifts behind the tags table's actual max tag number. Previously, once divergence occurred (from earlier outer-transaction rollback, multi-process race, or non-monotonic counter upsert), every transform pass would propose an already-claimed tag number, hit a UNIQUE collision, abort tagging, and skip the persisted-drop / reasoning-clear / caveman-compression replay — resurrecting tens of thousands of stripped tokens and forcing a full provider-cache miss on every affected turn. The tagger now reads the live DB max on every allocation and walks past collisions automatically, so a brand-new pass on a divergent session self-heals in milliseconds without any user intervention.
-
Counter upsert is now monotonic. Concurrent writers (multiple OpenCode instances, or sessions in different processes) can no longer move a session's counter backward, so a stale low writer cannot undo state from a higher writer that already advanced past it.
-
Existing divergent sessions heal automatically on first startup after upgrading. A one-shot migration brings every session whose
MAX(tag_number) > counterback into sync. Cheap, idempotent, and runs once — fresh DBs and already-healthy sessions are unaffected. -
One tagging failure no longer rolls back the whole transform pass. Per-call atomicity is preserved through SAVEPOINTs while the outer wrapper is removed, so a single isolated collision can no longer leave the pass with empty tag targets and skipped drop/reasoning replay.
Upgrade
bunx --bun @cortexkit/opencode-magic-context@latest doctor --forceAfter upgrading to v0.15.7, divergent sessions self-heal on next plugin load. If you were seeing repeated cache busts after long idle gaps or multi-process activity on the same project, this release closes that path.
Full Changelog: v0.15.6...v0.15.7
v0.15.6
What's Fixed
- Note reminders re-surface after work boundaries when the agent's prior
ctx_note(read)result has dropped out of context (was reduced, aged out, or compartmentalized). Previously, once an agent read its notes, future reminders were suppressed until note content changed — even if the read tool call was no longer visible to the agent. Now, work-boundary triggers (commit detection, historian completion, todo completion) re-surface the same notes when the agent has lost visibility into them. - Installer always picks the latest plugin version. The
curl | bashand PowerShell installers now explicitly pin@cortexkit/opencode-magic-context@latestso cached older versions are bypassed cleanly.
What's New
- Auto-update: Magic Context now detects newer npm releases on session start and self-updates the cached install, since OpenCode no longer auto-resolves
@latestplugin entries on each launch. Updates apply on the next OpenCode restart. Theauto_updateflag (defaulttrue) is USER-only — project configs cannot disable plugin self-updates. Pinned versions (@0.15.5) are detected and skip auto-update with a notification instead. doctor --issueredacts secrets before bundling logs into bug reports. The sanitizer recognizes 12 secret-token shapes including Anthropic, OpenAI, GitHub PATs, HuggingFace, AWS access keys, Slack, Google API keys, JWTs, bearer tokens, and generic env-var assignments where the variable name suggests a credential.
Upgrade
bunx --bun @cortexkit/opencode-magic-context@latest doctor --forceAfter upgrading to v0.15.6, future plugin updates install automatically — no more manual doctor --force runs to clear stale caches.
Full Changelog: v0.15.5...v0.15.6
v0.15.5
🚨 Critical Fix
v0.15.4 broke the curl-piped installer and any plain-bunx CLI invocation. This patch restores both.
What was broken in v0.15.4
The CLI bundle imported bun:sqlite at module top (used by the historian-failure section of the diagnostics report). Node's ESM loader rejects bun: specifiers during module resolution — before any user code runs — so the entire CLI crashed the moment it was launched under Node:
Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only URLs with a scheme in:
file, data, and node are supported by the default ESM loader.
Received protocol 'bun:'
This affected:
curl ... install.sh | bash— the piped installer routes throughbunx <pkg> setup(delegates to Node by design, because@clack/promptsinteractive selects don't work reliably under Bun on/dev/tty).- Plain
bunx <pkg> setup/bunx <pkg> doctor/bunx <pkg> doctor --force/bunx <pkg> doctor --issue— same Node delegation path.
The runtime plugin loaded by OpenCode itself was unaffected (it's built --target bun and OpenCode loads it under Bun).
Fix
bun:sqlite is now loaded lazily via a runtime-gated dynamic import inside collectHistorianFailures():
- Under Bun: the import succeeds and historian failures are read normally.
- Under Node: the import is skipped entirely. The historian-failure section of
doctor --issuereports as empty; every other diagnostic (config, plugin cache, conflicts, log tail, dump metadata) builds normally.
Upgrading
If you're on v0.15.4 and bunx ... setup or bunx ... doctor is failing for you, force the Bun runtime once to clear the broken cache:
bunx --bun @cortexkit/opencode-magic-context@latest doctor --forceAfter v0.15.5, both bunx <pkg> (Node) and bunx --bun <pkg> (Bun) work for all CLI commands.
Full Changelog: v0.15.4...v0.15.5
v0.15.4
v0.15.4
Three correctness fixes plus a sidebar/status alignment that resolves a long-standing UX mismatch.
🎯 Sidebar token breakdown now matches /ctx-status
The TUI sidebar's token bar and /ctx-status's "History block" line have been showing different numbers for the same content — sometimes off by 5K+ tokens. Two structural fixes land in this release:
Per-model calibration for tokenizer drift. ai-tokenizer's claude / o200k_base / cl100k_base / p50k_base encodings approximate provider tokenizers but drift by model-specific amounts — Anthropic Opus 4.7 most aggressively (1.51× system, 1.57× tools), GitHub Copilot and OpenRouter routing the same models with the same drift. The sidebar now scales System and Tool Definitions through empirically measured ratios from scripts/calibrate-tokenizer/, so those two buckets match billed tokens within ~5%.
Verbatim history buckets. Compartments, Facts, and Memories now display local raw counts unscaled — the same numbers /ctx-status reports as "History block". The sidebar and status dialog now match exactly. Conversation and Tool Calls absorb the remaining provider-reported drift proportionally, which is the most honest mapping for buckets containing mixed user/assistant text and tool I/O.
The sum of all categories equals provider-reported inputTokens exactly — verified across pathological inputs including clamp-path edge cases.
🧠 Three single-purpose signal sets replace flushedSessions
The old flushedSessions set was overloaded: producers used it to mean "history needs refresh", "system prompt needs refresh", and "pending ops need to materialize" all at once, and consumers couldn't tell which intent applied. This caused two real bugs:
- After a historian publication busted cache once, the flag stayed set, so the next defer pass would gratuitously rebuild
<session-history>again with no DB change in between — one wasted cache-busting cycle per historian run. - A
/ctx-flushissued during an active historian run could lose its pending materialization signal because the same flag was being drained for unrelated reasons.
Split into three independent session-scoped sets in live-session-state.ts:
historyRefreshSessions— drained immediately whenprepareCompartmentInjection()consumes itsystemPromptRefreshSessions— drained at handler entry only when the handler actually consumed a refresh signalpendingMaterializationSessions— survives blocked passes; only drains after heuristics actually run
isCacheBustingPass was redefined to mean "this pass mutated state" rather than "this pass had queued intent" — closing the cascade and making the cache-busting discipline explicit at every consumer.
💾 memory.enabled and memory.auto_promote now honored
Two memory config flags existed but had no effect on automatic promotion. Historian and recomp would still promote session facts to project memories regardless of either setting. Reported in #44.
memoryEnabled and autoPromote are now threaded through both runners; promotion is gated on memoryEnabled !== false && autoPromote !== false. Manual ctx_memory write is unaffected — it still works when memory.enabled: false, intentionally, because tools that the agent invokes explicitly should respect the agent's intent. When memory.enabled: false, the ctx_memory tool itself is hidden from the agent's tool list as before.
🔍 Embedding endpoint failures now actionable
embedding-openai.ts was reporting Unexpected end of JSON input SyntaxErrors when openai-compatible endpoints returned empty bodies, HTML error pages, or non-JSON responses. The root cause was almost always endpoint config (wrong path, auth failure, wrong model name) — not actually a JSON parse problem.
The reader now loads the response as text first, then attempts to parse. Empty bodies produce a typed EmptyBody failure, non-JSON bodies produce a typed NonJsonBody failure with a snippet of the actual response, and both are recorded as circuit failures with informative log messages. Single transient blips don't trip the breaker — it still requires 3 failures within a 60s window.
🪟 Dashboard cache page: per-session windowing
Reported separately. The cache events query was using a single global LIMIT, so when many sessions were active concurrently, each one's visible bar count would shrink. Replaced with ROW_NUMBER() OVER (PARTITION BY session_id) so each session can show up to 200 cache events independently. Frontend windowing matches.
The dashboard's Dreamer config card was also rendering as a malformed nested-grid; restructured into two clean stacked 2-col rows. (Both ship in the next dashboard release.)
🧪 Verification
- 973 plugin tests, 23 e2e tests, lint, typecheck, build — all green
- Plus regression tests for the three-set signal model, calibration sum invariants (including pathological tiny inputs), longest-prefix matching across OpenRouter / GitHub Copilot routes, and
memory.enabled=falsepromotion gating
🔧 How to upgrade
```bash
bunx --bun @cortexkit/opencode-magic-context@latest doctor --force
```
Restart OpenCode afterward.
Dashboard dashboard-v0.3.4
🐛 Fix
Model dropdowns no longer empty for users with stock OpenCode installs
The "Add fallback model" dropdown for historian, dreamer, and sidekick was rendering "No models found" for users whose opencode binary lives at ~/.opencode/bin/opencode (the path the official OpenCode installer writes to).
Root cause: GUI processes on macOS don't inherit shell $PATH, so the dashboard tries an explicit list of candidate binary locations when running opencode models. The previous candidate list missed the most important location — ~/.opencode/bin/opencode — so the lookup failed silently and models() returned an empty array, which made every model dropdown render its empty-state.
This bug masqueraded as the same fallback_models filter problem fixed in v0.3.3. The v0.3.3 fix (string-vs-array normalization) addressed one of two distinct empty-dropdown causes; this release fixes the deeper one.
~/.opencode/bin/opencode is now the first candidate on macOS and Linux, with %USERPROFILE%\.opencode\bin\opencode.exe as the first Windows candidate. The shell-PATH opencode fallback is preserved for users who launch OpenCode from a terminal.
After upgrade, the existing availableModels localStorage cache (empty [] from a prior failed lookup) is overwritten by the next refresh on app startup — no manual cache clear required.
📦 Pairs with plugin v0.15.4
This dashboard release is tested against plugin v0.15.4. Upgrade both for the full experience:
bunx --bun @cortexkit/opencode-magic-context@latest doctor --forceUpgrade
Auto-update is enabled — existing installations will prompt within 24 hours. You can also trigger it immediately via Check for Updates... in the app menu (macOS) or the tray icon.
Manual install: download from the release assets below, or fetch from https://cortexkit.github.io/opencode-magic-context/latest.json.
Full Changelog: dashboard-v0.3.3...dashboard-v0.3.4