/working-with-skills
Best practices for agents managing PostHog skills via the MCP `skill-*` tools — how to discover, read, create, update, and refactor skills efficiently, especially large skills with many bundled files. Use whenever you are about to call any `skill-*` tool, asked to author or edit
$ npx -y skills add posthog/posthog --skill working-with-skills --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/working-with-skills
Context preview
The summary Claude sees to decide when to auto-load this skill.
Best practices for agents managing PostHog skills via the MCP `skill-*` tools — how to discover, read, create, update, and refactor skills efficiently, especially large skills with many bundled files. Use whenever you are about to call any `skill-*` tool, asked to author or edit
SKILL.md
working-with-skills.SKILL.mdname: working-with-skills
description: >-
Best practices for agents managing PostHog skills via the MCP `skill-*` tools —
how to discover, read, create, update, and refactor skills efficiently, especially
large skills with many bundled files. Use whenever you are about to call any
`skill-*` tool, asked to author or edit a shared skill, or troubleshoot
why a skill write was rejected. Pairs with `skills-store` (which covers the
raw tool surface) by adding the decision-tree, efficiency, and pitfall guidance.
Working with PostHog skills
This skill teaches agents how to use the `skill-*` MCP tools well — minimum context, minimum round-trips, minimum mistakes. If you are not yet familiar with the tool surface itself, read the `skills-store` skill first for the catalog. This document is about _how to choose between the tools_ and _how to scale the workflow_ when skills get big.
Operating principles
1. **Progressive disclosure is non-negotiable.** Lists return descriptions, get returns body + manifest, file-get returns one file. Never preload bundled files "just in case" — every preloaded script is wasted context for the actual task. 2. **Pick the smallest write primitive that does the job.** A targeted `edits` or `file_edits` is cheaper, safer, and clearer in version history than a full body or full bundle replacement. 3. **Reads are cheap; concurrent overwrites are not.** Always have a recent `version` from `skill-get` (or from the response of the previous write) before calling any write tool, and pass it as `base_version`. 4. **Authoring follows the [Agent Skills spec](https://agentskills.io/specification).** Keep `name` kebab-case, descriptions trigger-rich, body short, bulky material in bundled files.
Decision tree: which tool do I call?
Need to know what's available?
└─► skill-list (names + descriptions only)
Need to use / inspect a specific skill?
└─► skill-get (body + file manifest, NO file contents)
└─► skill-file-get (one file, on demand, only as referenced)
Authoring a brand new skill?
└─► skill-create (body + all initial files in one call)
Editing an existing skill?
├─ Body change?
│ ├─ Substantial rewrite ............. update(body=...)
│ └─ Surgical tweak .................. update(edits=[{old, new}, ...])
├─ Bundled file content change?
│ └─ update(file_edits=[{path, edits:[...]}, ...])
├─ Add / remove / rename a file?
│ ├─ Add ............................. skill-file-create
│ ├─ Delete .......................... skill-file-delete
│ └─ Rename .......................... skill-file-rename
└─ Wholesale bundle reset (rare!) ....... update(files=[...]) # replaces ALL files
Want a fork as the starting point?
└─► skill-duplicate (then update the copy)
Done with a skill entirely?
└─► skill-archive (hides ALL versions; cannot be undone)If you find yourself reaching for `update(body=...)` plus a sprawling `files=[...]` to change one paragraph and one script, stop — that's two narrower calls (`update(edits=[...])` plus `update(file_edits=[...])`) or even a single `update` carrying both `edits` and `file_edits`.
Discover before you fetch
posthog:skill-list
{ "search": "fractal" }`skill-list` is the right tool to "find a skill" — it returns names and descriptions only. Reading the descriptions is the entire point: pick the right skill before pulling any body. If `search` doesn't narrow it enough, list without it and scan, but do not start fetching candidate bodies blindly.
`skill-get` should be called **once per skill per task**, not per question. Cache the body in your working memory; fetch again only if you suspect the skill changed under you (e.g. a `409` on write — see "Concurrency" below).
Reading a large skill efficiently
Big skills (long body, many bundled files) are the case where lazy loading matters most.
1. `skill-get(skill_name=...)` — read `body` + `files[]` manifest. 2. Scan the body's table of contents / headings. The body should already tell you which file goes with which task — that's why bodies stay short and reference files by path. 3. For each file the body explicitly points at for _the current task_, call `skill-file-get(file_path=...)`. Skip everything else. 4. If the body references "see scripts/X for the rare case Y" and you are not in case Y, do not fetch `scripts/X`.
When in doubt, fewer files. You can always fetch one more on the next turn.
Authoring a new skill
Use a single `skill-create` call with body **and** initial files — the skill lands at `version: 1` complete. Do not create the skill empty and then make N follow-up `skill-file-create` calls; that's N extra versions and N extra round-trips for no benefit.
posthog:skill-create
{
"name": "my-skill",
"description": "What it does AND when to use it. Include trigger keywords.",
"body": "# my-skill\n\n## When to use\n...\n## Workflow\n...",
"license": "MIT",
"compatibility": "Requires Python 3.10+",
"allowed_tools": ["Bash", "Write"],
"metadata": { "author": "me", "category": "..." },
"files": [
{ "path": "scripts/foo.py", "content": "...", "content_type": "text/x-python" },
{ "path": "references/primer.md", "content": "...", "content_type": "text/markdown" }
]
}Authoring rules of thumb
- **`description` is the discovery surface.** It is the only thing
`skill-list` returns. Make it trigger-rich (what the user might say) and scope-honest (what the skill does and does not do).
- **`name`** — kebab-case, max 64 chars, no leading/trailing/consecutive
hyphens. The spec validator rejects anything else.
- **Body ≤ ~500 lines.** Long preambles, exhaustive SQL, full example payloads,
and runnable code belong in `references/`, `assets/`, or `scripts/`. The body should _route_ to those files, not inlin
Read more
name: working-with-skills description: >- Best practices for agents managing PostHog skills via the MCP `skill-*` tools — how to discover, read, create, update, and refactor skills efficiently, especially large skills with many bundled files. Use whenever you are about to call any `skill-*` tool, asked to author or edit a shared skill, or troubleshoot why a skill write was rejected. Pairs with `skills-store` (which covers the raw tool surface) by adding the decision-tree, efficiency, and pitfall guidance.
Working with PostHog skills
This skill teaches agents how to use the `skill-*` MCP tools well — minimum context, minimum round-trips, minimum mistakes. If you are not yet familiar with the tool surface itself, read the `skills-store` skill first for the catalog. This document is about _how to choose between the tools_ and _how to scale the workflow_ when skills get big.
Operating principles
1. **Progressive disclosure is non-negotiable.** Lists return descriptions, get returns body + manifest, file-get returns one file. Never preload bundled files "just in case" — every preloaded script is wasted context for the actual task. 2. **Pick the smallest write primitive that does the job.** A targeted `edits` or `file_edits` is cheaper, safer, and clearer in version history than a full body or full bundle replacement. 3. **Reads are cheap; concurrent overwrites are not.** Always have a recent `version` from `skill-get` (or from the response of the previous write) before calling any write tool, and pass it as `base_version`. 4. **Authoring follows the [Agent Skills spec](https://agentskills.io/specification).** Keep `name` kebab-case, descriptions trigger-rich, body short, bulky material in bundled files.
Decision tree: which tool do I call?
Need to know what's available?
└─► skill-list (names + descriptions only)
Need to use / inspect a specific skill?
└─► skill-get (body + file manifest, NO file contents)
└─► skill-file-get (one file, on demand, only as referenced)
Authoring a brand new skill?
└─► skill-create (body + all initial files in one call)
Editing an existing skill?
├─ Body change?
│ ├─ Substantial rewrite ............. update(body=...)
│ └─ Surgical tweak .................. update(edits=[{old, new}, ...])
├─ Bundled file content change?
│ └─ update(file_edits=[{path, edits:[...]}, ...])
├─ Add / remove / rename a file?
│ ├─ Add ............................. skill-file-create
│ ├─ Delete .......................... skill-file-delete
│ └─ Rename .......................... skill-file-rename
└─ Wholesale bundle reset (rare!) ....... update(files=[...]) # replaces ALL files
Want a fork as the starting point?
└─► skill-duplicate (then update the copy)
Done with a skill entirely?
└─► skill-archive (hides ALL versions; cannot be undone)If you find yourself reaching for `update(body=...)` plus a sprawling `files=[...]` to change one paragraph and one script, stop — that's two narrower calls (`update(edits=[...])` plus `update(file_edits=[...])`) or even a single `update` carrying both `edits` and `file_edits`.
Discover before you fetch
posthog:skill-list
{ "search": "fractal" }`skill-list` is the right tool to "find a skill" — it returns names and descriptions only. Reading the descriptions is the entire point: pick the right skill before pulling any body. If `search` doesn't narrow it enough, list without it and scan, but do not start fetching candidate bodies blindly.
`skill-get` should be called **once per skill per task**, not per question. Cache the body in your working memory; fetch again only if you suspect the skill changed under you (e.g. a `409` on write — see "Concurrency" below).
Reading a large skill efficiently
Big skills (long body, many bundled files) are the case where lazy loading matters most.
1. `skill-get(skill_name=...)` — read `body` + `files[]` manifest. 2. Scan the body's table of contents / headings. The body should already tell you which file goes with which task — that's why bodies stay short and reference files by path. 3. For each file the body explicitly points at for _the current task_, call `skill-file-get(file_path=...)`. Skip everything else. 4. If the body references "see scripts/X for the rare case Y" and you are not in case Y, do not fetch `scripts/X`.
When in doubt, fewer files. You can always fetch one more on the next turn.
Authoring a new skill
Use a single `skill-create` call with body **and** initial files — the skill lands at `version: 1` complete. Do not create the skill empty and then make N follow-up `skill-file-create` calls; that's N extra versions and N extra round-trips for no benefit.
posthog:skill-create
{
"name": "my-skill",
"description": "What it does AND when to use it. Include trigger keywords.",
"body": "# my-skill\n\n## When to use\n...\n## Workflow\n...",
"license": "MIT",
"compatibility": "Requires Python 3.10+",
"allowed_tools": ["Bash", "Write"],
"metadata": { "author": "me", "category": "..." },
"files": [
{ "path": "scripts/foo.py", "content": "...", "content_type": "text/x-python" },
{ "path": "references/primer.md", "content": "...", "content_type": "text/markdown" }
]
}Authoring rules of thumb
- **`description` is the discovery surface.** It is the only thing
`skill-list` returns. Make it trigger-rich (what the user might say) and scope-honest (what the skill does and does not do).
- **`name`** — kebab-case, max 64 chars, no leading/trailing/consecutive
hyphens. The spec validator rejects anything else.
- **Body ≤ ~500 lines.** Long preambles, exhaustive SQL, full example payloads,
and runnable code belong in `references/`, `assets/`, or `scripts/`. The body should _route_ to those files, not inlin
:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.
Repo: posthog/posthog
Other skills on posthog.
- /analyzing-expensive-users
Analyze the most expensive users in AI observability and explain why they cost so much. Use when the user asks about top spenders, expensive users, per-user LLM cost, user-level cost drivers, or patterns behind high AI observability spend.
Open skill - /creating-online-evaluations
Author continuously-running online evaluations in PostHog AI observability, grounded in real failure modes you've identified. Use when the user wants evaluations that automatically score new generations or whole traces going forward — "create an eval to catch X", "continuously
Open skill - /exploring-ai-failures
Find where an AI/LLM application is failing in production and surface the failure patterns, working from real traces. Use when someone wants to understand what's going wrong with an AI feature, find and categorize failure modes, triage errors, or investigate quality issues
Open skill - /exploring-llm-clusters
Investigate AI observability clusters — understand usage patterns in AI/LLM traffic, compare cluster behavior, compute cost/latency metrics, and drill into individual traces within clusters.
Open skill - /exploring-llm-costs
Investigate LLM spend in PostHog — total cost over time, cost by model, provider, user, trace, or custom dimension, token and cache-hit economics, and cost regressions. Use when the user asks "how much are we spending on LLMs?", "which model / user / feature is most expensive?",
Open skill - /exploring-llm-evaluations
Investigate AI observability evaluations — `hog` (deterministic code-based), `llm_judge` (LLM-prompt-based), and `sentiment` (user-message sentiment). Find existing evaluations, inspect their configuration, run them against specific generations, query individual results, and
Open skill

