# Persistence, permissions, and UI internals

[← README](../README.md)

## Persistence and model context

One versioned collection stores records, the current attachment, and the allocation high-water mark; no duplicate current-plan or execution mirrors are saved. Meaningful transitions save a snapshot once; identical snapshots, reads, lists, and ordinary model requests do not. Restoration retains completed, abandoned, and transferred records, unsaved metadata/outcomes, and step progress. Old detached records from the former multi-plan workflow remain untouched as hidden inert history: they are not listed, counted, resumed, selected, or migrated. Malformed modern state is reported and disables mutations instead of falling back to partial data. Persisted tool snapshots are historical data, not runtime authority: each tool refresh derives the unmanaged base from Pi's live active set so another extension's additions and removals survive.

Reload/tree navigation restores branch state while allocation honors the session-wide high-water mark and existing files. Forks copy tracked files to child paths without overwriting source files. Fresh implementation transfers **only the current approved plan**, not historical records or planning conversation. Pi starts the replacement extension before `newSession.setup` appends its state, so the first kickoff request adopts the pending fresh snapshot before building context. Destination state is persisted first; the closed source session is then reopened through `SessionManager` only to append a terminal transferred snapshot, without reusing stale extension APIs. That same atomic state entry carries the one durable source-transfer notice; its renderer uses `success`, while ordinary state entries remain invisible and outside model context.

The `context` hook refreshes one current mode/task block before each model request. Because Pi converts custom messages to user-role messages, this background block is placed before the latest actual user request (or at the beginning if none remains), never after its tool results. It requires no acknowledgment. Obsolete extension-owned reminders are filtered from outgoing context without deleting transcript history. Build with no current plan receives none. Current contexts include outcome facts and, when applicable, executable-step or execution-waiting restrictions. Awaiting-validation context includes the exact required user action until it is resolved; in Build it also retains compact task-boundary and tracked-Markdown guidance without granting paused step work. File facts refresh at restoration, current selection, canonical edit/write results, and user-run boundaries; action-time safety checks do not rely on display caches.

## Presentation and UI compatibility

The rounded composer uses the current theme’s `warning` color in Plan and `thinkingLow` in Build on the top-left border and continuous solid `│` left rail. The right rail uses Pi’s border color. The unfinished attached task’s title preserves its capitalization and sits centered in the top border, with the mode-colored dashes split into balanced runs on either side (the extra dash goes on the right); mode, model, provider, and thinking level sit in the bottom border. Text truncates to terminal width. Model/thinking changes update the display live.

User-visible text follows one semantic color contract. Text that asks the user to act uses the theme’s `accent` color in bold through one shared helper: the awaiting-validation heading, step-kickoff guidance, cancelled-question notice, `stay`/`step-by-step` mode announcements, and step-control clauses that await instruction or approval. `success` marks confirmed state changes; `muted` marks pending activity, no-ops, inventory, paths and other bookkeeping, and legacy or unknown renderer details; `warning` marks cautions and degraded or unfinished states; and `error` marks failures. Mixed tool results style each clause separately—for example, a completed-step clause is `success` while its following wait-for-instruction clause is bold `accent`. Explanatory prose and user-provided content remain ordinary text.

After one empty line, the awaiting-validation instruction body uses regular-color Markdown, so it can wrap naturally and present multiple checks as bullets without turning a paragraph into an accent block. The heading and body use Pi's standard one-column transcript inset, and list markers keep the normal conversation `mdListBullet` styling. Bold keeps action cues legible when a theme places `accent` near body text. `/plan show`, `/plan history`, plan reviews, and completion summaries remain plain Markdown reports. Composer mode chrome, transcript rails, and panel state markers retain their dedicated mode/status colors. TUI/RPC notifications use Pi's available `info`, `warning`, and `error` levels: successful and neutral notices use `info`, cautions use `warning`, and failures use `error` because notifications do not expose `success` or `accent` levels.

When enabled, titles stay through mode changes and execution pauses, disappear on completion/abandonment, and change only when the task identity changes. Validation notices belong in the main chat, never in the composer title or border. Metadata takes precedence over the first nonempty top-level Markdown heading outside fenced code. An existing unfinished file without a title displays `Untitled task`; empty reservations do not. No scope is inferred from the display fallback.

Submitted user messages retain their original mode-colored rail after mode changes and session restoration. Recreated custom editors restore the latest 100 active-branch user prompts for Up/Down history. Pi Plan Build leaves the footer untouched; its keyed status is a fallback when another extension owns the composer.

