Writing skills for PostHog agents
Read the full guide at [docs/published/handbook/engineering/ai/writing-skills.md](../../../docs/published/handbook/engineering/ai/writing-skills.md).
Quick workflow
# 1. Scaffold
hogli init:skill
# 2. Write your skill in products/{product}/skills/{skill-name}/SKILL.md
# 3. Lint
hogli lint:skills
# 4. Build to verify
hogli build:skills
# 5. Test locally with PostHog Desktop or a coding agent
hogli sync:skill -- --name <skill-name>
# 6. Delete the test skill (optional)
hogli unsync:skill -- --name <skill-name>
Distribution is automatic after merge — CI publishes to PostHog/skills.
This repo is not the only source. PostHog/context-mill publishes the omnibus skills — instrument-integration, instrument-product-analytics, instrument-feature-flags, instrument-error-tracking, instrument-llm-analytics, instrument-logs — and every shipping consumer overlays them on top of this repo's, so context-mill wins on a same-named skill. hogli lint:skills fails if you add one of those names under products/*/skills/; change the context-mill source instead. Local builds are the opposite case: they carry no omnibus skills at all, so anything that depends on one has to overlay it or fail loudly. See [Context-mill skills override this repo's](../../../docs/published/handbook/engineering/ai/writing-skills.md#context-mill-skills-override-this-repos) for the merge sites.
When to write a skill
When new functionality is added to a product and agents need to know how to work with it. A skill is not about what tools exist (that's the MCP server) — it's about how an experienced person would approach a job using those tools.
Ask: "If a customer asked an agent to do X with my feature, would the agent know the right approach?" If not, write a skill.
How many is too many?
Skill count is a budgeted, shared resource — agents pick from a list of all skill descriptions, and many harnesses truncate that list once it grows long, so every extra skill makes the others less likely to fire. Prefer a small set of focused skills, each with rich references/, over many thin ones:
- New trigger → new skill. A skill earns its own entry point only when its "when to use it" is clearly distinct from every existing skill.
- More detail →
references/, not a new skill. Another failure mode, SDK variant, or query catalog is depth on an existing job — add it to that skill's references/ instead of spending a new slot.
- Consolidate near-duplicate siblings. Skills sharing a diagnosis, bug class, or trigger should be one skill with references, not two.
Key rules
- Name: lowercase kebab-case, prefer gerund form (
analyzing-llm-traces, not llm-analytics). Never prefix with posthog-*.
- Description: third person, specific, include trigger terms and when to use it. Max 1024 chars.
- Structure:
SKILL.md entry point + references/ for detailed content. Keep SKILL.md under 500 lines.
- Frontmatter:
name and description are required.
- Tone: describe the workflow and reasoning, not a rigid script. Trust the agent to adapt.
- Conciseness: the agent is smart — only include context it doesn't already have.
Skill structure
products/{product}/skills/{skill-name}/
SKILL.md # entry point (required)
references/ # optional
guidelines.md
models-foo.md
example-bar.md.j2 # Jinja2 template, rendered at build time
scripts/ # optional
setup.sh
Only references/ and scripts/ subdirectories are collected. Others are ignored.
Template functions
Files ending in .j2 are rendered with Jinja2 at build time by [products/posthogai/scripts/buildskills.py](../../../products/posthogai/scripts/buildskills.py). Extend the build pipeline so the monorepo stays the source of truth — when domain knowledge lives in code (Pydantic models, query runners, function registries), add a template function rather than duplicating it as static markdown that drifts.
Available functions:
pydantic_schema("dotted.path.to.Model") — renders a Pydantic model's JSON Schema
renderhogqlexample({"kind": "TrendsQuery", ...}) — renders a query spec to HogQL SQL
hogql_functions() — returns all available HogQL function names
Good example: querying-posthog-data
- Clear entry point linking to 30+ reference files
- Progressive disclosure — agents load only what they need
- Mix of static
.md and generated .md.j2 content
- See [
products/posthogai/skills/querying-posthog-data/SKILL.md](../../../products/posthogai/skills/querying-posthog-data/SKILL.md)
Bad example: llm-analytics
An umbrella skill covering traces, experiments, evaluations, cost tracking, prompt management. Too broad — agents can't determine when to activate it. Break into focused skills instead.