Skip to content

feat(jafar-perf): add the jafar-perf plugin and attach the jfr-mcp plugins to a shared daemon - #8

Merged
jbachorik merged 3 commits into
mainfrom
feat/jafar-perf-plugin
Oct 3, 2026
Merged

jbachorik merged 3 commits into
mainfrom
feat/jafar-perf-plugin

Conversation

@jbachorik

@jbachorik jbachorik commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

What & why

Moves the jafar-perf plugin here from btraceio/jafar-perf-box, so the btraceio agent plugins live in one marketplace instead of two with overlapping names, and points both jfr-mcp plugins at the shared daemon from btraceio/jafar#119.

A separate plugin, not folded into jfr-analyzer. The overlap turned out to be small. jafar-perf is task playbooks (triage, cpu, latency, gc, memory-leak, heap-diff, compare) plus specialist subagents and a perf-lead fan-out. jfr-analyzer is the USE/TSA method and the async-profiler/BTrace interop. They clash only on the agent name perf-engineer, which plugin namespacing already keeps apart, and on the MCP wiring below.

Commit Change
fce91c1 add jafar-perf (both manifests, both catalogs, package.json), --attach for both jfr-mcp plugins, fix jfr-analyzer's .mcp.json, the Node drift check, a relaxed skill front-matter check
c160726 make the drift check resolve the published server with jbang --fresh
85fc3ad scheduled tool-drift.yml workflow
  • --attach. Both plugins now start the server as jbang jfr-mcp@btraceio --stdio --attach, so every session shares one daemon instead of starting a JVM each. An older jfr-mcp ignores the flag and runs a private server, so this degrades instead of breaking.
  • jfr-analyzer's .mcp.json was broken. It pointed at an SSE daemon on localhost:3000 with no token, which the daemon rejects. It now uses the bridge, keeping the jfr-mcp server key so the agent's mcp__jfr-mcp__* tool names still match. Its README also named a jafar-mcp alias that does not exist.
  • Drift check (scripts/check-tool-references.js, ported from jafar-perf-box in Node like the other validation scripts): starts the server, asks for tools/list, and fails naming every tool a skill or agent mentions that the server lacks, with file and line. It only reads plugins whose .mcp.json uses jfr-mcp, and ignores jfr_session/jfr_window/jfr_evidence, which are field names in the interop skill's evidence record, not tools.
  • Relaxed validate-repository.js. Its front-matter regex only allowed name and description, so it rejected 7 jafar-perf skills that carry allowed-tools (which pre-approves their MCP tools). Stripping the field would have changed how the skills behave, so the check now allows further single-line fields. A skill with no description is still rejected.
  • --fresh in the drift check. jbang caches the catalog; a stale alias started a server reporting 0.10.0 with 36 tools and the check failed on jfr_compare, drift that did not exist. The published 0.28.0 exposes 37 tools and all 35 referenced ones.

How verified

