A small collection of pi extensions bundled as one pi package. It fixes four everyday annoyances when you use pi with a mixed model set:
- Pi forgets your model. Every new session starts on whatever is in
settings.json, so you re-pick by hand. → remember-model remembers the model you last selected and restores it next session. - OpenRouter routes to a random upstream provider. The same model id can be served by backends with different speed/quality/price. → openrouter-lock-provider pins a model to the upstream provider you choose.
- You accidentally chat with the wrong model. A stray Ctrl+P or
/modelcan send a prompt to a costly or weak model. → model-preference-guard warns and asks for confirmation before a prompt leaves for a model outside your allow-list. - Delegating a focused task means polluting your context or juggling another
terminal. → subagent runs a task in an isolated
piprocess on a named profile (its own model), then folds the captured conversation into your session, expandable with Ctrl+O and abortable with Esc.
All features share one settings file and all commands are prefixed with pt-.
# from npm (once published)
pi install npm:@liyu1981/pi-tweaks
pi install npm:@liyu1981/pi-tweaks@0.1.0 # pinned
# from GitHub
pi install git:github.com/liyu1981/pi-tweaksTry it without installing:
pi -e npm:@liyu1981/pi-tweaks
pi -e git:github.com/liyu1981/pi-tweaksSeveral commands open interactive pickers, styled like pi's own /model picker.
Used by /pt-model-guard-pref (no args, or add / remove).
| Key | Action |
|---|---|
| type | substring-filter on provider/model |
| ↑ / ↓ | move cursor |
| Space | toggle highlighted model (and advance) |
a / n |
select all / none (only while the search box is empty) |
| Enter | confirm selection |
| Esc | clear search, or cancel if search is already empty |
☑checked,☐unchecked; models without a configured API key show⚠ no key.- Checked models sort first, then keyed models, then alphabetically; 20 rows are visible at a time with a scroll indicator.
Used by /pt-openrouter-lock-provider with no arguments.
| Key | Action |
|---|---|
| type | filter model ids |
| ↑ / ↓ | move cursor |
| Backspace | delete a search character |
| Esc | clear search, or cancel if empty |
| Enter | pick the highlighted model |
After picking, a one-line text prompt asks for the provider slug (empty clears the lock).
Opened by /pt-subagent (and shown before the task prompt when you run
/pt-subagent <text>).
| Key | Action |
|---|---|
| ↑ / ↓ | move cursor |
| Enter | open the task prompt phase for the highlighted profile |
e |
edit the highlighted profile (name, then model picker) |
a |
add a profile (asks for a name, then opens the model picker) |
d |
delete the highlighted profile (with confirmation) |
| Esc | close |
Each row shows name and its provider/model, with :provider appended when
an OpenRouter provider lock is set.
Shown after choosing a profile. It lists the profile and the system prompt the subagent will receive, then gives you a multi-line editor for the task.
| Key | Action |
|---|---|
| Enter | run the task |
| Ctrl+J / Shift+Enter | insert a newline |
| Esc | back to the profile list |
model-preference-guard uses pi's standard Yes/No confirm before sending a
prompt to a non-allow-listed model; declining cancels the send.
| Command | Description |
|---|---|
/pt-remember-model [status|on|off|clear] |
Remember and restore the last selected model. |
/pt-openrouter-lock-provider [<provider>|clear|list|on|off] |
Manage OpenRouter provider locks. No argument opens a TUI picker. |
/pt-model-guard-pref [list|on|off|toggle|add|remove] |
Manage the allowed-model list. No argument opens a multi-select picker. |
/pt-subagent [\-p <profile> [prompt]] |
No argument: profile list → task prompt. With -p <profile>: run directly (or open the task prompt if no prompt given). Otherwise the text is the task prompt; the profile list opens first. |
Every feature has an on/off switch and defaults to on. Turning off
openrouter-lock-provider also stops remember-model from appending the
:<provider> suffix to the default model.
Everything is stored in one file:
~/.pi/agent/pi-tweaks-settings.json
Missing sections are filled with defaults on load. Writes are serialized and atomic, so the extensions can safely update the file concurrently.
On every model selection it saves the model to rememberModel.last and writes defaultProvider / defaultModel into pi's own settings.json. On new / startup sessions it restores that model. Toggle with /pt-remember-model on|off; forget the saved model with /pt-remember-model clear.
If the model is an OpenRouter model with a provider lock, the model written to pi's settings uses a :<provider> suffix, e.g. deepseek/deepseek-v4.1-flash:deepseek. pi's resolver does not understand that suffix, so the extension restores the base model itself at session start.
OpenRouter routes a model across several upstream providers. A lock pins one:
/pt-openrouter-lock-provider deepseek
/pt-openrouter-lock-provider clear
/pt-openrouter-lock-provider listAt request time the extension sets OpenRouter's provider.order to your locked provider and strips the :<provider> suffix so OpenRouter never sees it. Disable the whole feature with /pt-openrouter-lock-provider off; while off, remember-model writes the plain base model id (no suffix) and no routing is applied.
Maintain an allow-list of preferred provider/model combinations. When you type a prompt with a model outside the list, pi asks for confirmation first. With an empty list the guard allows everything. Disable temporarily with /pt-model-guard-pref toggle.
Define named profiles (name + provider/model) with /pt-subagent. Running
it without arguments opens the profile list; press Enter to move to the task
prompt phase, which shows the chosen profile and its system prompt and gives
you a multi-line editor (Enter runs, Ctrl+J adds a newline, Esc goes back).
/pt-subagent -p scout summarize the README runs that profile directly, and
/pt-subagent summarize the README opens the profile list first with the task
pre-filled. A run spawns an isolated pi --mode json process on the chosen
profile, streams its tool calls and output live, and stores the captured
conversation in the transcript as a foldable entry (Ctrl+O to expand, Esc to
abort).
The subagent conversation is display-only: it never enters your parent session's
LLM context. OpenRouter provider locks apply automatically — the profile's base
model id is turned into the <model>:<provider> variant for the child, whose
openrouter-lock-provider handler strips the suffix and sets
OpenRouter's provider.order.
The child mirrors the parent's project-trust decision (--approve /
--no-approve). This matters because project system-prompt files
(.pi/SYSTEM.md, .pi/APPEND_SYSTEM.md), project settings, extensions and
skills are trust-gated: without --approve a non-interactive child would
silently drop them even though your interactive session loaded them. The child
is also given an explicit system-prompt preamble stating its working directory
and instructing it to follow the project instructions (AGENTS.md,
AGENTS.override.md, or CLAUDE.md) — reading them first if they are not
already in context.
No build step: pi loads TypeScript directly via jiti.
npm install # once, for the type-checker and dev deps
npm run check # tsc --noEmitLoads this working tree as a package for a single run. Edits are picked up on the next run.
npm run dev # pi -e .
npm run dev -- --model openrouter/deepseek/deepseek-v4.1-flash
# or directly
pi -e .Installs this directory into pi's settings as a local package. The path is referenced, not copied, so pi keeps loading the current working tree — including uncommitted changes — until you remove it. This is the way to test the latest code before pushing to GitHub or publishing to npm.
npm run install:local # pi install .
npm run uninstall:local # pi remove .After installing, restart pi (or run /reload in the TUI) to pick up edits.
Avoid duplicate handlers. If you previously loaded the standalone files, remove them before installing this package, otherwise both sets run:
rm ~/.pi/agent/extensions/pt-remember-model.ts rm ~/.pi/agent/extensions/pt-model-guard.ts
npm run check # tsc --noEmit
npm run pack:check # npm pack --dry-run: shows exactly which files would shipThe package is published publicly to the @liyu1981 scope
(publishConfig.access: "public"), so a plain publish works:
npm version patch # or minor / major
npm publish # prepublishOnly runs `npm run check` first
git push --follow-tagsMIT © Yu Li
{ "version": 1, // /pt-remember-model "rememberModel": { "enabled": true, "last": { "provider": "openrouter", "modelId": "deepseek/deepseek-v4.1-flash" } }, // /pt-model-guard-pref "modelGuard": { "enabled": true, "allowedModels": [ { "provider": "openrouter", "model": "deepseek/deepseek-v4.1-flash" } ] }, // /pt-openrouter-lock-provider (base model id -> upstream provider slug) "openrouterModelProviderPref": { "enabled": true, "locks": { "deepseek/deepseek-v4.1-flash": "deepseek" } }, // /pt-subagent (named profiles; OpenRouter locks applied at run time) "subagent": { "profiles": [ { "name": "scout", "provider": "openrouter", "model": "deepseek/deepseek-v4.1-flash" } ] } }