Instructions for all agents (and humans) working in this repo. This is the
single source of truth; CLAUDE.md just points here.
This repo packages PostHog's developer content (docs, prompts, example code) into Agent Skills-compliant skill packages. The build pipeline emits a versioned manifest plus per-skill ZIPs, consumed by the PostHog wizard and the PostHog MCP server.
User-facing intro: README.md. Contributor handbook: CONTRIBUTING.md.
| Concern | Where |
|---|---|
| Skill source content | context/skills/<name>/ |
| Skill descriptor / CLI role declarations | context/skills/<name>/config.yaml |
| Build pipeline | scripts/lib/ (skill generator, build phases, change router) |
| Build entrypoints | scripts/build.js (full) and scripts/dev-server.js (partial / watch) |
| Tests | scripts/lib/tests/ and scripts/plugins/tests/ (vitest) |
| Manifest output | dist/skills/manifest.json, dist/skills/skill-menu.json (CLI entries live under cliEntries) |
| Per-skill ZIPs | dist/skills/<id>.zip |
Every skill's config.yaml may declare an optional cli: block that tells the
wizard whether and how to expose the skill as a CLI command. It's compiled into
cliEntries in dist/skills/skill-menu.json, which the wizard fetches at
runtime. Adding or renaming a skill-backed command is a context-mill release —
no wizard code change. The full schema, the YAML→command mapping, and the
promotion criterion live in
CONTRIBUTING.md. Quick shape:
cli:
role: command # command | skill | internal
parentCommand: audit # optional — nests this command under another
command: events # the user-typed word; required when role is commandThe parser is parseCliBlock in scripts/lib/skill-generator.js. It enforces:
roleis one ofcommand,skill,internal(default:skillif nocli:block is set at all)commandandparentCommandare kebab-case, 2–20 characters- Neither field is a yargs reserved word (
help,version,completion) or a wizard internal flag (playground,benchmark,yara-report,local-mcp,ci,skill) default(optional, boolean) marks the leafwizard <family>runs by default (and pre-highlights it in the picker once a family has several)
Failures throw at build time, before drift can ship to the wizard.
Flat vs. family rule: a public command is flat when there's only one option
today, a family when the user must pick. Don't pre-create wizard migrate <vendor> while there's only one vendor — restructure to a family when a second
lands. See CONTRIBUTING.md § Flat vs. family.
- Read CONTRIBUTING.md § Promotion criterion for
role: command. - Run
npm test— the parser's suite (scripts/lib/tests/cli-block.test.js) covers every naming-convention case. - Run
npm run build— confirm the entry appears (or disappears) undercliEntriesindist/skills/skill-menu.jsonwith the values you expect. - The wizard resolves new entries at runtime, so no wizard release is required unless the change needs wizard-side hooks (custom outro, content blocks, abort cases).
The wizard CLI was overhauled. Use the new command names. Old names mostly no longer exist — only some keep an alias.
| Old command | New command | Status |
|---|---|---|
wizard integrate |
wizard (default flow) |
command removed |
wizard events-audit |
wizard audit events |
moved into audit family |
wizard audit (single) |
wizard audit <subcommand> |
now a family — see audit subcommands below |
wizard audit-3000 |
removed | retired |
wizard revenue |
wizard revenue-analytics |
renamed (old revenue removed) |
wizard upload-sourcemaps |
wizard upload-source-maps |
renamed; upload-sourcemaps kept as alias |
Audit subcommands — the one family today backed by skills from this repo:
| Subcommand | Backing skill |
|---|---|
wizard audit events |
audit-events (default leaf) |
wizard audit all |
audit |
wizard audit autocapture |
audit-autocapture |
wizard audit feature-flags |
audit-feature-flags |
wizard audit identify |
audit-identify |
wizard audit session-replay |
audit-session-replay |
wizard audit web-analytics |
(wizard-native, not a skill here) |
Commands vs. skills: those audit subcommands are skills, promoted to
commands via cli: role: command. A role: skill skill is reachable only via
wizard skill <id>. Same machinery, two surfaces — so wizard audit <subcommand>
picks an audit area, it does not take a skill name.
Commands vs. programs: a command is the word a user types; a program is the
internal logic behind it. posthog-integration is a program id, not a command
— it powers the default flow. Don't reference it as a CLI command.
When you rename a command, update this table. A rename is a breaking change for users — keep the old name working as an alias only when external callers (users' scripts) may still use it; when the only caller is one we control, update the caller instead.
npm install # Install dependencies
npm test # vitest run (parsers, expander, plugins, cli block)
npm run build # Full build: emits dist/skills/<id>.zip + manifests
npm run dev # Partial-rebuild dev server with watch- Skill content lives in markdown, never in JS/TS. The build pipeline reads YAML configs and stitches markdown together; it doesn't generate prose.
- The
cli:block is the single source of truth for the wizard's command surface for any skill. Don't duplicate command names in the wizard repo; they're derived from the manifest. additionalProperties: falseis set on the JSON Schema — adding a new field to the manifest shape is a coordinated change (bump the schema, bump consumer types in the wizard). See PostHog/wizard CONTRIBUTING.md for the wizard-side contract.