@axnic/pi-extension-settings
Centralized settings panel for pi extensions.
Package details
Install @axnic/pi-extension-settings from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@axnic/pi-extension-settings- Package
@axnic/pi-extension-settings- Version
0.2.0- Published
- Apr 23, 2026
- Downloads
- 2,204/mo · 361/wk
- Author
- anicolaie
- License
- Apache-2.0
- Types
- extension
- Size
- 6.7 MB
- Dependencies
- 4 dependencies · 0 peers
Pi manifest JSON
{
"extensions": [
"./dist/index.js"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
- Why
- Features
- Install
- UI — the settings panel
- For extension authors
- Documentation
- Project layout
- Contributing
- License
Why
Every pi extension eventually needs settings. Without a shared framework, each one re-invents storage, validation, UI, and change listeners — and the TypeScript types drift from the on-disk format over time.
pi-extension-settings solves this once. You declare a schema; the framework gives you typed accessors, validation, a rendered TUI panel, and live change events.
No UI code. No custom storage. No hand-rolled types.
Features
For users
- Unified settings panel — Browse and edit settings from all installed extensions in one place. Open it with
/extensions:settings. - Keyboard-first — Navigate, search, inline-edit, reorder, and delete without leaving the keyboard.
- Live save — Every confirmed edit persists immediately, and other extensions react in real time.
For extension authors
- Type-safe accessors —
ExtensionSettings<S>exposesget(),set(),onChange(), andgetAll(), all inferred from your schema at compile time. - Declarative schema builders — One call to
S.settings({...})covers defaults, validation, transforms, autocompletion, and display format — per setting. - Rich node types — Text, Number, Boolean, Enum, List (structured rows), Dict (key/value maps), and nestable Sections.
- 43 built-in hooks — validators (
v.*), transforms (t.*), completers (c.*), and display functions (d.*), composable viav.all/v.any/t.pipe/t.compose, and more.
Install
Run one of the following from inside pi:
pi install npm:@alnic/pi-extension-settings # recommended
pi install git:github.com/xunleii/pi-extension-settings@v0.0.1
Note — The order of extensions in your
packageslist does not matter; pi resolves dependencies automatically.
Warning — The
git:install method has not been fully tested. Extensions that depend on this SDK require the npm package at runtime; the git install may not satisfy that requirement correctly.
Restart pi. The extension registers the /extensions:settings slash command on startup.
UI — the settings panel
Open the panel with:
/extensions:settings
The panel aggregates settings from every registered extension into a single tree view.
Layout and navigation
─────────────────────────────────────────────────────────────────────────────
>
→[-] pi-extension-settings
├ [-] behavior
│ └ start-in-search-mode false •
└ [-] controls
├ reset-to-default r
├ collapse-expand space
├ collapse-all shift + space
├ reorder-item-up shift + up
├ reorder-item-down shift + down
└ delete-item d
[-] pi-welcome
├ gradient-from ■ #ff930f
├ gradient-to ■ #fff95b
└ tips 5 items configured
(10 settings · 2 sections)
[extension] pi-extension-settings (7 settings)
<space> collapse/expand · <enter> to enter section · </> search · <esc> cancel · <shift+space> collapse all
→marks the current cursor position; use↑/↓to move.•next to a value means it differs from the schema default (modified).space— collapse or expand a section.enteron a section header — scope the view to that extension only;escto return./— open search; results filter and highlight as you type.r— reset the selected setting to its default.d— delete an item from a list or dict.
Inline validation
Editors validate on every keystroke. A failing validation blocks the save and shows the reason inline:
→ api-url https://not a url█
✖ must be a valid URL
A passing edit saves immediately on enter and the cursor returns to the tree.
A short asciinema demo showing navigation, inline editing, and list operations will be available in docs/ once recorded.
For extension authors
Getting started
Add pi-extension-settings as a peer dependency in your package.json — it is provided at runtime by the installed extension, but you need it locally for types and SDK imports during development:
{
"peerDependencies": {
"pi-extension-settings": "*"
},
"devDependencies": {
"pi-extension-settings": "*"
}
}
Then declare a schema and instantiate ExtensionSettings:
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { ExtensionSettings, S, v, t } from "pi-extension-settings/sdk";
const schema = S.settings({
"api-url": S.text({
description: "API base URL",
default: "https://api.example.com",
validation: v.url(true),
transform: t.normalizeUrl(),
}),
theme: S.enum({
description: "Color theme",
default: "dark",
values: ["dark", "light", "system"],
}),
enabled: S.boolean({
description: "Enable extension",
default: true,
}),
});
export default function myExtension(pi: ExtensionAPI) {
const settings = new ExtensionSettings(pi, "my-extension", schema);
// Fully typed reads — type inferred from the schema.
const url = settings.get("api-url"); // string
const on = settings.get("enabled"); // boolean
// Fully typed write — transform runs before save.
settings.set("theme", "light");
// React to user edits made from the panel (or programmatic set() calls).
settings.onChange("theme", (next) => applyTheme(next));
}
The settings panel UI is generated from your schema automatically — no UI code required.
Guidelines
Keys must not contain
.— dots are reserved for section path separators (e.g.appearance.themeis the keythemeinside theappearancesection). Use kebab-case for multi-word keys (api-url,font-size).
Use a stable extension identifier — the string passed as the second argument to
ExtensionSettingsis your storage namespace. Renaming it strands previously saved values.
Do not store secrets —
~/.pi/agent/settings.jsonis plain text. Use environment variables or a system keychain for API keys and tokens.
Keep descriptions short — the 128-character limit on
descriptionis enforced at schema construction time (S.settings()throwsDescriptionTooLongErrorimmediately). If you provide adocumentationfield, it must be at least 64 characters (throwsDocumentationTooShortError); for anything shorter, omit it and rely on the inlinedescriptionalone.
Further reading
The SDK documentation covers everything else in depth:
| Topic | Page |
|---|---|
| Full Getting Started walkthrough | sdk/docs/getting-started.md |
All node types (S.*) |
sdk/docs/concepts/schema-builder.md |
Lifecycle, get / set / onChange / getAll |
sdk/docs/concepts/extension-settings.md |
All 43 hooks (v.*, t.*, c.*, d.*) |
sdk/docs/hooks/README.md |
| Progressive examples (weather widget → AI assistant) | sdk/docs/examples/README.md |
| Full API reference | sdk/docs/reference/api.md |
Documentation
| Resource | Audience | What's inside |
|---|---|---|
| SDK guide | Extension authors | Getting started, concepts, hooks, and the full API reference |
| SDK examples | Extension authors | Three progressive examples: weather widget → code formatter → AI assistant |
| API reference | Extension authors | Every exported symbol with its signature |
| Hooks reference | Extension authors | All 43 validators, transforms, completers, and display functions |
| Design spec | Contributors | Panel architecture, mockups, and behavior specs |
| Schema analysis | Contributors | Runtime schema introspection API |
| SDK internals | Contributors | Event protocol, registry, storage layer |
Project layout
pi-extension-settings/
├── index.ts Extension entry point (command + event wiring)
├── sdk/
│ ├── index.ts Public SDK surface
│ ├── docs/ Full SDK documentation
│ ├── examples/ Runnable example extensions
│ └── src/
│ ├── core/ Schema, ExtensionSettings, nodes, errors
│ └── hooks/ 43 hook implementations
├── src/
│ ├── settings.ts Own-settings schema (dog-fooding the SDK)
│ ├── core/ Registry and storage
│ └── ui/ Panel, model, renderer, input, state
└── docs/ Banner, design spec, SDK internals
The repository is split into two distinct layers:
- Extension (
index.ts,src/) — the pi extension itself. It registers the/extensions:settingsslash command, owns the TUI panel, and manages the central registry that aggregates schemas from all participating extensions. - SDK (
sdk/) — the public library that other extensions import. It is completely independent of the panel; it exposes the schema builders, theExtensionSettingsaccessor, and all 43 hooks. The SDK communicates with the extension at runtime via pi's event bus.
This separation means you can use the SDK in your extension without caring about how the panel is implemented — and the panel can evolve without breaking the SDK's public API.
Contributing
See CONTRIBUTING.md for local setup, how to register the extension with pi during development, and how to run the tests.
License
Apache 2.0 — see LICENSE.
This project was vibe-coded with AI assistance (Claude, GPT-5, Gemmini) and reviewed by the maintainer before publishing.
