# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.7.1] - 2026-11-08

### Changed

- **Published through npm trusted publishing** — this version is published by the tag workflow with npm trusted publishing instead of by hand. The package contents are unchanged from 0.7.0.

## [0.7.0] - 2026-11-06

### Added

- **Date anchor** — the `schematic_date` prompt section holds a `## Current date` block (ISO date, weekday, IANA zone, UTC offset, plus a resolve-relative-references directive). `before_agent_start` renders it once per user prompt, and it is byte-stable within a calendar day, so while the host zone stays fixed it changes at most once per day; on a DST transition day the offset adds one more change. When it changes, Pi appends a section-update message and the leading system message stays unchanged. A zone Intl cannot render falls back to `UTC` rather than throwing.
- **Notebook pages open in a pager** — Enter in the interactive `/notebook` picker opens the selected page in `$PI_PAGER`, else `$PAGER`, else `less` if installed (not on Windows); with no pager or a `cat` or `more` pager it shows the inline preview instead. Quitting either returns to the list on the same page. See [Compatibility and limits](README.md#compatibility-and-limits).
- **npm package** — Published on npm as `@chunkhound/pi-schematic`; install with `pi install npm:@chunkhound/pi-schematic`.

### Breaking Changes

- **No compaction events for a handoff cut** — `session_before_compact` and `session_compact` no longer fire for a handoff; schematic no longer handles `session_before_compact`. Other extensions find the cut as a `compaction` entry whose `details.handoffId` is set.
- **`handoff` must be the only tool call in its message** — a `handoff` that shares an assistant message with other tool calls is refused and stages nothing; the other calls go to their own handlers, and the refusal tells the model to call `handoff` alone in its next message. Previously the `handoff` ran, its cut aborted the run, and the calls after it in the message were skipped. When a message holds only `handoff` calls, every call after the first is refused.
- **Successor recovery is removed** — a session written by an earlier version whose successor was lost after its cut is not repaired, and the user prompts again.
- **Spawn returns failures once the child session exists** — a spawn that fails after its child session was created now resolves with an error result carrying the child's usage. It used to throw. This covers a failed prompt, a child with no output, a reset, an abort, a failed dispose, and a prompt Pi rejects before the run. A failure before the child session exists still throws: model or route resolution, constraint validation, and the session factory rejecting. A direct caller of `execute` gets a resolved error result where its call used to reject, and `details` and `usage` now carry the child's stats, or `statsUnavailable`. A child run that ends with stop reason `error` or `aborted` also returns an error result with `isError`, and `details.outcome` stays `error` or `aborted`. See [Architecture](docs/architecture.md#behavioral-notes).
- **`truncateText` is no longer exported** — `spawn/index.ts` no longer exports `truncateText`. Spawn limits its result text internally, and a caller that imported the function needs its own copy.
- **Global Model Groups follow the agent directory** — with `PI_CODING_AGENT_DIR` set to a directory other than `~/.pi/agent`, the global `model-groups.json` is read only from `pi-schematic/` inside that directory. A `model-groups.json` at `~/.pi/agent/pi-schematic/` is then no longer read and is not migrated; move it into the agent directory. Until it is moved the file is missing, and a missing file loads as an empty configuration with no warning: `/model-groups` lists no global groups, and in an interactive session a prompt whose frontmatter names one of those groups, with no project group of the same name and no explicit `model:`, does not expand and reports an error containing `Model Group '<name>' is not defined.` A `spawn` naming such a group runs on the parent's model; the spawn tool's TUI display marks it as `<group>? fallback → <provider>/<model> • <thinking>` and the result's `details.route` carries status `unknown-fallback`, while the result text the model receives carries no marker. The global prompt scan moves the same way. With such a directory set, pi's default prompt discovery no longer covers `~/.pi/agent/prompts`, but schematic used to read the frontmatter of those prompts and apply their `readonly`, `model` and `thinking` values to a typed command that pi did not expand. Schematic no longer scans that directory.

### Changed

- **Handoff completes inside the calling run** — the cut and the successor are written together at the end of the turn that called `handoff`, in one `turn_end` boundary pass: notebook discard entries, a retain-none compaction, the successor, and a hidden note. The successor turn continues the same run. If another extension's `turn_end` handler stops the continuation, the successor runs on the next prompt. The successor shows as a `pi-schematic-handoff` message instead of a user message, and a hidden `pi-schematic-handoff-note` tells it that the system prompt is stale until the next run starts; a message typed during the run does not refresh it. If another extension's `turn_end` handler keeps the cut and the successor but drops the notebook discard entries, the pages stay in the notebook, the completion notice counts them as kept, and a session with a UI also shows a warning naming them.
- **Failed handoff cut** — a handoff whose cut is missing at the next turn or when the run settles reports the failure and leaves a pending handoff request pending. The failure guidance is a `pi-schematic-handoff-failed` message that starts no run, for an abort and for every other cause (another extension replacing the `turn_end` entries, invalid drafts). Further `handoff` calls in the same run are refused, and after a dropped cut the notebook is rebuilt from the branch. The watchdog's `MAX_HANDOFF_ATTEMPTS` still bounds the attempts, and the failure on the last attempt says no required handoff remains pending. A `handoff` call rejected at validation reports its reason in the tool's error result and queues no follow-up message. If another extension's `turn_end` handler keeps the cut but drops the successor, or appends its own compaction after the cut so the successor is no longer in context, the handoff fails instead of completing. A successor turn is aborted before it reaches the model, the failure message carries the instruction, and the request is cleared without a retry because the context is already cut.
- **Spawn result limit marker** — the truncation marker and the child prompt write the size as `50 KiB (51200 bytes)`, the form notebook uses, instead of `50KB`. The marker now advises spawning a new child with a narrower request.
- **Pi minimum** — Pi 0.99.2 is now the documented minimum for the `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent` and `@earendil-works/pi-tui` peers, and the `typebox` peer minimum is 1.3.27.

### Fixed

- **Handoff successor cannot be lost between the cut and a send** — the successor is persisted in the same pass as the cut instead of being sent afterwards.
- **Readonly blocks the powershell tool** — readonly mode now blocks pi's built-in `powershell` tool in the parent and removes it from readonly children, and readonly bash blocks launching PowerShell or cmd. Previously a Windows setup with `powershell` in `defaultTools` had an unguarded shell.
- **Sections from other extensions reach the model** — schematic now adds its prompt content as named Pi prompt sections instead of replacing the system prompt, so sections written by extensions that run after it are no longer dropped (#45). A topic, Model Groups, or notebook change no longer re-sends the context-management primer.
- **Empty notebook pages** — selecting a page with an empty body in `/notebook` now opens it like any other page instead of closing the picker.
- **Discarded notebook pages** — selecting a page removed by a handoff discard while the `/notebook` list was open now reopens the refreshed list instead of closing the picker.
- **Model edit opens on the current thinking level** — opening a model in the Model Groups TUI now puts the cursor on the model's configured thinking level and marks it `✓ current`, instead of always landing on `inherit`, where Enter silently reset the value. A configured level the model no longer supports (or whose model is not in the registry) is still shown as `⚠ current, unavailable` and preserved unless another option is deliberately chosen (#29).
- **Handoff enforcement ignores automatic retries** — the watchdog counts a required handoff's enforcement attempts once per settled agent run instead of once per `agent_end`, so a run that pi retries automatically counts once. A run counts only when one of its requests carried the eligible required-handoff nudge, so a run that ends in automatic threshold compaction still counts and a run nudged only to keep working does not.
- **Spawn usage reaches the parent's totals** — `spawn` returns the child session's token and cost usage with its result. The parent's session totals and footer then include the work its children did. The sum covers the child's whole session, including compaction summaries. If the child's entries cannot be read or summed, the result keeps the child's text, reports zero usage and sets `statsUnavailable`. Context-window accounting is unchanged, because Pi does not count a tool result's usage toward the parent's context size.
- **Spawn preview strips terminal sequences** — the collapsed spawn preview now removes OSC (including OSC 8 links), APC, and erase and cursor-position sequences from child assistant text, not only SGR styling (#83).
- **Global files follow `PI_CODING_AGENT_DIR`** — the global `model-groups.json` and the global prompt scan resolve inside pi's agent directory, so with `PI_CODING_AGENT_DIR` set both move with it, as pi's own global files do. With the variable unset, both stay at their previous locations.
- **Type-checks against Pi 1.5** — the `spawn` tool builds its `thinking` parameter schema with typebox instead of pi-ai's `StringEnum`, which returns a non-typebox schema from Pi 1.5 on. The schema sent to the model is unchanged.
- **Readonly sandbox passes commands through and reports blocks on Linux** — readonly bash commands under `sandbox-exec` or `bwrap` now get the same stdin, exit code and output as unsandboxed commands, except for the differences listed in [Architecture](docs/architecture.md#behavioral-notes); commands that read stdin no longer swallow part of the sandbox wrapper, and output is no longer buffered until exit. The sandboxed command runs under the shell pi started instead of always under `/bin/bash`. The readonly block notice now appears on Linux (`Read-only file system`) and for lowercase errors such as node's `EPERM`/`EROFS`, and no longer appears for `Permission denied` failures the sandbox does not cause. The notice is appended to the failed tool result and says the block applies if the failure was a write outside the OS temp dir.

## [0.6.0] - 2026-09-26

### Added

- **Brand mark** — the blocky `S` for "schematic", built from Pi's 5×5 grid unit (`117.355`) and palette. Ships a static tri-colour mark, a monochrome variant, and a Tetris-style animated intro (`assets/`) used as the README hero and the pi.dev gallery preview (`pi.image`).

### Breaking Changes

- **Project renamed to `pi-schematic`** — the package, repository, and config directory move to `chunkhound/pi-schematic`. Runtime identifiers change with no backwards compatibility: session custom entries and TUI keys use the `pi-schematic-*` prefix, Model Groups persist under `~/.pi/agent/pi-schematic/` (or `.pi/pi-schematic/`), and the shared state type is now `SchematicState`. Existing sessions and config files from `pi-agenticoding` are not migrated.
- **Handoff carries the next instruction verbatim** — the handoff tool now takes `nextInstruction?`, `context?`, `discardPages?` (replacing the old `task` field). The successor's objective is delivered word-for-word in a real user message (`## Next instruction` + `## Context`), so it can no longer be paraphrased away at compaction. Human-facing behavior is unchanged (`/handoff <direction>` works as before); the break is limited to the internal LLM-facing tool contract, where stale callers passing `task` fail loudly.

### Changed

- **Handoff splits instruction from preparation** — the next instruction is carried by the extension and delivered verbatim (`/handoff <direction>` queues it, otherwise the model supplies it); the model owns only preparation: writing `context` (state, blockers, open questions, failed paths, concrete next step) and curating the notebook. The instruction must not be started in the current context, which is discarded at compaction.
- **Fixed continuation frame** — the compaction summary now has a fixed frame with no task text; each cut adds only an identity marker so Pi reports the correct compaction entry. The old synthetic "Proceed." is gone. The exact, versioned successor payload is also stored in compaction details, so `/tree` and resume recover it only when session-tree lineage shows no successor was delivered.
- **Readonly is live, not frozen** — the summary no longer embeds execution constraints (a `/tree` rollback can change readonly). On handoff completion a pending nudge re-announces the ON posture on the first post-handoff turn (a clean OFF-to-OFF handoff stays silent), and `/tree` navigation into an enabled branch re-announces it again; `tool_call` enforcement stays live.
- **Queue-safe post-compaction delivery** — handoff completion, failure guidance, and the successor's instruction are sent with `deliverAs: "followUp"`, so they queue while a run is active instead of being rejected (previously failure guidance could itself throw while streaming).
- **Recoverable successor delivery** — the exact payload remains in compaction details; `/tree`, resume, and a later settled run requeue it only when no user turn follows the cut and no session-tree descendant owned by that cut proves delivery. Pi exposes no delivery acknowledgement, so a failed fire-and-forget follow-up is recovered from persisted state rather than treated as confirmed delivery. Any user turn after the cut — the delivered successor or newer user input — ends recovery, while a delivered successor retained outside the active branch proves recovery is unnecessary during `/tree` editing, and an identical payload on another cut can neither mask a loss nor provoke a duplicate. Recovery coalesces repeated triggers through an in-process latch, waits for a queued follow-up to drain before rescanning (so a successor still in Pi's queue is never double-delivered), and clears the latch at every settled run so a genuinely lost send is retried while a persisted successor is never re-sent.

### Fixed

- **Lineage-based handoff recovery** — successor delivery is now attributed through the session tree: a user turn belongs to the nearest handoff cut on its `parentId` chain. Identical payloads on different cuts can therefore neither mask a genuinely lost delivery nor provoke a duplicate resend, replacing the previous same-message heuristic.
- **Malformed session content no longer crashes recovery** — unvalidated persisted user-message content (non-array content or non-object parts) is skipped instead of throwing during `session_start`, `/tree`, and settled-run recovery scans.

## [0.5.0] - 2026-08-21

### Added

- **Model Groups manager** — added `/model-groups` with durable project/global JSON persistence, boot validation, CRUD TUI flows, per-model thinking levels, and operator notifications for invalid configs or unavailable model refs.
- **Model Groups spawn routing** — `spawn` can route children through an optional exact Model Group name with names-only prompt guidance, `#group` autocomplete sugar that shows model/thinking details, authenticated random entry selection, thinking inheritance/clamping, and routed/fallback result identity lines.
- **Capability-aware spawn routing** — a Model Group now carries a capability set (currently input modalities: `text` and `image`) derived from its configured, authenticated members, with the option to narrow it via an explicit override capped at the member union. A `spawn` call can declare `constraints` the delegated task needs; the router checks the group and the exact selected model and fails before any child would be created when the requirement can't be met. The main-session prompt lists each group's capabilities.
- **Pluggable capability kernel** — added a small constraint system so each capability is one descriptor (read fact → aggregate → reconcile override → satisfy check → present). Modalities are the first, and only, production capability; a synthetic test-only descriptor exercises the full extension point so a future capability (e.g. min context window) needs no edits to config load, spawn routing, or UI render.
- **Frontmatter-driven model selection** — skills and prompts can declare `model`, `model-group`, and `thinking` frontmatter to control model routing and reasoning level per invocation. Resolved during idle input and visibly blocked while streaming; an explicit `model` overrides `model-group`; multi-slash model IDs are supported; invalid values block command expansion with operator notifications, and invalid thinking warns while a valid model still applies.
- **Handoff `discardPages`** — the handoff tool accepts `discardPages` to prune stale notebook pages, staged transactionally via a sequential epoch and committed only after compaction succeeds; interrupted or failed discards retain pages. Notebook rehydration is branch-scoped with generation markers and an epoch watermark, ignores future-format entries, and handoff now verifies notebook completeness first and reports completion truthfully after the discard commit.

### Changed

- **Model Groups editing** — searchable complete-result and ten-visible-row add-model pickers, plus a prompt-free inline group-name editor.
- **Spawn lifecycle** — migrated child spawning to Pi's public selected-model and child-owned runtime APIs, added `max` thinking support, and disposed every created child session exactly once across completion, failure, abort, and reset races. Pi 0.84.1 and Node 22.19.0 are now the documented minimums; parent-only transient provider/auth state fails explicitly without model fallback.
- **Model Group editing** — the editor now shows per-member capability chips (T/I) and lets users narrow the automatically derived modality set with an explicit override; group capability summaries also appear in `#group` autocomplete.

### Fixed

- **Model Groups add-model navigation** — now uses Pi's key matcher for Escape/left-arrow handling and filters provider/model choices to authenticated models.

## [0.4.0] - 2026-07-22

### Breaking Changes

- **Ledger renamed to notebook** — tools are now `notebook_write`, `notebook_read`, and `notebook_index`; `/ledger` is `/notebook`. Legacy `ledger-entry` session data still rehydrates so existing sessions keep their pages.
- **Handoff briefs no longer embed notebook bodies** — referenced pages are fetched on demand via `notebook_read`. The brief carries only the task and primer; the notebook remains the long-term grounding store.
- **Handoff eligibility gate** — handoff rejects empty briefs, sessions under ~30k tokens, or missing usage data so compaction cannot run without a real brief and a meaningful context load.
- **Human-set notebook topics are authoritative** — the agent cannot override a topic the user set via `/notebook` or the topic UI.

### Added

- **Readonly mode** — `/readonly`, Ctrl+Shift+R, and `--readonly` toggle a session-persisted read-only posture. Write/edit are blocked; bash is classified and limited (allowlist / temp-only writes), with OS sandboxing on macOS (`sandbox-exec`) and Linux (`bwrap`) when available. Spawned children inherit the posture (no write/edit; guarded bash). Status shows 🔒 with gentle nudges. Handoff is blocked unless the user runs `/handoff` or crosses an eligible human topic boundary; readonly resumes after compaction.
- **Notebook topics** — `notebook_topic_set` and `/notebook <topic>` set the active semantic frame (🧭 in the status bar). Topics clear after handoff so the next context assigns a fresh one. Topic-change boundary hints integrate with the watchdog.
- **Readonly frontmatter on skills and prompts** — `readonly: true` defers enabling readonly when that skill or prompt is invoked.

### Changed

- **Spawn tool inheritance** — child agents inherit active registered parent tools executable in the child session, including MCP/extension tools, while still excluding spawn and handoff and keeping child-local notebook tools.
- **Topic- and readonly-aware watchdog** — band-throttled primacy-zone nudges with copy that reflects the active topic and readonly state; warning widget at ≥70% context; malformed context percentages render as `ctx --%`.
- **Handoff lifecycle status** — richer TUI status (requested / required / in progress), generation guards, and rejection of overlapping handoff attempts.
- **Notebook overlay and indicators** — interactive `/notebook` overlay (renamed from `/ledger`) with subject-oriented page semantics; empty notebook count stays dim/discoverable rather than hidden without cue.

### Fixed

- **TUI-safe diagnostics** — removed stderr/console logging that corrupted pi's ANSI TUI rendering from the extension host process.
- **Headless UI guards** — `ui.notify` and readonly toggle no-op cleanly when no UI is attached instead of throwing.
- **Rehydration null-safety** — notebook and readonly session resume no longer crash on missing or partial persisted state.

## [0.3.0] - 2026-05-23

### Added

- **Interactive `/ledger` TUI overlay** — replaced the static notification popup with a full interactive overlay. Use arrow keys to navigate entries, press Enter to preview a selected entry body (truncated at 500 chars with `...`), and Escape to close. Empty state shows a discoverability hint.
- **Visual handoff indicator** — when `/handoff` is invoked, a live `🤝 Handoff in progress` badge appears in the TUI status bar. Clears automatically when compaction completes, or when the agent finishes a turn without calling the handoff tool.
- **Ledger tool TUI renderers** — `ledger_add` calls now render inline with a styled preview (`✓ Saved "entry-name": first line...`) in the conversation. Shows the full entry body when expanded.
- **Write-lock reentrancy detection** — nested calls to `saveLedgerEntry` now throw an explicit error instead of silently corrupting the serialization chain.

### Changed

- **Frame-based spawn scheduler** — replaced the microtask-per-event render model with a scheduler that batches expensive component work at ~30 FPS. High-frequency streaming events (50–100+/sec) accumulate state cheaply per-event; layout, cache invalidation, and TUI invalidates are deferred to the next frame tick. Eliminates UI jank during bursty LLM streaming in child sessions.
- **ESM module type** — added `"type": "module"` to `package.json` for compatibility with strict ESM projects.

### Fixed

- **Stray ANSI reset codes in spawn shell** — `truncateToWidth` no longer injects escape sequences that break background color styling in collapsed spawn renderer borders and padding.

## [0.2.0] - 2026-05-21

### Added

- **Microtask event batching** — rapid child session events are coalesced into a single parent invalidate per microtask boundary, preventing UI jank during bursty tool execution.
- **Epoch-based invalidation** — the spawn renderer uses epoch counters rather than pointer comparison to detect stale sessions, making ownership checks reliable across session resets.

## [0.1.0] - 2026-05-21

### Added

#### Context Management System Prompt

- **Automatic system-prompt injection** — the LLM receives a context management primer at session start, teaching it how and when to use spawn, ledger, and handoff. No configuration needed.
- **Live ledger listing in system prompt** — each session start injects the current ledger entries (name + first-line preview) so the agent always knows what stored knowledge is available without fetching blindly.

#### Spawn — Isolate Subtasks in Clean Child Contexts

- **`spawn` tool** — delegate isolated work to an in-memory child agent with its own clean context. The child inherits the parent's model, thinking level, working directory, and built-in tools. Only the condensed result is returned — no context pollution in the parent.
- **Parallel execution** — siblings run concurrently; the parent orchestrates and merges results. Tested for independent concurrent spawns producing correct results.
- **Child tool inheritance** — children receive ledger tools (add/get/list) and the parent's built-in tools, but never the spawn or handoff tools, preventing recursive nesting.
- **Ledger-aware child prompts** — child sessions are told what ledger entries exist so they can fetch knowledge on demand without the parent pre-loading bodies.
- **Child output truncation** — child results are limited to 2000 lines / 50KB to prevent runaway output from overwhelming the parent. Truncated results include an advisory message.
- **Explicit model-required error** — spawn fails immediately with a clear message when no model is configured, rather than with a cryptic runtime error.
- **No grandchildren** — children cannot spawn further children, preventing explosive branching.
- **Session lifecycle management** — children are properly cleaned up on completion, error, or parent session reset. Aborted children produce explicit `aborted` outcomes.
- **Signal-based cancellation** — spawn respects AbortSignal, allowing the parent to cancel a running child mid-flight.

#### Ledger — Sparse Continuity Cache

- **`ledger_add` tool** — save a named, compact continuity entry. Same-name writes overwrite (refinement). Writes are serialized via a process-local lock, preventing race conditions.
- **`ledger_get` tool** — retrieve a full entry body by name. Returns the current entry listing alongside the body. Reports "not found" gracefully with the complete entry list.
- **`ledger_list` tool** — list all entries with name and first-line preview. Returns empty-state placeholder when no entries exist.
- **Persistence across sessions** — ledger entries survive context resets, handoffs, and session restarts. On session start, the extension scans the session history newest-to-oldest and rehydrates the in-memory ledger from the latest epoch.
- **Ledger entry persistence via custom entries** — each `ledger_add` appends a versioned custom entry that survives compaction and session archival.
- **Epoch-based staleness** — child ledger tools reject access with a clear "invalidated by reset" error when the parent session has been reset, preventing stale writes.

#### Handoff — Deliberate Context Compaction

- **`handoff` tool** — triggers a deliberate compaction that replaces noisy context with a clean restart. The agent drafts a handoff brief preserving knowledge still missing from the ledger, then the session restarts with the brief at the top of context.
- **`/handoff` command** — user-facing shortcut that asks the agent to draft a handoff brief from a user direction, capture reusable state to the ledger, and call the handoff tool — all in one turn.
- **Rich compaction summary** — the handoff brief includes inlined ledger entries referenced in the task text (up to 3 entries, 4000 chars total), and a structured handoff primer explaining the continuation contract.
- **Clean slot handoff** — compaction replaces all pre-handoff messages with just the handoff summary. Full history remains in the session file for later reference.
- **Post-handoff auto-resume** — the agent receives a "Proceed." message after compaction completes, keeping momentum without manual re-prompt.
- **Enforcement tracking** — the `/handoff` command tracks whether the agent actually called the tool, preventing the command from being silently ignored. The watchdog cleans up stale enforcement state.

#### Primacy-Zone Watchdog

- **Advisory context-usage reminders** — a `context` hook injects a watchdog message before each LLM call when context usage exceeds 30%, 50%, or 70%. The message is advisory only — the agent decides whether to act.
- **Tiered nudge messages** — at 30-50% the agent is reminded of the primacy-zone heuristic; at 50-70% it's advised to consider handoff soon; at 70%+ it's warned that automatic compaction may trigger soon.
- **Hidden from user** — watchdog messages use a `custom` role with `display: false`, so they inform the LLM without cluttering the visible conversation.
- **`agent_end` tracking** — the watchdog records the latest context usage percent after each agent run, available for diagnostic use.

#### TUI and Status Indicators

- **Context usage in status bar** — a live `ctx 65%` indicator in the TUI status bar, color-coded: green (<30%), yellow (30-50%), orange (50-70%), red (≥70%).
- **Ledger count indicator** — a 📒 `N` badge in the status bar showing the number of ledger entries, hidden when the ledger is empty.
- **`/ledger` command** — shows all ledger entries with name, line count, and first-line preview in a TUI notification overlay.
- **Live spawn rendering** — child agent sessions render inside the parent's TUI with:
  - **Collapsed view**: model name, thinking level, real-time "last action" summary (thinking, tool execution, or assistant text preview), 5-line preview of last assistant output, and token/cost statistics.
  - **Expanded view**: full chat history with 4-space indent, streaming assistant messages, and tool execution components.
  - **Ownership lifecycle**: session ownership transfers from state to the renderer on first render, with proper cleanup on dispose, reset, or reattachment.
- **Render caching** — rendered output is cached by width/expanded/showImages, avoiding unnecessary re-renders when inputs haven't changed.
- **Graceful degradation** — the spawn renderer recovers from malformed events, missing tool definitions, subscribe failures, and null results without crashing the parent TUI.

#### Extension Wiring and Lifecycle

- **Single state object** — all primitives read/write through a single `AgenticodingState` instance, shared across extension hooks, tool executions, and the TUI renderer.
- **Session lifecycle hooks**:
  - `before_agent_start` — injects context primer and ledger listing.
  - `context` — injects watchdog reminders before LLM calls.
  - `session_start` — rehydrates ledger on continuation; resets state on `/new`.
  - `turn_end` — updates TUI indicators.
  - `agent_end` — records context usage and manages handoff enforcement.
  - `session_before_compact` — consumes pending handoff task as the compaction summary.
- **One-line install** — install via `pi install npm:pi-agenticoding` and disable platform compaction in settings.
- **Comprehensive test suite** — 50+ tests covering spawn execution and rendering (concurrency, cancellation, truncation, stale detection, ownership lifecycle, microtask batching), ledger tools (add/get/list, staleness, rehydration, empty states, prompt hints), handoff (tool, command, compaction), watchdog (nudge injection, enforcement), and extension lifecycle.
- **MIT licensed** — open-source permissive license.

[Unreleased]: https://github.com/chunkhound/pi-schematic/compare/v0.7.1...HEAD
[0.7.1]: https://github.com/chunkhound/pi-schematic/compare/v0.7.0...v0.7.1
[0.7.0]: https://github.com/chunkhound/pi-schematic/compare/v0.6.0...v0.7.0
[0.6.0]: https://github.com/chunkhound/pi-schematic/compare/v0.5.0...v0.6.0
[0.5.0]: https://github.com/chunkhound/pi-schematic/compare/v0.4.0...v0.5.0
[0.4.0]: https://github.com/chunkhound/pi-schematic/compare/v0.3.0...v0.4.0
[0.3.0]: https://github.com/chunkhound/pi-schematic/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/chunkhound/pi-schematic/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/chunkhound/pi-schematic/releases/tag/v0.1.0
