singularity-forge/docs/dev/extending-pi/26-extension-template.md

2.2 KiB

Extension Development Template

Use this template for small repo-local extensions before adding packaging, dependencies, or distribution metadata.

Directory Layout

~/.sf/agent/extensions/my-extension/
├── index.ts
├── extension-manifest.json
└── README.md

For source-tree development inside this repository, place bundled extensions under src/resources/extensions/<extension-id>/ and keep tests next to the extension's existing test conventions.

extension-manifest.json

{
	"id": "my-extension",
	"name": "My Extension",
	"version": "0.1.0",
	"description": "Adds one focused command or tool.",
	"tier": "project",
	"entry": "index.ts",
	"provides": {
		"tools": ["my_tool"],
		"commands": ["/my-command"],
		"hooks": []
	},
	"dependencies": {
		"extensions": [],
		"runtime": []
	}
}

index.ts

import { Type } from "@sinclair/typebox";
import type {
	ExtensionAPI,
	ExtensionContext,
} from "@mariozechner/pi-coding-agent";

/**
 * Register the extension's command and tool.
 *
 * Purpose: expose one project-specific operation through a typed tool and a
 * human-triggered command.
 *
 * Consumer: SF runtime extension loader.
 */
export default function activate(pi: ExtensionAPI, ctx: ExtensionContext) {
	pi.registerTool({
		name: "my_tool",
		description: "Return a concise project-specific status.",
		parameters: Type.Object({
			label: Type.String({ description: "Status label to display." }),
		}),
		async execute({ label }) {
			return { ok: true, label };
		},
	});

	pi.registerCommand("my-command", {
		description: "Show the current extension status.",
		async run() {
			ctx.ui.notify("My extension is loaded.", "info");
		},
	});
}

Review Checklist

  • The extension has one clear purpose and a named production consumer.
  • Every tool parameter has a TypeBox schema.
  • Persistent state is written under the project .sf/ tree or the managed agent directory, not arbitrary home-directory paths.
  • Commands and tools degrade with useful messages when dependencies are missing.
  • Tests cover the behavior contract, not only mocks or call counts.
  • User-facing environment variables are added to src/env.ts and docs/user-docs/configuration.md.