pyroscope — Claude Code skill: continuous profiling
A skill for continuous profiling with Grafana Pyroscope: CPU, memory and allocation flame graphs read straight from the agent chat.
npx skills add grafana/skills --skill pyroscope -a claude-codeWhat pyroscope does
The skill lays out three instrumentation paths. A language SDK (Go, Java, Python, Ruby, Node, .NET, Rust) pushes samples to Pyroscope directly. Alloy with eBPF collects profiles with no code change. Or the SDK posts to pyroscope.receive_http and Alloy forwards them. Inside you get a Python SDK config example, a config.alloy block for cluster-wide eBPF profiling, ProfileQL queries, and the profile types: CPU, memory, allocations, goroutines, mutex.
Alloy eBPF needs root, host PID access and Linux kernel 5.8+ with BTF (or RHEL 4.18+). Grafana Cloud Profiles needs a numeric Pyroscope user (stack id) and an API key. On an older kernel or without BTF the pyroscope.ebpf component goes unhealthy with BPF errors, so check ls /sys/kernel/btf/vmlinux before rolling collection out across a cluster.
Span Profiles link a slow Tempo trace to its profile, which points at the code path behind the latency. There is a troubleshooting section too: an SDK that starts but produces no flame graph, a Cloud 401 from a wrong basic_auth_username, and profiles arriving with no frames — Java wants PYROSCOPE_FORMAT=jfr, Python on Alpine needs procfs and glibc compatibility.
What it helps with
- find what is burning CPU from a flame graph
- compare two profiles to catch a regression
- deploy cluster-wide profiling with Alloy, no code change
- correlate a slow Tempo trace to its profile
- track down high memory and allocation use
Example prompts for the agent
- add Pyroscope profiling to this Python service
- set up Alloy as an eBPF profiler for the whole cluster
- compare these two CPU profiles and show me the regression
How to install pyroscope
1Skills CLI (Vercel)
npx skills add grafana/skills --skill pyroscope -a claude-code2Manually: put the files in place
~/.claude/skills/pyroscope/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/pyroscope/
1Skills CLI (Vercel)
npx skills add grafana/skills --skill pyroscope -a codex2Manually: put the files in place
.agents/skills/pyroscope/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add grafana/skills --skill pyroscope -a cursor2Manually: put the files in place
.cursor/skills/pyroscope/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install grafana/skills pyroscope2Manually: put the files in place
.github/skills/pyroscope/SKILL.md1Skills CLI (Vercel)
npx skills add grafana/skills --skill pyroscope -a gemini-cli2Platform CLI
gemini skills install https://github.com/grafana/skills --path skills/grafana-lgtm/pyroscopeManually: put the files in place
.devin/skills/pyroscope/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add grafana/skills --skill pyroscope -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about pyroscope
How do I install pyroscope in Claude?
Run npx skills add grafana/skills --skill pyroscope -a claude-code. The skill lands at ~/.claude/skills/pyroscope/SKILL.md.
What does the pyroscope skill do?
It helps you wire up continuous profiling with Grafana Pyroscope and read the output as flame graphs. It covers SDKs, eBPF via Alloy, ProfileQL queries and trace-to-profile linking.
What does eBPF profiling with Alloy require?
Root, host PID access and Linux kernel 5.8+ with BTF (or RHEL 4.18+). Without those the pyroscope.ebpf component reports unhealthy.
Source text
SKILL.md · Apache-2.0
---
name: pyroscope
license: Apache-2.0
description: Continuously profile applications with Grafana Pyroscope and read the result as flame graphs. Covers three instrumentation paths — language SDK push (Go / Java / Python / Ruby / Node / .NET / Rust), Alloy eBPF auto-instrumentation (no code change, requires kernel 5.8+ with BTF), and SDK → Alloy receiver — plus ProfileQL queries, profile types (CPU / memory / allocations / goroutines / mutex), Grafana Cloud Profiles endpoint, and Span Profiles trace-to-profile linking. Use when adding profiling to a service, deploying Alloy as a cluster-wide eBPF profiler, hunting CPU / memory hotspots from a flame graph, comparing two profiles to find a regression, or correlating a slow Tempo trace to its profile — even when the user says "find what's burning CPU", "flame graph this app", "continuous profiling", "heap hotspots", or "why is allocation so high" without naming Pyroscope.
---
# Grafana Pyroscope
> **Docs**: https://grafana.com/docs/pyroscope/latest/
Continuous profiling — flame graphs of CPU, memory, allocations, mutex contention, goroutines.
## Prerequisites
- Pyroscope server (OSS) or Grafana Cloud Profiles endpoint
- For Cloud: numeric Pyroscope user (stack id) + API key
- For eBPF via Alloy: root + host PID + Linux ≥ 5.8 with BTF (or RHEL 4.18+)
## Instrumentation paths
1. **Alloy eBPF** (preferred) — auto-instrument, no code change
2. **SDK direct push** — application calls Pyroscope API
3. **SDK → Alloy** — SDK posts to `pyroscope.receive_http`, Alloy forwards
## Common Workflows
### 1. Instrument an app with the SDK (representative: Python)
```bash
pip install pyroscope-io==1.0.11
```
```python
import pyroscope, os
pyroscope.configure(
application_name="my.python.app",
server_address="http://pyroscope:4040",
sample_rate=100, oncpu=True,
tags={"region": os.getenv("REGION"), "env": "prod"},
)
# Dynamic tag for a hot path
with pyroscope.tag_wrapper({"controller": "slow_controller"}):
slow_code()
```
```bash
# Verify the app is pushing — Pyroscope ingests samples in a few seconds
curl -s http://pyroscope:4040/ready # → "ready"
curl -s http://pyroscope:4040/api/v1/labels | jq '.data | index("service_name")' # → not null
# Verify the service shows up in Grafana → Explore → Profiles → service dropdown.
```
Other SDKs (Java agent, Node, Ruby, .NET, Rust) + Cloud auth + tunable env vars: [`references/sdks.md`](references/sdks.md).
### 2. Cluster-wide eBPF profiling with Alloy
```alloy
# config.alloy — full block in references/ebpf-and-query.md
pyroscope.ebpf "local_pods" {
forward_to = [pyroscope.write.cloud.receiver]
targets = discovery.relabel.local_pods.output
sample_rate = 97
collect_interval = "15s"
}
pyroscope.write "cloud" {
endpoint {
url = "https://profiles-prod-xxx.grafana.net"
basic_auth { username = sys.env("PYROSCOPE_USER")
password = sys.env("GRAFANA_API_KEY") }
}
}
```
```bash
# 1. Reload Alloy
curl -X POST http://localhost:12345/-/reload
# 2. Verify the eBPF component is healthy
curl -s http://localhost:12345/api/v0/web/components \
| jq '.[] | select(.id|contains("pyroscope.ebpf")) | {id,health:.health.state}'
# Expect: health.state == "healthy"
# 3. Verify profiles arriving in Pyroscope
# Grafana → Explore → Profiles datasource → query:
# {namespace="default", __profile_type__="process_cpu:cpu:nanoseconds:cpu:nanoseconds"}
# Expect flame graph to render with frames from the target pods.
```
### 3. Query with ProfileQL
```
{service_name="myapp", env="prod",
__profile_type__="process_cpu:cpu:nanoseconds:cpu:nanoseconds"}
```
Profile-type list + full ProfileQL grammar: [`references/ebpf-and-query.md`](references/ebpf-and-query.md).
## Troubleshooting
- SDK starts but no flame graph → check the app actually called `start()` / `configure()` (some SDKs are lazy); check `server_address` reachable from inside the container
- Alloy eBPF component `unhealthy` with BPF errors → kernel < 5.8 or BTF missing; `ls /sys/kernel/btf/vmlinux`
- Cloud push 401 → wrong `basic_auth_username` (must be the numeric stack id, not the slug)
- Profile shows up but with no frames → for Java, set `PYROSCOPE_FORMAT=jfr`; for Python on Alpine, ensure `procfs` and `glibc` compatibility
## Resources
- [Pyroscope docs](https://grafana.com/docs/pyroscope/latest/)
- [Grafana Cloud Profiles](https://grafana.com/docs/grafana-cloud/monitor-applications/profiles/)
- [`references/sdks.md`](references/sdks.md) — Java/Node/Ruby/.NET/Rust install + config + env-var table + profile-type matrix
- [`references/ebpf-and-query.md`](references/ebpf-and-query.md) — full Alloy eBPF pipeline + ProfileQL
© grafana · Apache-2.0 · grafana/skills