| name | new-package |
| description | Create a new Pi package in the pi-userland monorepo. Use this skill whenever the user mentions adding, scaffolding,
or creating a new package, extension, or module — even if they don't explicitly say 'new package.' Also trigger when
the user discusses pi-userland, monorepo setup, or needs boilerplate for a Pi extension. Always ask for confirmation
before running commands.
|
Pi userland new package scaffolding
When to use
- User wants to add a new package to the pi-userland monorepo
- User asks to scaffold a new Pi extension
- User mentions "new package", "add package", or discusses pi-userland/monorepo setup
- User needs boilerplate for a Pi extension
Before you start
- Confirm the package name follows the pattern:
pi-* (lowercase, hyphenated)
- Identify the basename — the package name without the
pi- prefix. For pi-session-hygiene, the basename is session-hygiene.
Quick start
- Ask for the package name (e.g.,
pi-session-hygiene, pi-spinner-verbs)
- Confirm the name follows pattern:
pi-* (lowercase, hyphenated)
- Ask for a package description
- Create the package directory and files using the commands below
Package structure
packages/<name>/
├── extensions/
│ └── <basename>/
│ └── index.ts # Extension entry point
├── __tests__/ # Test files
├── package.json
├── README.md
└── tsconfig.json # Minimalist, relies on base config, no build
Where <basename> is <name> without the pi- prefix (e.g., session-hygiene for package pi-session-hygiene).
Commands to run
BASENAME="${NAME#pi-}"
mkdir -p packages/$NAME/extensions/$BASENAME
mkdir -p packages/$NAME/__tests__
package.json template
{
"name": "@robhowley/<name>",
"version": "0.1.0",
"type": "module",
"description": "<package_description>",
"files": [
"extensions",
"<optional-subdir>",
"README.md",
"../LICENSE"
],
"publishConfig": {
"access": "public"
},
"keywords": ["pi-package", "pi-userland"],
"pi": {
"extensions": ["./extensions/<basename>"]
},
"repository": {
"type": "git",
"url": "https://github.com/robhowley/pi-userland.git",
"directory": "packages/<name>"
},
"homepage": "https://pi-userland.dev",
"scripts": {
"lint": "eslint extensions/",
"format:check": "prettier --check extensions/",
"format:write": "prettier --write extensions/",
"typecheck": "tsc --noEmit",
"test": "vitest run __tests__"
},
"license": "MIT",
"peerDependencies": {
"@earendil-works/pi-ai": "*",
"@earendil-works/pi-coding-agent": "*"
},
"devDependencies": {
"@types/node": "^22.15.17"
}
}
Extension template (extensions//index.ts)
import type { ExtensionAPI, ExtensionContext } from '@mariozechner/pi-coding-agent';
export default function (pi: ExtensionAPI) {
pi.on('session_start', async (_event, ctx) => {
ctx.ui.notify('Extension loaded', 'info');
});
}
README template
# <name>
Brief description of what this package does.
## Installation
```shell
pi install npm:@robhowley/<name>
## Example workflow
**Input:** "Add a new package called pi-session-hygiene"
**Process:**
1. Package name: `pi-session-hygiene` ✓ (follows `pi-*` pattern)
2. Basename: `session-hygiene`
3. Run scaffolding commands with `$NAME=pi-session-hygiene`, `$BASENAME=session-hygiene`
**Resulting structure:**
packages/pi-session-hygiene/
├── extensions/
│ └── session-hygiene/
│ └── index.ts
├── tests/
├── package.json # name: @robhowley/pi-session-hygiene
├── README.md
└── tsconfig.json
After creating the package:
1. Update `.github/release-please-config.json` to include the new package
2. Update `.github/release-please-manifest.json` with initial version
3. Update repo level `README.md` to list the new package
## Requirements
- Package must be independently publishable
- Narrow scope
- Minimal cross-package dependencies
- Uses `@robhowley/` npm scope