Skip to content

v0.23.0

Choose a tag to compare

@github-actions github-actions released this 11 Jun 14:37
· 2847 commits to master since this release

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_note read is paginated — newest 25 first with a "N older" continuation footer, instead of dumping hundreds of notes into context.
  • ctx_memory takes one unified ids array — update one, archive many, merge several, all through the same parameter.
  • Notes are anchored to the conversationctx_note read shows ↳ @msg N so the agent can expand the conversation that produced a note.
  • ctx_search got 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_reduce could 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-aug helper) is read-only on project memory now; ctx_memory archive rejects 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 and npx @cortexkit/magic-context@latest doctor removes 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.