v0.23.0
v0.23.0 — Self-managing context, big-session speed, and the title fix
A minor release with three themes: the context-reduction system was rebuilt around quiet, cache-safe nudges (and subagents now manage their own context); the heaviest per-message work moved off the database hot path, removing multi-second stalls on large sessions; and the agent can now maintain its own project memories instead of only writing new ones. Includes two database migrations (applied automatically) and the fix for the missing-session-titles regression.
Highlights
The agent maintains its own memories now. ctx_memory grew update, archive (including batch archive in one call), and merge for the memories the agent already sees in its context — previously these were reserved for the background dreamer, so a wrong or outdated memory stayed wrong until the next maintenance run. Cross-project access stays locked down: an agent can only touch its own project's memories. Memory categories are now schema-enforced (the 5-category taxonomy), so invalid categories fail at validation instead of being silently rejected.
Context nudges are quieter and structurally simpler. The agent-facing context-reduction reminders (never shown in chat) used to be injected into the message stream and replayed byte-for-byte on every pass — which worked, but needed careful replay machinery to stay cache-stable. The redesign removes that machinery instead of maintaining it: a compact <system-reminder> appended to tool outputs when reclaimable context piles up (Channel 1) persists naturally in the session database with nothing to replay, and a single one-shot escalation near the threshold (Channel 2) is delivered mid-turn — between tool calls, while the pile is still growing — and only when a fresh measurement confirms it's still warranted, never on stale data. Channel 1 paces itself: the re-fire interval scales with the history budget, repeat reminders in the same severity band are suppressed, and the cycle resets once the pile actually shrinks — so a long turn sees a handful of escalating reminders instead of one per tool call. Subagents get the same self-management machinery now: they see §N§ tags and ctx_reduce, with a minimal guidance block, so long-running subagent sessions no longer balloon.
Emergency context recovery actually hits its target. At ≥85% pressure the tiered emergency drop (T3 misc → T2 edit/search → T1 navigation tools, newest 20% of each tier reserved) replaces the old need-blind age-based drops — and its reclaim target is now computed from the full live tail, fixing a systematic under-eviction the audits caught. The routine auto_drop_tool_age / drop_tool_structure config knobs are removed (doctor cleans them up); reduction is the agent's job via ctx_reduce, with the tiered drop as the safety net.
Big sessions got dramatically faster. Three structural fixes for sessions with tens of thousands of messages:
- The historian trigger no longer re-reads the session from the database on every streaming event (which froze the event loop ~3s per event on a 60k-message session). It now runs once per request, inside the transform, from the messages already in memory — zero database reads in steady state.
- Per-message token counts are computed once and cached on the tag row, then summed in SQL — the sidebar, the history boundary, and the nudge math all read the same durable counts (a 250ms-per-pass floor went to 2.4ms).
- The protected-tail boundary reads only the post-compaction tail, never the whole session.
History compaction can't deadlock on sparse sessions (#132). The protected tail — the recent slice the historian never summarizes — is now sized by tokens rather than "the last 5 user turns." Sessions with few user messages (long autonomous runs, AFK workflows) previously protected everything and could never compact; now they compact like any other session. And the inverse guard: the size-based trigger fires on actual summarizable content, so tool-heavy sessions at low pressure no longer spawn the historian to write fragmented mini-compartments — runs batch into properly-sized history chunks.
Session titles generate again in fresh directories (#129). OpenCode permanently skips title generation once a session contains more than one real user message — and Magic Context's startup notifications (config warnings, conflict warnings, announcements) could land in a brand-new session before its title was generated, suppressing it forever. This reproduced most often in non-git directories, where the new session is the only delivery target. Notifications now wait for the session to have a real title and retry on a later launch otherwise.
Improvements
- Tool descriptions rewritten for the agent. All five
ctx_*tools now explain what they're for and when to reach for them, with concrete examples (including what a<compartment>is and how to expand one). Pi previously carried drifted inline copies; both harnesses now share one source. ctx_noteread is paginated — newest 25 first with a "N older" continuation footer, instead of dumping hundreds of notes into context.ctx_memorytakes one unifiedidsarray — update one, archive many, merge several, all through the same parameter.- Notes are anchored to the conversation —
ctx_note readshows↳ @msg Nso the agent can expand the conversation that produced a note. ctx_searchgot literal-probe recall — exact symbol names, slash-commands, paths, and commit SHAs now match reliably alongside semantic search.
Fixes
Beyond the headline items, three blind audit rounds over this release's changes surfaced and fixed (among others):
- Channel-2 nudge could deliver on stale pressure data and permanently consume its one-per-session cap; delivery now revalidates the full trigger predicate and an unknown measurement never burns the cap.
- The cheap historian-trigger gate undercounted eligible history after tool drops, suppressing real compaction triggers in long sessions.
- Legacy tool tags (from sessions started before v0.23.0) never converged to the new token cache; they now backfill on first observation.
- A primary agent could merge another project's memories (now dreamer-only, like the rest of cross-project access).
- Token-count math: ordinal gaps from malformed rows no longer drop valid messages from boundary sums; a literal
<EOT>-like string in tool output no longer crashes tokenization. - Tool calls cleared by
ctx_reducecould be stripped one pass too early, busting the prompt cache on a defer pass (frozen-watermark replay fixes it). - Routine history compaction can no longer cross the newest user message — the active prompt always survives a background historian pass intact.
- The Channel-2 one-shot lease is crash-safe: a delivery interrupted mid-send (process kill, database contention) is recovered by a TTL-scoped heal instead of wedging the nudge off for the rest of the session.
- Two processes opening the shared database at the same moment could race during the WAL journal-mode switch; the busy timeout now installs first.
- One-shot notifications (upgrade reminder, context-limit alert) only mark themselves delivered after an actual send — a skipped or failed delivery retries on a later launch instead of being lost.
- Sidekick (the
/ctx-aughelper) is read-only on project memory now;ctx_memory archiverejects already-archived ids with a friendly error instead of silently re-archiving.
Config changes
- Removed:
auto_drop_tool_age,drop_tool_structure,nudge_interval_tokens,iteration_nudge_threshold(the features they tuned were replaced by the systems above). Stale keys in your config are ignored andnpx @cortexkit/magic-context@latest doctorremoves them. - Database migrations v31–v32 apply automatically on first start. As always with a schema bump: update both harnesses (OpenCode and Pi) around the same time if you use the shared database from both — an older binary fails closed (safely, with a notice) against a newer database.
Pi
Full parity for everything above: Channel 1/2 nudges (via tool_result mutation and agent_end follow-up), the tiered emergency drop, the protected-tail redesign, cached token counts, memory actions, and the shared tool descriptions.