@axnic/pi-extension-settings

Centralized settings panel for pi extensions.

Package details

extension

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

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 accessorsExtensionSettings<S> exposes get(), set(), onChange(), and getAll(), 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 via v.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 packages list 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.
  • enter on a section header — scope the view to that extension only; esc to 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.theme is the key theme inside the appearance section). Use kebab-case for multi-word keys (api-url, font-size).

Use a stable extension identifier — the string passed as the second argument to ExtensionSettings is your storage namespace. Renaming it strands previously saved values.

Do not store secrets~/.pi/agent/settings.json is plain text. Use environment variables or a system keychain for API keys and tokens.

Keep descriptions short — the 128-character limit on description is enforced at schema construction time (S.settings() throws DescriptionTooLongError immediately). If you provide a documentation field, it must be at least 64 characters (throws DocumentationTooShortError); for anything shorter, omit it and rely on the inline description alone.

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:settings slash 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, the ExtensionSettings accessor, 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.