Adopt Apache Magpie (agent-assisted maintainer workflows) + JMeter config#1
Adopt Apache Magpie (agent-assisted maintainer workflows) + JMeter config#1milamberspace wants to merge 10 commits into
Conversation
Complete the snapshot-based adoption started in 729551e: - Pin the framework in .apache-magpie.lock (git-branch, apache/magpie@main) - Wire security, pr-management, and issue skill families (+ always-on setup-*/list-*) as gitignored magpie-* symlinks - Scaffold .apache-magpie-overrides/ - Wire the agent-guard PreToolUse hook in .claude/settings.json - Document the adoption in README.md and AGENTS.md Generated-by: Claude Opus 4.8
Add .apache-magpie-overrides/project.md — the per-project config the apache-magpie skills read to resolve identity, repositories, mailing lists, mail sources, and security-workflow knobs for JMeter. Filled from confirmed facts (upstream apache/jmeter@master, GitHub Issues, dev@/private@/user@/commits@jmeter.apache.org, ASF Vulnogram CNA, Gmail+PonyMail mail sources). Security-tracker/board/issue-template blocks are marked N/A: JMeter runs no dedicated GitHub security tracker (.asf.yaml projects: false); vulnerabilities go to security@apache.org and private@jmeter.apache.org. Generated-by: Claude Opus 4.8
Add the three per-project config files the pr-management-triage skill reads from .apache-magpie-overrides/: - pr-management-config.md — identifiers, labels, grace windows (tuned longer than framework defaults for JMeter's slow triage cadence), workflow choices (pr-body feedback channel). - pr-management-triage-comment-templates.md — JMeter doc URLs (CONTRIBUTING.md, gradle.md, building.html), the fixed quality-criteria marker, and the AI-attribution footer. - pr-management-triage-ci-check-map.md — maps JMeter's real GitHub Actions check names (Validation, Error Prone, Matrix Preparation, the JDK x vendor x OS x locale test matrix) to categories + gradle.md. area-grouping is disabled (JMeter uses no area:* labels); the workflow labels are documented as not-yet-created (PMC decision) so label actions degrade to feedback-only until then. Generated-by: Claude Opus 4.8
Match the SPDX-License-Identifier header the four sibling files in .apache-magpie-overrides/ already carry (project.md, pr-management-config.md, pr-management-triage-comment-templates.md, pr-management-triage-ci-check-map.md). AGENTS.md is intentionally left without a header, consistent with JMeter's other root docs (README.md, CONTRIBUTING.md, SECURITY.md, THREAT_MODEL.md, gradle.md), which carry none. Generated-by: Claude Opus 4.8
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/agent-guard.py\"", |
There was a problem hiding this comment.
What is this? Why creating a hook without agent-guard.py?
There was a problem hiding this comment.
Good catch. Two parts, then the fix.
What it is: .claude/settings.json wires Magpie's deterministic agent-guard — a Claude Code PreToolUse hook that blocks risky gh/git commands before they run (a commit carrying a Co-Authored-By trailer, an @-mention that would ping a maintainer, marking a PR "ready" while CI is still pending, force-pushing an empty PR…). It's a safety rail, not project logic.
Why agent-guard.py isn't in the PR: same rule as the 68 skills — it's framework code, gitignored on purpose, synced from the Magpie snapshot by /magpie-setup (re-collected on upgrade). We don't vendor it into JMeter's history; only magpie-setup + config are committed.
But your underlying point is valid: the committed wiring referenced a script that isn't there until /magpie-setup runs, so on a fresh clone the hook would try to exec a missing file on every Bash call — and a PreToolUse error can block the tool. That's a footgun.
Fixed in 6ec2d88: the committed command is now a no-op until the script exists —
[ -f "$CLAUDE_PROJECT_DIR/.claude/hooks/agent-guard.py" ] && python3 "$CLAUDE_PROJECT_DIR/.claude/hooks/agent-guard.py" || true
I'll also upstream this to apache/magpie (via setup-upstream-fix), since it affects every adopter. If you'd rather not commit the wiring at all, the alternative is to let /magpie-setup write it into the gitignored settings.local.json instead — happy to switch to that if you prefer.
There was a problem hiding this comment.
Upstreamed: the guard is now proposed for every adopter in apache/magpie#786 — it updates the committed hook snippet in skills/setup/adopt.md and tools/agent-guard/README.md to the same [ -f … ] && … || true form. Once that merges and we /magpie-setup upgrade, our local 6ec2d88 becomes redundant and can be dropped. Thanks again for catching it.
| <!-- SPDX-License-Identifier: Apache-2.0 | ||
| https://www.apache.org/licenses/LICENSE-2.0 --> | ||
|
|
||
| # Apache JMeter — project manifest |
There was a problem hiding this comment.
Fair question — same one you raised on dev@, so here it is inline too.
These are slow-moving facts (upstream repo, default branch, mailing lists, label names, CI-check names) — a label rename or a new CI job touches one line. Keeping them current isn't a separate chore:
/magpie-setup upgradereconciles these overrides against framework changes and surfaces any drift for review, andsetup-upstream-fixpushes our own fixes back upstream.- When JMeter itself changes something referenced here (renames a label, adds a CI check), whoever makes that change updates the one line — exactly like
.asf.yamlor CODEOWNERS. - The skills read this file at runtime, so an obviously-stale value surfaces on the next run.
So: "who" = the maintainers who use the skills, like any config; "what" = reconcile-on-upgrade plus normal review. Not a standing maintenance burden.
There was a problem hiding this comment.
The CI matrix changes very often. The stale context is worse than no context.
whoever makes that change updates the one line — exactly like .asf.yaml
I would prefer Magpie to source information from .asf.yaml rather than forcing everybody to duplicate the info.
There was a problem hiding this comment.
Good point — you're right, and I've changed it.
I collapsed the CI-check map to a single generic pointer (a6a8908): there are no per-check-name patterns to maintain anymore, so nothing goes stale when the matrix changes. Every failing check just points at gradle.md — and since the old rows all pointed there anyway, we lose nothing. Stale context is worse than no context.
On sourcing from .asf.yaml: agreed in spirit, with one caveat — .asf.yaml doesn't actually carry the CI-check names (those live in .github/workflows/ + matrix.mjs), so it couldn't have fed this particular file. Where it does help is the stable project fields (repo, mailing lists via notifications:, labels), and those rarely change. The remaining project.md values here (repo, default branch, dev@/private@, the CNA org id) are stable too, so the staleness risk is essentially gone.
That said, your underlying request — Magpie should derive adopter config from existing sources instead of making everyone duplicate it — is a good framework-level idea, not a JMeter-local one, so I filed it upstream: apache/magpie#815 (same path as the hook fix → apache/magpie#786). Thanks for pushing on this.
There was a problem hiding this comment.
Franlky, I do not see reasons to document ci check names in magpie and/or in other places
There was a problem hiding this comment.
Done — dropped the per-check-name patterns entirely (a6a8908); the CI-check map is now a single generic pointer to gradle.md, so there are no check names to keep in sync. I also filed the broader "derive adopter config from existing sources instead of duplicating" idea upstream: apache/magpie#815.
Per @vlsi's review on PR #1: .claude/settings.json wires the agent-guard PreToolUse hook, but agent-guard.py is gitignored (framework code synced by /magpie-setup, like the skills). On a fresh clone before /magpie-setup runs, the hook would exec a missing file on every Bash call — and a PreToolUse error can block the tool. Guard the command so it is a no-op until the script exists: [ -f ".../agent-guard.py" ] && python3 ".../agent-guard.py" || true Worth upstreaming to apache/magpie (affects every adopter). Generated-by: Claude Opus 4.8
Per @vlsi's review on PR #1: JMeter's CI matrix job names are generated dynamically (matrix.mjs) and change often, so the per-check-name patterns (Validation / Error Prone / vendor substrings / stress-JIT / …) were a stale-prone surface with no added value — every row pointed at the same gradle.md anyway. Collapse the map to a single generic catch-all (+ the merge-conflict and failing-CI fallbacks). "Stale context is worse than no context." Generated-by: Claude Opus 4.8
vlsi
left a comment
There was a problem hiding this comment.
I do not care much about the contents of magpie-setup skill, however I would like to keep only really important entries in agents.md.
| "hooks": { | ||
| "PreToolUse": [ | ||
| { | ||
| "matcher": "Bash", |
There was a problem hiding this comment.
Good catch — the [ -f … ] && … || true form is POSIX-only and would break under Windows PowerShell. Fixed in 3d302c3 with a pure-Python existence check that no-ops when the script is absent (fresh clone) and runs the guard otherwise — cross-platform, no shell conditional:
python3 -c "import os,sys,subprocess; p=os.path.join(os.environ.get('CLAUDE_PROJECT_DIR',''),'.claude','hooks','agent-guard.py'); sys.exit(subprocess.call([sys.executable,p]) if os.path.isfile(p) else 0)"
The earlier POSIX form landed upstream in apache/magpie#786 (already merged), so I'll open a follow-up there to make it cross-platform too.
There was a problem hiding this comment.
Can magpie add the hook entry to claude/settings.local.json on setup?
There was a problem hiding this comment.
Follow-up opened: apache/magpie#823 makes the committed hook cross-platform (the pure-python3 -c form) upstream too.
There was a problem hiding this comment.
Done — good call; not committing the wiring at all is cleaner than any guard.
- Dropped
.claude/settings.jsonfrom this PR (bea19ec) and gitignored.claude/settings.local.jsonas the hook's home (ff2b836). - Filed the framework change upstream: setup: write the agent-guard hook to gitignored settings.local.json instead of committing it to settings.json apache/magpie#824 —
/magpie-setupwrites the hook intosettings.local.jsonat the same moment it syncsagent-guard.py. Because the wiring then only ever exists once the script is present, there's no fresh-clone footgun and no cross-platform shell trick needed: a plainpython3 ".../agent-guard.py"works on POSIX and Windows alike. That supersedes my cross-platform PR fix(agent-guard): make the fresh-clone hook guard cross-platform (Windows) apache/magpie#823.
The guard is simply inactive in JMeter until apache#824 lands — fine for an opt-in, pending adoption.
| @@ -1 +1,36 @@ | |||
| Security model: [SECURITY.md](./SECURITY.md) | |||
|
|
|||
| ## apache-magpie framework | |||
There was a problem hiding this comment.
Please do not include excessive items to agents.md.
They will be injected in all the agent context, so it would distract agent attention and it would consume tokens.
As magpie is optional, I see no reason to mention it here
There was a problem hiding this comment.
Agreed — removed the whole apache-magpie section from AGENTS.md in 3d302c3, back to just the Security model line. You're right: AGENTS.md is injected into every agent context and Magpie is opt-in, so it shouldn't sit there. The adoption / setup summary stays in README.md (which is not always-injected).
| via PR to | ||
| [`apache/magpie`](https://github.com/apache/magpie). | ||
|
|
||
| ### Reviewing pull requests |
…platform Per @vlsi's review on PR #1: - AGENTS.md: drop the whole "apache-magpie framework" section (incl. the "Reviewing pull requests" note). AGENTS.md is injected into every agent context, so an opt-in-framework advert is a permanent token tax and a distraction; the adoption/setup info already lives in README.md (which is not always-injected). Back to the single "Security model" line. - .claude/settings.json: the previous guard used POSIX shell (`[ -f … ] && … || true`), which does not work under Windows PowerShell. Replace it with a pure-Python command that no-ops when the script is absent (fresh clone) and runs the guard otherwise — cross-platform, and no shell conditional: python3 -c "... sys.exit(subprocess.call([sys.executable,p]) if os.path.isfile(p) else 0)" Generated-by: Claude Opus 4.8
Per @vlsi's review on PR #1: rather than committing the PreToolUse hook in .claude/settings.json, the wiring belongs in the gitignored, per-machine .claude/settings.local.json, written by /magpie-setup when it syncs agent-guard.py in. Since the script is then always present when the wiring exists, no fresh-clone guard is needed and the command stays a plain cross-platform `python3 ".../agent-guard.py"` — no committed footprint, no Windows shell issue. Removing the committed settings.json here; the framework-side change (adopt flow writing settings.local.json) is filed upstream. The guard is simply inactive in JMeter until that lands — acceptable for an opt-in, pending adoption. Generated-by: Claude Opus 4.8
Companion to the previous commit. The agent-guard hook wiring now lives in the per-machine .claude/settings.local.json, written by /magpie-setup — so gitignore it (it must never be committed), and refresh the stale comment that still referred to the removed committed settings.json. Generated-by: Claude Opus 4.8
| - https://github.com/apache/jmeter | ||
| - https://gitbox.apache.org/repos/asf/jmeter.git | ||
|
|
||
| ## Agent-assisted contribution (apache-magpie) |
There was a problem hiding this comment.
I am afraid PR triage and issue triage does require JMeter knowledge, so advising people to install magpie and start triaging PRs might be too much.
It might be ok as a section in CONTRIBUTING.md.
WDYT of listing the rules regarding agent-assisted contribution in the root readme (or contributing.md) instead?
What
Adopts the Apache Magpie framework of
agent skills into JMeter, plus the JMeter-specific configuration, so
maintainers can run structured, auditable workflows (PR triage, issue
triage, stats dashboards, security-issue and release helpers) from their
own AI coding agent.
Committed footprint (the important part)
19 files. The split:
project.md, thepr-management-*config,.gitignore, a shortREADMEsection, tworelay symlinks,
.apache-magpie.lock.magpie-setupbootstrap skill (~4.7k lines ofMarkdown docs, not code) — required so a fresh clone can re-fetch the
framework.
snapshot (
.apache-magpie/), fetched on demand. They never land ingit and never sit in the agent's context window (skills load on demand;
only a one-line description per skill is indexed).
Full removal is a single command:
/magpie-setup unadopt.What's wired for JMeter
pr-management,issue,security.release-*is intentionally not wired yet.
area:*labels (area groupingdisabled), no GitHub security tracker / Projects board (those panels are
N/A), real CI-check names mapped (
Validation,Error Prone, the JDK ×vendor × OS test matrix), longer grace windows for our slow triage
cadence.
dev@/private@via the ASF PonyMailarchive, ASF Vulnogram CVE tooling.
How it stays low-risk
before any comment, label, merge, or commit. No bots posting on their
own, no CI automation.
their own credentials. No shared service; no project data leaves the
maintainer's control.
PreToolUsehook blocks premature"ready", maintainer pings, and
Co-Authored-Bytrailers. The hook iswired into the gitignored, per-machine
.claude/settings.local.jsonby/magpie-setup(nothing hook-related is committed — seesetup: write the agent-guard hook to gitignored settings.local.json instead of committing it to settings.json apache/magpie#824).
Example output (read-only, nothing posted)
PR-backlog dashboard generated from our 70 open PRs by the
pr-management-statsskill:https://gistpreview.github.io/?b22eb23da618ff3b17a4e4e921375d72
Commits
magpie-setup)🤖 Generated with Claude Code