Compatible editor decorators may invoke Plan Build’s editor factory and retain its composer. A preexisting editor, non-composing replacement, or competing fullscreen layout triggers one warning and reduced optional UI rather than replacing the other owner. Core modes, tools, shortcuts, and restored step progress remain available. Teardown restores only UI slots still owned by Plan Build.

The guarded transcript-rail integration decorates Pi's exported `UserMessageComponent` because no built-in user-message renderer hook exists.

The step-panel layout uses public fullscreen primitives plus a guarded read of the runtime layout root, since Pi's API currently exposes a setter but no getter. Ownership is checked before installation and teardown.

## Outcome reconciliation

A normal saved-plan Build run can receive **one** hidden outcome-reconciliation reminder after approved implementation or a successful project edit/write. It requires a normal terminal response and no recorded outcome. Errors, interruptions, pending input, work without a current plan, conversation-only turns, Plan, and step execution do not trigger it. The reminder authorizes no more implementation/tests and infers no success. Its instruction is visible only during its live bookkeeping follow-up, including the final response after recording an outcome. It expires when that follow-up settles, when a new user message arrives, or when the plan/mode changes; restoration never reactivates it. Its consumed marker is saved before dispatch, preventing replay across restoration; ignoring it leaves the plan unfinished without looping. Shell-only work outside approval may not arm it, so explicit agent finishing remains the primary contract.

Tool output stays compact and preserves errors even during partial output. Expanded inventory and Markdown completion summaries retain specialized rendering. A newly recorded `awaiting_validation` outcome also sets one transient in-memory signal. At the next eligible `agent_settled`, Plan Build consumes that signal before showing the standard completion selection, so later settles and restored sessions cannot replay it. The durable outcome and transcript notice remain the authority if the user stays in Build or cancels. Before applying completion, the handler rechecks the attached sequence, validation action, active step identity, and whether that step still represents intermediate or final execution; stale selections warn and do nothing. Ordinary and final-step prompts use plan-completion wording, while intermediate steps use current-step wording. Ordinary completion reuses the whole-plan transition, while step completion reuses the paused validated-step transition and never starts the next step. TUI reads the action from the preceding notice, while RPC receives it in the selection title. Interactive `question` supports structured choices and custom answers when the optional `questionTool` setting is enabled; its registration and active-tool injection are skipped when that setting is off, while the cancelled-question entry renderer stays registered so restored notices keep rendering. Hidden model guidance is hidden in the normal UI, not inaccessible through session/API data.

## Permission boundary

Plan guidance allows only observation, analysis, discussion, and planning. Plan Build recognizes `edit`, `write`, `replace`, `insert`, and `undo_last_change` as file mutators. Calls with a path may target **only the attached canonical plan path**, and only finalization or explicitly requested revision is appropriate. A recognized editor without a visible path is blocked because Plan Build cannot resolve private anchor state. Other tools remain visible for exploration. Bash/powershell are not sandboxed in ordinary Plan mode: the read-only requirement is model guidance, not arbitrary shell classification.

Mode refreshes manage only Plan Build's own lifecycle/question tools. The current live host set remains authoritative, so Plan Build neither force-enables built-in editors nor resurrects tools another extension removed.

Build keeps tracked Markdown read-only when a recognized editor supplies its target; completion and post-approval scope metadata belong in extension state. A successful task mutation that changes stored scope removes any previous unfinished outcome and refreshes active lifecycle tools, while title-only updates, discussion decisions, and no-ops preserve it. Paused execution remains paused. Path guards normalize Pi path forms (including `@` and `~`) and resolve filesystem symlink aliases, including existing parents of new files. Unresolvable targets fail closed. Pathless editors such as hashline `replace`/`insert` in their default anchor-only configuration remain usable during ordinary approved Build work, but their target cannot be preflighted by this extension. Pi currently exposes neither mutation metadata nor a target resolver on `ToolDefinition`, so unknown tools and private extension state remain outside this boundary. These guards are not an arbitrary-tool or shell sandbox and do not protect against adversarial extension code or filesystem races. Extension-controlled revisions of unimplemented step instructions remain supported and share Pi’s file-mutation queue.

Recognized mutators, including pathless hashline editors, do fail closed when plan state is unusable, a `plan_task` transition has not settled, or step execution awaits instruction. Successful recognized file-mutation results also participate in outcome reconciliation; opaque successful edits conservatively count as project work and refresh plan-derived display state.

See [Workflow](workflow.md) for approval, validation, RPC review, and step-execution behavior. See [Settings](settings.md) for user configuration.
