# masks Switch model and thinking level together, with optional temporary prompt tool profiles. ## Install / load This extension is loaded through the root pi-ext package. See [root README](../../README.md). ## Commands / tools / settings Commands: - `/masks` opens the fuzzy mask picker. - `/masks ` equips one mask directly. - `/masks-cancel` discards deferred masked prompts without interrupting the current run. Tools: none. Hooks: - `input` detects masked templates, equips their profiles before system-prompt construction, and defers busy follow-ups. - `turn_end` restores after successful completion; `agent_settled` restores after recovery and starts the next deferred prompt. - `session_start` reports invalid mask settings. Settings: ```json { "masks": { "pickerShortcut": "alt+m", "items": [ { "name": "sol", "model": "openai-codex/gpt-5.6-sol", "thinkingLevel": "high", "shortcut": "alt+1" } ] } } ``` `masks.pickerShortcut` is optional and defaults to `alt+m`. `masks.items` is an ordered array. Each item requires a unique `name`, a `provider/model`, and a `thinkingLevel`. `shortcut` is optional and must not collide with the picker or another mask. Thinking levels are `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`. Settings are user-only because masks describe personal model access and bindings. They are read once at load time from `~/.pi/agent/settings.json`, before any session exists. Project settings are never read, even for trusted projects. There are no flags or environment variables. Precedence: user `masks`, then the default (picker on `alt+m`, no masks). Invalid entries are skipped and each error is reported as a warning at session start; valid masks still load. A non-object `masks` value is reported and loads no masks; it never falls back to another source. Run `/reload` after changing them. Prompt templates may equip a mask for one prompt and its tool loop: ```markdown --- description: Review this change mask: terra tools: [read, grep, find, ls] --- Review the current change. ``` `mask` must exactly match a configured mask name. `tools` is optional and applies only to masked templates. When present, it must be a nonempty array of unique, nonempty names registered when the prompt dispatches. Invalid or unknown names reject the prompt before model, thinking, or tools change. The mask and optional tool profile last through tool calls, automatic retries, and continuing compaction, then restore before the next ordinary follow-up. A tool profile replaces the active set for the run and restores the exact pre-prompt set; tool activation during that run is temporary. Omitting `tools` leaves tool state untouched. Failed profile switches abort the prompt and roll back every changed component. Failed restoration blocks later prompts until restoration succeeds. Busy masked follow-ups use an extension-owned FIFO queue, shown in the footer. They run after Pi's native queue drains, not in mixed submission order. Templates and masks are resolved at execution; attached images are preserved. Steering a masked template is rejected because it would change the current run's model. Abort, error, tree navigation, and session shutdown discard deferred prompts. Pi's native queue editor does not manage this queue; use `/masks-cancel`. Pi provides no dispatch acknowledgement: prompt expansion failures can lose a prompt and stall the remaining queue. Concurrent input during masked preparation is rejected instead of risking the wrong model. If dispatch fails during preparation, `/reload` clears the reservation and deferred queue. ## Behavior The picker fuzzy-matches mask names, models, thinking levels, and shortcuts. Without a query, it shows every configured mask in settings order. A mask changes the model first, then applies its thinking level. Missing models or credentials leave the thinking level unchanged and report an error. Successful switches add no status because Pi's existing footer shows model and thinking. ## Debug Opt in through [debug contract](../DEBUG.md). Safe events: `session.start`, `session.shutdown`, `mask.apply.start`, `mask.apply.finish`, `mask.apply.error`.