@zigai/pi-extension-settings
v0.4.1
Published
TypeBox-first configuration runtime and artifact tooling for Pi extensions.
Maintainers
Readme
Pi Extension Settings
Persistent, typed settings for Pi extensions.
Define one TypeBox schema and this package uses it for defaults, runtime validation, config.schema.json, and generated documentation. An optional example settings layer can demonstrate a realistic non-default setup in the README.
The runtime API consists of:
defineExtensionSettings()for defining settings.loadPiExtensionSettings()for loading defaults, global settings, and trusted project overrides.updatePiExtensionSettings()for validated, conflict-aware global or project updates.getPiGlobalSettingsPath()andgetPiProjectSettingsPath()for locating settings files.
Recommended: use the template
For the easiest setup, use pi-extension-template, which has extension settings built in.
If you do not want to use the template, or you want to add settings to an existing extension, follow the manual setup below.
Manual setup
Install
Install @zigai/pi-extension-settings:
npm install @zigai/pi-extension-settingsDefine and load settings
import { defineExtensionSettings } from "@zigai/pi-extension-settings";
import { loadPiExtensionSettings, type PiSettingsContext } from "@zigai/pi-extension-settings/pi";
import { Type } from "typebox";
export const settingsDefinition = defineExtensionSettings({
id: "pi-example",
title: "Pi Example",
description: "Settings for Pi Example.",
schemaId: "https://raw.githubusercontent.com/zigai/pi-example/main/config.schema.json",
schema: Type.Object(
{
enabled: Type.Boolean({
default: true,
description: "Enable the extension.",
"x-control": "switch",
}),
excludedTools: Type.Array(Type.String(), {
default: [],
description: "Tool names the extension should ignore.",
}),
},
{ additionalProperties: false },
),
exampleSettings: {
excludedTools: ["bash", "write"],
},
});
export function loadExampleSettings(ctx: PiSettingsContext) {
return loadPiExtensionSettings(settingsDefinition, ctx, {
bundledSchema: { kind: "url", url: new URL("../config.schema.json", import.meta.url) },
});
}
export default settingsDefinition;exampleSettings is optional. Add it only when complex settings need an Advanced example alongside the generated Defaults.
Update settings transactionally
Use updatePiExtensionSettings() to change the latest global or project settings layer. It handles
locking, validation, and atomic writes. Load settings first to install and verify the schema.
import { updatePiExtensionSettings } from "@zigai/pi-extension-settings/pi";
const result = await updatePiExtensionSettings(settingsDefinition, ctx, {
scope: "global",
update: (current) => ({ ...current, enabled: false }),
});
if (result.status !== "updated" && result.status !== "unchanged") {
ctx.ui.notify(result.message, "error");
}The callback receives the latest encoded layer. Invalid files or updates are left untouched, and project updates require a trusted project.
To detect stale editor snapshots, pass the loaded globalRevision or projectRevision as
expectedRevision; a mismatch returns conflict. Omit it to always update the latest valid layer.
Optional TUI control hints
TypeBox preserves custom JSON Schema annotations in the generated schema. Extension authors can use
the optional x-control keyword to tell compatible settings editors how a property should be
presented when its ordinary JSON Schema shape is ambiguous. The annotation does not change runtime
validation, defaults, or loading behavior.
Pi Settings UI recognizes these values:
| x-control | Compatible schema | TUI behavior |
| ------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| text | string | Single-line inline input. |
| textarea | string | Pi's multiline editor. |
| switch | boolean | Boolean toggle. |
| segmented | primitive choices | Compact choice changed with Left and Right. |
| select | primitive choices | Searchable choice picker. |
| slider | number or integer | Compact range bar with stepping and exact-number entry. Schema bounds and multipleOf refine its range and step. |
| numeric | number or integer | Single-line numeric input. |
| color | string | Single-line color input with a live swatch for hexadecimal colors. |
| path | string | Single-line path input with Tab completion. |
| combobox | string or string-only union | Searchable suggestions from string examples or finite string branches, plus a custom schema-validated value. |
| json-editor | any property schema | Full validated JSON editor instead of a shape-derived control. |
Pass the annotation as a quoted TypeBox option:
const schema = Type.Object({
prompt: Type.String({ "x-control": "textarea" }),
root: Type.String({ "x-control": "path" }),
limit: Type.Integer({ minimum: 1, maximum: 20, "x-control": "slider" }),
color: Type.String({
"x-control": "combobox",
examples: ["accent", "warning"],
}),
});Generate the schema and documentation
Add the settings definition and commands to package.json:
{
"piExtensionSettings": {
"definition": "./src/settings.ts",
"schema": "./config.schema.json",
"readme": "./README.md"
},
"scripts": {
"config:generate": "pi-extension-settings generate",
"config:check": "pi-extension-settings check"
}
}Then run:
npm run config:generate
npm run config:checkgenerate writes config.schema.json and adds or updates the generated configuration section in the README.
check verifies that both artifacts are up to date without changing files, making it suitable for pre-commit and CI.
