Skip to content

v0.46.0

Choose a tag to compare

@github-actions github-actions released this 08 Oct 08:29
· 150 commits to master since this release

This minor release adds protected_tools, which keeps the newest results of chosen tools out of every automatic drop, and turns smart drops on for everyone. It migrates the shared database to schema v95. In Rust transform mode on OpenCode 1, the compaction marker now moves past partial summaries, so OpenCode stops sending nearly the whole conversation every turn. Edits to cache_ttl now reach running sessions (#624), and on OpenCode 2 the dreamer runs on its schedule (#627) and per-model execute thresholds apply (#622). The release also fixes several unnecessary prompt-cache rewrites, makes smart-note checks more robust, and lowers the cost of each pass on large sessions. OpenCode 2 history commands now work with pure-v2 stores, tool errors survive /compact, and the historian works on Pi 1.0.

Upgrading

  • The database moves from schema v94 to v95. The migration runs the first time the new version opens context.db. It adds indexes for cleanup, retention and search reads, removes indexes that duplicate others, adds a lookup table for git commit search, and moves stored idle-gap marker decisions into their own table. On a 6.2 GB copy of a real database, the migration itself took about 1.4 seconds and that first start about 3.2 seconds.
  • Quit every OpenCode, OpenCode 2 and Pi process before restarting any of them. They all share one database, including instances in other projects. While a process on an older version is still running, the new version refuses to migrate. After the migration, a host still on an older version refuses to open the v95 database, and downgrading the plugin does not downgrade the database.
  • OpenCode 2 still needs 2.0.22 or newer. On an older OpenCode 2, Magic Context stays off and refuses every turn with a notice asking you to upgrade. OpenCode 2 does not install plugin updates on its own: open /plugins, select Magic Context and press ctrl+u, or run opencode plugin update.
  • Rust transform mode (experimental): use the ck-mc from this release. v95 changes the indexes on two tables that ck-mc writes, so an older ck-mc refuses to write history summaries and user-memory candidates to the migrated database.
  • Remove smart_drops from your config. The setting is deprecated and ignored because smart drops are now always on. A config that still contains it loads normally, and doctor reports a config warning until you remove it.
  • If the upgrade stops with a message about the git commit search map, stop every host and run magic-context doctor git-fts-map --repair. It backs up context.db and store.db first and rebuilds only that map. Without --repair, the command only reports what it finds.

New

  • protected_tools: keep the newest results of chosen tools (#621, requested by @tenshiak). A map from tool name to a count, for example "protected_tools": { "ask_user": 3 }, keeps the newest N completed results of each named tool out of every automatic drop, at any context pressure. The defaults are todowrite: 1 and ctx_reduce: 3; your user and project maps are merged over them, and 0 turns protection off for a tool. Tool names are case-insensitive and ignore a leading mcp_. A ctx_reduce or historian drop that targets a protected result waits until newer calls push it out of the protected count. Protection does not stop the historian: when that part of the conversation is summarized, the raw result leaves with it. If protected results alone cannot fit the model's context window, the turn is refused with an explanation instead of being sent over the limit. This applies on OpenCode, Pi and the Rust module.
  • Smart drops are always on. Tool output that a later call has made obsolete is now removed for everyone: older edits to the same file are shortened to a marker that keeps the file path, and spent todowrite, ctx_reduce and status outputs are dropped. This happens only on passes that already rebuild the prompt cache, so it never causes a cache rewrite on its own; a session that had smart drops off catches up on its first such pass.
  • OpenCode 1, Rust transform mode: the compaction marker now advances. Rust-mode summaries usually end partway through a message, and a safety check kept OpenCode's compaction marker from moving past those ends, so OpenCode sent nearly the whole conversation (thousands of messages on long sessions) every turn, slowing every pass. The marker now moves past ends that the next summary covers, never past content that has not been summarized, and only on passes that already rebuild the cache. When a pass cannot prove that the shortened request fits, the move waits for a later rebuild. If a pass fails after it may have moved the marker, that turn is refused and the next turn rebuilds the request instead of resending stale data.
  • cache_ttl edits apply to running sessions (#624, reported by @null-axiom). User and project cache_ttl settings now take effect on the next pass in OpenCode, Pi and the Rust module; only the built-in defaults stay fixed per session. Raising the TTL keeps the cached prefix; lowering it rebuilds only after the normal idle expiry. /ctx-status now says whether the TTL comes from your config or from the built-in default.
  • OpenCode 2: the dreamer runs on its schedule (#627, reported by @ICEY16360). The dreamer's schedule timer never started on OpenCode 2, so dream tasks ran only after a session finished a turn. The timer now starts on OpenCode 2 and stops when OpenCode 2 shuts down or reloads the project. A scheduled run uses the most recent session in that project folder; if there is none yet, tasks that need a session wait for their next scheduled time, and the other tasks still run. On OpenCode 2 the timer does not yet clean up stored data for deleted sessions.
  • The dashboard ships separately and has its own release notes.

Changes

  • OpenCode subagents no longer get ctx_memory and ctx_note. Memories and notes belong to the primary session, so these tools are hidden from subagents on OpenCode 1 and 2, and a subagent call to either is refused. ctx_search, ctx_expand and ctx_reduce stay available, the primary session's tool list does not change, and Pi is unchanged.
  • More varied historian calibration examples. The historian now sees three built-in example summaries, three older summaries from the session chosen for a spread of importance scores, and the session's four most recent summaries without their scores, so the scores it gives new summaries lean less on recent ones.
  • Files are created owner-only everywhere. The Rust module (ck-mc), setup, doctor, database repair and the dashboard now create Magic Context's files as 0600 and directories as 0700, as the plugin already did, and your user magic-context.jsonc ends up 0600 when one of them rewrites it. In Rust transform mode the shared data directory stays owner-only even with storage.enforce_private_permissions: false.
  • SQLite now syncs less often on Pi, the CLI and the Rust module. These writers use SQLite's NORMAL sync mode with its write-ahead log, as OpenCode on Bun already did. In a measured run of 32 writes, the total time spent holding the write lock fell from about 4.1 ms to 0.25 ms. After a power failure or operating-system crash, the most recent writes can be lost, but the database stays consistent.
  • OpenCode 1.18.32 and newer adopt a system-prompt change on the request whose messages are final. The new system prompt is already sent on that request, so Magic Context no longer schedules another rebuild that would rewrite the provider cache a second time.
  • The Rust historian input names its raw message range. It now includes a Messages X-Y: header, matching the TypeScript historian input even when some messages are omitted from the prompt.
  • Rust transform mode waits for an execute pass to publish the first historian result into an append-only prompt. A historian finishing below the execute threshold no longer forces an early rewrite of the warm prompt prefix.
  • Configured model variants reach Rust-mode historian and dreamer requests. The Rust module now sends each configured chain model's variant, including fallback models, instead of using the provider default.
  • The OpenCode plugin no longer installs its own copy of Solid and OpenTUI. OpenCode's TUI already provides them to plugins, so solid-js, @opentui/core and @opentui/solid are now optional peer dependencies. This removes two critical advisories in seroval (GHSA-p6vx-979v-rg4c, GHSA-jp82-f5mq-hwhp) from the installed package. The sidebar and status dialog render as before on OpenCode 1 and OpenCode 2.
  • The dreamer recognizes a provider's quota notice. Some auth plugins answer an exhausted account with a short message instead of an error. Magic Context now treats that as a provider failure, uses your configured fallback model, and skips the exhausted model for the rest of that run until its reset time. /ctx-status shows when the primary model's quota resets.

Fixes

  • OpenCode 2: /ctx-wrapup and /ctx-recomp work with pure-v2 stores (#629, reported by @isilveirascsimdigital). Both commands now use the OpenCode 2 history and compaction paths instead of attempting a v1-only database write.
  • OpenCode 2: tool errors survive /compact (#631, reported by @moynzzz). Compacted requests keep both the error status and the error text for earlier tool calls.
  • Pi: historian runs on Pi 1.0 (#633, reported by @WhaleFell). Plain Pi no longer reads Oh My Pi's host tool registry while its extension runtime is loading, which could fail historian and recomp runs.
  • Search no longer returns memories already shown in forced folds. OpenCode 1 and Pi now track the memories rendered in both history blocks, so ctx_search excludes memories already visible in the updates block.
  • Pi keeps the measured last-good request across append-only recaptures. New messages appended to a previously measured request no longer discard its provider-measured size, reducing false over-window refusals.
  • Writes stop when another machine holds the session's agent checkout. OpenCode 1, OpenCode 2 and Pi now refuse the turn with an explanation rather than writing session state for an agent checked out elsewhere.
  • Subagents apply queued drops at the execute threshold (#619, reported by @dhaern). A subagent's queued ctx_reduce drops and other queued cleanup waited until its context reached the force band. They now apply on the subagent's passes at the execute threshold. Primary sessions are unchanged. This applies on OpenCode, Pi and the Rust module.
  • OpenCode 2: per-model execute thresholds apply (#622, reported by @Tahmid-kabir-addin). Per-model entries in execute_threshold_percentage and execute_threshold_tokens were ignored on OpenCode 2, so every session used default to decide when queued drops run and when the historian starts. OpenCode 1 and Pi were not affected.
  • ctx_reduce no longer drops ctx_reduce calls (#623, reported by @Sugaroverdose). A model could ask ctx_reduce to drop the tag of its own ctx_reduce call, see the context unchanged because the newest tags are protected, and repeat the same reply in a loop. A request to drop the tag of a ctx_reduce call is now skipped with one sentence in the tool result explaining that these calls are cleaned up automatically; the other requested tags still apply.
  • Note reminders no longer rewrite cached messages. A reminder about pending notes could be added to a user message that had already been sent, rewriting the cached prefix from that point (about 147,000 tokens in one measured case). Reminders are now added only to a new user message the first time it is sent, or on a pass that already rebuilds the cache. This applies on OpenCode, Pi and the Rust module.
  • Pi: idle-gap time markers stay put after a history cut. After Pi removed old history, the next pass could drop a time marker such as +5m from an earlier user message, rewriting about 186,000 cached tokens in one measured case. Each message's marker decision is now stored and replayed on later passes, and markers for new messages are decided only on a pass that rebuilds the cache.
  • Rust transform mode: a held replay is no longer released early. After a pass falls back to the last good request, Rust mode keeps sending those exact bytes. 0.45.0 ended that hold after a set number of passes or new messages, and a counting error could end it on the very next healthy pass, so earlier messages that were already cached changed. The hold now lasts until a pass that rebuilds the cache anyway, or until the held request is no longer safe to send, and new messages reach the module as small updates in the meantime. If both the held request and the module's output are known to be over the model's limit, the turn is refused instead.
  • Fallback resends are judged on the provider's measured size. When Magic Context resends the last good request because the current pass failed, it now uses the provider's measured size of that request plus an estimate for the new messages, instead of re-estimating the whole request. A large session could otherwise be refused at an estimate well above its real size. This applies on OpenCode 1 and 2.
  • Rust transform mode: ctx_search with a date range finds older matches. Date filters were applied after each source's 100-result cap, so older matches inside the range could be hidden behind 100 newer ones.
  • Smart notes wait out GitHub rate limits instead of parking public repositories. Compile dry-runs and scheduled checks now recognize GitHub's secondary rate-limit responses as well as reset and Retry-After headers, and retry later without counting a failure. Warnings that a check could not run are marked as delivered once shown, so they do not repeat on later turns. This applies on OpenCode and Pi.
  • Smart-note checks no longer time out on slow sites. A check could be stopped after 2 seconds while its web request was allowed 5, so a slow GitHub answer failed the check and, after three such failures, downgraded a healthy note. Checks now get the full request time, and a network timeout is retried later without counting as a failure.
  • Smart-note checks can no longer hang the dreamer. A check waiting on a host call, such as a web request, that ignored cancellation could hold up the whole sweep and the dreamer task; every such call now ends at the check's deadline. A slow start of the check sandbox no longer cuts into a check's own time limits, and a sandbox that fails to load within 10 seconds leaves the check for the next sweep without counting a failure.
  • Startup right after a migration no longer races the migration's cleanup. The migration reported that it had finished before closing its database connection, so a host that read the database immediately could fail with a "database is busy" error.

Performance

  • Pi batches heuristic tool-removal bookkeeping. On cleanup passes that remove many tools, Pi now prepares native removal markers in one transaction instead of writing once per tool.
  • Fold preparation holds the write lock for less time. Rendering the main history summary and preparing drop conversions happen before writer admission; rendering the history-update delta and writing the cached prompt remain together under the lock.
  • OpenCode 1 execute passes avoid log-only host reads and full tag loads. They no longer wait for permission reads used only for logging, and pending drops load only the tags they need instead of the session's full tag history.
  • Shorter database lock holds after a history summary. Choosing which drops to queue after the historian publishes now happens before taking the write lock, so other sessions' turns no longer wait behind it. This applies on OpenCode and Pi.
  • Faster, bounded compaction-marker writes on OpenCode 1. The check before writing the compaction boundary into OpenCode's database now uses the per-message index (1.7 seconds to under 1 ms on a session with a million parts), and the write waits at most 250 ms for OpenCode's own writer before retrying on the next rebuild. Removing a marker keeps its longer wait.
  • Faster passes and lower memory on large sessions. Repeated work on each pass is reused or skipped: token measurements of unchanged messages, Pi's session snapshots and history lookups, and checks for queued drops. Per-turn state now keeps small flags instead of the streamed message content: 3.7 MB instead of 121 MB on a 60,000-message test session. Pi also releases a session's cached content when the session closes.
  • Fewer database reads and writes. Opening the database no longer takes the write lock when there is nothing to update; with another process holding that lock, an open fell from 286 ms to under 1 ms. On OpenCode 2, Magic Context reads OpenCode's storage less often and skips state writes that would not change anything. The new v95 indexes speed up cleanup, retention and git commit search.
  • Faster doctor on large databases. The check for projects split across two identities fell from 1.3 seconds to 70 ms on 60,000 sessions in one directory.

Internal

  • Release, CI and test infrastructure, the Rust module's role catalogs and model-runner client for CortexKit's own tooling, and design and measurement reports. None of these change behavior in OpenCode or Pi.