Command Result
scripts/validate-marketplace.sh passes: 5 plugins, 31 skills (only the existing interface warnings for jfr-analyzer and perf-engineer)
claude plugin validate plugins/jafar-perf passed
node scripts/check-tool-references.js against the published server OK: all 35 referenced tools exist (37 exposed)
same, with a planted jfr_bogus_tool in an agent FAIL naming the tool and plugins/jafar-perf/agents/cpu-analyst.md:21, exit 1
a skill with no description under the relaxed check still rejected
actionlint .github/workflows/tool-drift.yml clean
GitHub Actions on this PR Skills reference tools that exist (the new job, first run) pass in 21 s; both validate jobs pass
real Claude Code 2.1.288 (claude -p, strict MCP config) driving the built bridge server connected, jfr_open/jfr_summary/jfr_close succeed, two concurrent sessions with the same alias both succeed (btraceio/jafar#119 has the details)

Coverage notes

The validators cover manifests, catalogs, skill front matter and the Pi skill paths. The drift check covers every tool name in the two jfr-mcp plugins' skills and agents against the live server. No eval case was added: the corpus covers btrace-observability only.

Not verified / known limitations

  • The plugin installed through the marketplace with the real jbang jfr-mcp@btraceio --stdio --attach: the published jar has no --attach yet, so the Claude run above used the built jar with an equivalent scratch config.
  • The workflow's issue-opening step, which fires only on a failed scheduled run. The rest of the job ran and passed on this PR.
  • The branch is one commit behind main (docs: invoke JBang scripts directly, note jbang fallback #7); it merges cleanly and was not rebased.

Why this is a draft: it needs a jfr-mcp release that contains --attach to do what it says (until then it works, without sharing), and the issue-opening step is unexercised. It flips to ready once btraceio/jafar#119 is released.

Breaking changes / migration

  • jfr-analyzer users no longer need a daemon already running on localhost:3000; the plugin starts the server itself through JBang, which must be on PATH. A hand-started daemon is attached to automatically if one is already running.
  • jafar-perf-box users move with: /plugin marketplace remove btraceio, /plugin marketplace add btraceio/agent-plugins, /plugin install jafar-perf@btraceio-agent-plugins. A README pointer in that repository is prepared locally and will be pushed, and the repository archived, only after this merges.

Links

Depends on btraceio/jafar#119 (the --attach flag). Changelogs and plugin versions untouched.

🤖 Generated with Claude Code

jbachorik and others added 3 commits October 3, 2026 12:54
… shared daemon

Moves the jafar-perf plugin here from btraceio/jafar-perf-box so the btraceio
agent plugins live in one marketplace instead of two with overlapping names.
It is kept separate from jfr-analyzer: jafar-perf is task playbooks (triage,
cpu, latency, gc, memory-leak, heap-diff, compare) and specialist subagents,
jfr-analyzer is the USE/TSA method and the async-profiler/BTrace interop. The
perf-engineer agent keeps its name in both, which plugin namespacing keeps
apart.

- jafar-perf: agents, skills, Claude and Codex manifests, catalog entries in
  both marketplaces and package.json, README adapted to this repository.
- Both jfr-mcp plugins now start the server as `jbang jfr-mcp@btraceio
  --stdio --attach`, so every session shares one daemon with its own sessions
  instead of starting a JVM each. An older jfr-mcp ignores --attach and runs a
  private server, so this degrades rather than breaks.
- jfr-analyzer's .mcp.json pointed at an SSE daemon on localhost:3000 with no
  token, which the daemon rejects. It now uses the bridge, keeping the
  `jfr-mcp` server key so the agent's mcp__jfr-mcp__* tool names still match.
  Its README named a jafar-mcp alias that does not exist.
- scripts/check-tool-references.js (ported from jafar-perf-box, in Node like
  the other validation scripts) starts the server, asks for tools/list, and
  fails naming every tool a skill or agent mentions that the server lacks. It
  only reads plugins whose .mcp.json uses jfr-mcp, and ignores the field names
  of the interop skill's evidence record, which look like tools but are not.
- validate-repository.js accepted only `name` and `description` in skill front
  matter, rejecting skills that carry allowed-tools. It now allows further
  single-line fields; a skill without a description is still rejected.

Verified: scripts/validate-marketplace.sh passes (5 plugins, 31 skills) and
`claude plugin validate plugins/jafar-perf` passes; the only warnings are the
existing `interface` ones for jfr-analyzer and perf-engineer. The drift check
against a built jfr-mcp (37 tools) finds all 35 referenced tools, and catches a
planted nonexistent one with its file and line. A skill with no description is
still rejected by the relaxed front-matter check. Not run: a real Claude Code
install of the plugin, and the bridge from a plugin, since the published
jfr-mcp has no --attach yet.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
jbang caches the catalog, so a plain `jbang jfr-mcp@btraceio` can answer with
a stale alias. Here it started a server reporting 0.10.0 with 36 tools and the
check failed on jfr_compare, drift that did not exist: the published 0.28.0
exposes 37 tools and all 35 referenced ones. The check exists to test the
published server, so it now runs `jbang --fresh jfr-mcp@btraceio --stdio`.

Verified: with --fresh the check passes against the published server (37
tools, 35 references); the failing run above was reproduced without it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…oses

The skills and agents of the jfr-mcp plugins name the server's tools, and the
server is developed in btraceio/jafar, so a rename there turns a skill here
into instructions for a call that fails, and nothing in either repository's
tests connects the two. This runs scripts/check-tool-references.js against the
published server every Monday (the schedule is the point, since the drift
happens upstream), and on pushes and pull requests that touch the plugins or
the script. A failed scheduled run opens or updates an issue labelled
tool-drift, because nobody watches a cron job.

Carried over from btraceio/jafar-perf-box, with the Python script replaced by
the Node one and the action versions aligned with validate.yml where it uses
them (checkout and setup-node v5; setup-java and github-script stay on the
versions the original job ran).

Verified: actionlint passes on the workflow, and the exact command the job
runs passes locally against the published server. Not verified: a run on
GitHub Actions, including the issue-opening step, which only fires on a
failed scheduled run.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jbachorik
jbachorik marked this pull request as ready for review October 3, 2026 19:08
@jbachorik
jbachorik merged commit 4113985 into main Oct 3, 2026
3 checks passed
@jbachorik
jbachorik deleted the feat/jafar-perf-plugin branch October 3, 2026 19:32
jbachorik added a commit to btraceio/jafar-perf-box that referenced this pull request Oct 3, 2026
The jafar-perf plugin moved into the btraceio/agent-plugins marketplace so the btraceio
agent plugins sit in one place instead of two with overlapping names (this repository's
perf-engineer agent and jfr-analyzer's, for one). The README now says so at the top, with
the commands to switch: for Claude Code, remove this marketplace (named btraceio), add
btraceio/agent-plugins and install jafar-perf from it; for pi, remove this package and
install btraceio/agent-plugins; or re-run Jafar's installer, which migrates both.

Pushed once the move was complete: btraceio/agent-plugins#8 and #10 and btraceio/jafar#119 and
#120 are merged, jfr-mcp 0.29.0 is released, and the jbang catalog resolves to it. The
repository is archived right after.

Verified: `claude plugin marketplace remove`, `pi remove` and `pi install` exist in the
installed CLIs and are what the notice says; the installer's migration of an install made from
this repository was run in a scratch HOME (Claude Code and pi) and left only the new copies.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant