# Writing Skills

> Guide for writing PostHog agent skills — job-to-be-done templates that teach agents how to use MCP tools to achieve a goal. Use when adding new product functionality that agents should know how to work with, creating a new skill, or updating existing skills in products/*/skills/ or .agents/skills/.

- Skill: `gabrielmoreira/writing-skills` (Agent Skill)
- Install (CLI): `npx skillmds@latest add gabrielmoreira/writing-skills`
- Raw SKILL.md: https://api.skillmd.com/api/skills/gabrielmoreira/writing-skills/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML, Coding & Dev Tools
- Author: gabrielmoreira (https://skillmd.com/u/gabrielmoreira)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/gabrielmoreira/writing-skills

---


# 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).

## Choose a location

- Use `products/<product>/skills/` for work through PostHog tools, APIs, or customer code. These skills are published.
- Use `.agents/skills/` for work that requires a checkout of the PostHog repository. These skills stay in the repository.
- Staff-only access is not a reason to move a skill. An MCP workflow without a checkout stays published.
- For mixed skills, keep customer diagnosis published and move PostHog development steps into an existing internal skill or reference.
- Published workflows must not depend on internal skill files.

`hogli lint:skills` checks both locations. The scaffold, build, and sync commands below apply to published product skills.

## Quick workflow

```sh
# 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](https://github.com/PostHog/skills).

This repo is not the only source. [`PostHog/context-mill`](https://github.com/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

```text
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/posthog_ai/scripts/build_skills.py`](../../../products/posthog_ai/scripts/build_skills.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
- `render_hogql_example({"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/posthog_ai/skills/querying-posthog-data/SKILL.md`](../../../products/posthog_ai/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.

