From jfr-analyzer
Record a JFR profile from a live JVM process and optionally analyze the result.
How this skill is triggered — by the user, by Claude, or both
Slash command
/jfr-analyzer:jfr-recordThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Record a JFR profile from a live JVM process and optionally analyze the result.
Record a JFR profile from a live JVM process and optionally analyze the result.
Arguments: $ARGUMENTS
Parse $ARGUMENTS:
PID: extract from pid=<value>. Empty if not provided.DURATION: extract from duration=<value> (e.g. 30s, 2m, 120s). Default: 60s.OUTPUT: extract from output=<path> (path without extension). Default: /tmp/jfr_recording.ANALYZE: extract from analyze=true or analyze=false. Default: true.SRC_PATH: extract from src=<path>. Empty if not provided.LANG: extract from lang=zh or lang=en. Default: zh.Normalize DURATION to seconds as integer DURATION_SECS (e.g. 2m → 120, 60s → 60).
Step 0a — Ambiguity check (run before asking for missing params):
Inspect $ARGUMENTS for signals that the user may have intended a different action:
| Signal in input | Likely intent | Offer as option |
|---|---|---|
Contains a file path ending in .jfr or .txt | Analyze an existing file, not record | "Analyze existing file <path> with /jfr?" |
Contains only a number with no pid= prefix | Ambiguous — could be PID or irrelevant | "Did you mean pid=<number>?" |
| Empty arguments | Unclear — record or analyze? | Present choice menu (see below) |
If arguments are completely empty, present a single disambiguation menu before doing anything else:
I can help with JFR profiling. What would you like to do?
1. Record a new JFR profile from a running Java process
2. Analyze an existing JFR file (.jfr or .txt)
3. Record and analyze in one step (recommended)
Enter a number, or describe what you need:
Map responses:
1 → continue this skill with ANALYZE=false2 → hand off to jfr-analysis skill: tell user to run /jfr <file-path>3 → continue this skill with ANALYZE=trueStep 0b — Ask for missing required parameters (only if intent is confirmed as "record"):
Combine into a single interaction. Only ask what is missing:
| Missing | Ask |
|---|---|
PID only | Run jcmd -l first, display process table, ask user to enter PID |
LANG only | Ask: "Output language — Chinese (zh) or English (en)?" |
| Both | Run jcmd -l, display table, ask PID and language together |
| Neither | Skip — proceed to Phase 1 |
When asking for PID, always show the process list from jcmd -l so the user can identify the right process. Accept either the number alone or pid=<number> format.
1a. Check jcmd availability:
which jcmd
If jcmd is not found:
jcmd not found. Please ensure JDK (not just JRE) is installed and $JAVA_HOME/bin is in PATH."1b. Check jfr availability (for binary conversion):
which jfr
Note whether jfr is available. If absent, warn the user that .jfr → text conversion will be skipped and only the raw .jfr file will be produced (analysis unavailable without conversion).
1c. List running Java processes:
jcmd -l
Display the output as a table to the user so they can identify the target process. Format:
PID Main Class / Description
------ ----------------------------
12345 org.elasticsearch.bootstrap.Elasticsearch
67890 com.example.MyApp
If PID was already provided by the user, confirm the process name matches expectations.
Construct the JFR output file path: JFR_FILE = <OUTPUT>.jfr.
Run:
jcmd <PID> JFR.start name=claude_rec duration=<DURATION> filename=<JFR_FILE> settings=profile
settings=profile enables CPU sampling, allocation profiling, lock contention, and I/O events — the full set needed for analysis.Tell the user:
<PID>.<DURATION> (<DURATION_SECS> seconds).<JFR_FILE>.Wait for the recording to finish:
sleep <DURATION_SECS + 3>
(Add 3 seconds buffer for JVM flush.)
While waiting, inform the user: "Recording in progress… (waiting <DURATION_SECS>s + 3s buffer)"
After sleep, verify the file exists and is non-empty:
ls -lh <JFR_FILE>
If the file is missing or empty:
jcmd <PID> JFR.check name=claude_recRun jfr print to convert the binary recording to a plain-text export:
jfr print <JFR_FILE> > <OUTPUT>.txt
Set TXT_FILE = <OUTPUT>.txt.
After conversion, confirm the file is non-empty:
ls -lh <TXT_FILE>
If conversion fails or the output file is empty:
jfr print <JFR_FILE> > output.txtTell the user: "Converted to text: <TXT_FILE>"
Execute only if ANALYZE is true and TXT_FILE exists.
Find the full analysis script. Try paths in order:
~/.claude/plugins/cache/claude-spells/jfr-analyzer/1.0.0/skills/jfr-analysis/scripts/jfr_full.py~/.claude/plugins/local/jfr-analyzer/skills/jfr-analysis/scripts/jfr_full.pyRun:
python3 <SCRIPT_DIR>/jfr_full.py <TXT_FILE>
Capture full Markdown output as RAW_REPORT.
Then proceed through the full jfr-analysis workflow (Phases 2–7 of jfr-analysis SKILL.md):
SRC_PATH is provided<OUTPUT>_jfr_report.md<OUTPUT>_optimization_plan.mdAll prose in the language specified by LANG.
If ANALYZE is false, tell the user:
<JFR_FILE><TXT_FILE>/jfr <TXT_FILE> lang=<LANG>| Situation | Action |
|---|---|
jcmd not found | Stop, instruct JDK installation |
PID not found in jcmd -l | Warn user, ask to reconfirm PID |
JFR.start fails with "JFR not supported" | Inform that JFR requires JDK (not OpenJ9), Oracle JDK, or OpenJDK 11+ with --enable-preview off |
.jfr file missing after sleep | Check JFR.check, report status |
jfr print conversion fails | Offer the raw .jfr for manual conversion and skip analysis |
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub xhao/claude-spells --plugin jfr-analyzer