npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@axnic/pi-extension-settings

v0.2.0

Published

Centralized settings panel for pi extensions.

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/[email protected]

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.