From b34bd768f7fa1fa729e9d5950943ea8b5b3f9da2 Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Sun, 25 Oct 2026 20:31:51 +0100 Subject: [PATCH 1/3] fix: correct stale docs, counts and comments left by recent changes A spec-sync pass over the commits since 03c15a6d1 found places where the docs, tables and comments no longer match the code: - Skill tables and counts: add setup-complete-upgrade and setup-privacy-llm to docs/modes.md, complete-upgrade to the setup README, submit-to-oss-scan to the security README; fix eval step lists and case counts in the skill-evals READMEs. - Adapters: Bitbucket and GitLab are `partial`, not `partial-read-only`; the Bitbucket capability row lists the writes the tool ships. - `` resolves to `.apache-magpie/` on a snapshot install, not `.apache-magpie/apache-magpie`; fixed at the source (init_skill.py) and in the skills and READMEs that copied it. - CVE record-publish: document the vendor-advisory precondition (exit 4) and that --allow-state replaces the REVIEW default. - Secure setup: bubblewrap 0.13.1, PREK_HOME required only with prek, run the gateway hook by hand with ` provides read-only discovery of Jira keys associated with pull-request commits and hands them to the Jira bridge (`tools/jira`) for tracker operations. The `partial` qualifier means this tool implements named contract operations but does not satisfy the complete contract and must not be counted as a complete/selectable backend. Broader linked Jira coverage and the remaining pull-request coverage are incomplete. | +| [`tools/bitbucket`](../tools/bitbucket/) | `contract:change-request` + `contract:tracker` | Coverage: `partial`. Bitbucket Cloud and Bitbucket Data Center bridge foundation for repository metadata context, branch restriction context for PR-management decisions, pull-request discovery/fetching, read-only commit fetching, read-only diff fetching, comments-only discussion fetching, read-only review-state fetching, Cloud-only pull-request task listing/fetching, read-only merge-check context fetching, and read-only status fetching, plus narrowly scoped pull-request comment creation on Cloud and Data Center and Cloud-only write actions: `pr review` (with a `comment`, `approve`, or `request-changes` verdict), approve/unapprove, request-changes/remove-request-changes, decline, reject, and `pr merge` (with `pr merge-task-status` to follow an asynchronous merge). Native Bitbucket issue operations are not implemented: Atlassian removed the native Bitbucket Cloud Issue Tracker API on 2026-08-20 and Data Center native issues were never supported, so the historical issue CLI surface fails closed before any request. Data Center `pr jira-issues ` provides read-only discovery of Jira keys associated with pull-request commits and hands them to the Jira bridge (`tools/jira`) for tracker operations. The `partial` qualifier means this tool implements named contract operations but does not satisfy the complete contract and must not be counted as a complete/selectable backend. Broader linked Jira coverage and the remaining pull-request coverage are incomplete. | | [`tools/forgejo`](../tools/forgejo/) | `contract:tracker` + `contract:source-control` + `contract:change-request` | Coverage: `partial`. Forgejo / Gitea REST API and `tea` CLI forge bridge foundation for issue listing/fetching, confirmed issue creation, body edits, comments, labels, and milestones under `contract:tracker`, git-backed branch/commit/push operations under `contract:source-control`, and pull-request creation via REST API / compare URL and label edits under `contract:change-request`. Project boards are unsupported (`no-op`) due to absence of REST card/column endpoints. The `partial` qualifier means this tool implements named contract operations but does not satisfy the complete contract and must not be counted as a complete/selectable backend. | | [`tools/fossil`](../tools/fossil/) | `contract:tracker` + `contract:source-control` | Fossil SCM forge bridge: integrates local SQLite-backed ticket tracking, wiki, and forum reads with the version-control shim | | [`tools/github`](../tools/github/) | `contract:tracker` + `contract:source-control` + `contract:change-request` + `contract:people` | GitHub REST / GraphQL tracker substrate (called by every lifecycle phase) plus the Git source-control binding documented in [`source-control.md`](../tools/github/source-control.md) (runnable backend in [`tools/vcs`](../tools/vcs/)), the pull-request review/merge gate (`change-request`; the ASF default backend, alongside `tools/jira-patch/` and `tools/mail-patch/` for SVN-first projects), and account profiles / collaborators / team membership (`people`) | diff --git a/docs/modes.md b/docs/modes.md index d5700d72f..09b21c3dd 100644 --- a/docs/modes.md +++ b/docs/modes.md @@ -311,6 +311,8 @@ contributor threads on their own. The always-on `setup` and | [`setup-isolated-setup-doctor`](../skills/setup-isolated-setup-doctor/SKILL.md) | In-session functional health check of the secure-agent sandbox: probes SSH agent / Yubikey reachability, localhost port access, and filesystem restrictions. | | [`setup-status`](../skills/setup-status/SKILL.md) | Render a Markdown adoption dashboard: install method and pin, drift, and which skills are wired in the current repo. | | [`setup-welcome-guide`](../skills/setup-welcome-guide/SKILL.md) | Show a Magpie welcome guide on demand — the general one or a family's — and turn a dismissed one back on. | +| [`setup-complete-upgrade`](../skills/setup-complete-upgrade/SKILL.md) | Finish a Magpie upgrade in one run: check this machine and project against the installed version, apply one approved plan, re-check, and print exact commands for what is out of reach. | +| [`setup-privacy-llm`](../skills/setup-privacy-llm/SKILL.md) | Decide which LLMs may see this project's private foundation content, write `privacy-llm.md`, and prove it with the approved-model gate and the PII redactor. | | [`committer-onboarding`](../skills/committer-onboarding/SKILL.md) | Post-vote committer and PMC onboarding for Apache projects: walks the nominator through every step from ICLA check to welcome announcement for both podlings and TLPs. | | [`security-tracker-stats-dashboard`](../skills/security-tracker-stats-dashboard/SKILL.md) | Generate a self-contained HTML dashboard of `` statistics (lifecycle-band breakdowns, time-to-triage trends, velocity) without modifying any tracker state. | | [`optimize-skill`](../skills/optimize-skill/SKILL.md) | Optimize an existing framework skill by applying restructuring patterns: split oversized SKILL.md into linked sibling docs, trim frontmatter, improve eval alignment. | diff --git a/docs/security/README.md b/docs/security/README.md index 87af851a1..abf27ded6 100644 --- a/docs/security/README.md +++ b/docs/security/README.md @@ -33,9 +33,9 @@ End-to-end automation for an ASF project's security-issue handling process — from inbound report on the project's `security@` mailing list through to a published CVE record on `cve.org`. Eleven skills that compose into the canonical 16-step lifecycle, three that produce, -verify, and maintain the project's own security model, plus one -read-only supporting skill for tracker-stats dashboards (fifteen skills -total). +verify, and maintain the project's own security model, one that carries +that model into an OSS Scanner enrolment, plus one read-only supporting +skill for tracker-stats dashboards (sixteen skills total). Why a framework skill family? The 16-step process exists across the foundation; every project's security team runs essentially @@ -204,9 +204,10 @@ below sends, merges, or posts anything without you confirming it.* ### Security-model skills -The lifecycle skills above route **one report**. These three maintain the -document they route it against — the project's security model — so that -routing has something to cite. See +The lifecycle skills above route **one report**. These four work on the +document they route it against — the project's security model: three +maintain it so that routing has something to cite, and one carries it into +an external scanner's enrolment. See [**`security-model-preparation.md`**](security-model-preparation.md) for the lifecycle and the rationale. @@ -215,6 +216,7 @@ the lifecycle and the rationale. | [`security-model-prepare`](../../skills/security-model-prepare/SKILL.md) | Produce a first model for a project that has none, in draft-first mode, and land it with its discoverability chain as one PR per repository. | | [`security-model-verify`](../../skills/security-model-verify/SKILL.md) | Pre-flight an existing model: can an agent mechanically reach it, and does it cover the minimum bar a triager depends on. Discoverability is the only hard gate. | | [`security-model-update`](../../skills/security-model-update/SKILL.md) | Read the decision history back into the model — new known-non-finding entries and a model-gap list, regression-checked against past valid reports. | +| [`security-submit-to-oss-scan`](../../skills/security-submit-to-oss-scan/SKILL.md) | Prepare the enrolment (or update) PR that puts a project into Anthropic's OSS Scanner — `project.yaml`, an offline-capable `Dockerfile`, and a `threat_model.md` derived from the security model — and guide the maintainer through testing it first. | The rubric these skills measure against is maintained externally by Alpha-Omega () and diff --git a/docs/setup/README.md b/docs/setup/README.md index b11dd57de..afe0d199b 100644 --- a/docs/setup/README.md +++ b/docs/setup/README.md @@ -158,6 +158,7 @@ for the complete rule. | [`setup-privacy-llm`](../../skills/setup-privacy-llm/SKILL.md) | Configure which LLMs may see this project's private foundation mail, then prove it: detect the stack, write `privacy-llm.md` from the matching variant, and run the approved-LLM gate and the PII redactor end to end. | | [`setup`](../../skills/setup/SKILL.md) | Adopt and maintain the framework in a project repo through installation, verification, updates, overrides, and unadoption. | | [`setup upgrade`](../../skills/setup/upgrade.md) | Pull the framework checkout to latest `origin/main`. | +| [`setup-complete-upgrade`](../../skills/setup-complete-upgrade/SKILL.md) | Finish a Magpie upgrade in one run: check this machine and project against the installed version, apply one approved plan, re-check, and print exact commands for what is out of reach. | | [`setup verify`](../../skills/setup/verify.md) | Verify the framework is integrated correctly into an adopter tracker. | | [`setup-status`](../../skills/setup-status/SKILL.md) | Render a Markdown adoption dashboard (install pin, drift, wired agent targets, installed skill families, symlink health) and adjust the wiring in place. | | [`setup-shared-config-sync`](../../skills/setup-shared-config-sync/SKILL.md) | Commit + push the user's shared Claude config to its sync repo. | diff --git a/docs/setup/sandbox-troubleshooting.md b/docs/setup/sandbox-troubleshooting.md index 9a98826c5..57f8a3626 100644 --- a/docs/setup/sandbox-troubleshooting.md +++ b/docs/setup/sandbox-troubleshooting.md @@ -704,7 +704,7 @@ See [Container gateway](secure-agent-setup.md#container-gateway) in the setup gu |---|---|---| | `failed to read identity "…/machine/machine": operation not permitted` | `CONTAINER_HOST` / `DOCKER_HOST` are unset, so the CLI fell back to its default connection instead of the gateway | Add the reference `env` block below to `.claude/settings.local.json` | | `dial unix /.//.apache-magpie-local/run/podman.sock` — note the leading `/.//` | `CONTAINER_HOST` / `DOCKER_HOST` use a project-relative `unix://./…` value, which the CLIs do **not** resolve against the cwd | Use the absolute `unix:////…` spelling in the `env` block below | -| `dial unix //podman.sock: connect: no such file or directory` | The gateway is not running for this project. It exits after its idle timeout (4 h), when another session on the project ends, or when it crashes; the `PreToolUse` `ensure` hook restarts it before the next container command, so this error means that hook is not wired or could not start it | Wire the `ensure` hook per [Container gateway](secure-agent-setup.md#container-gateway), run `~/.claude/scripts/container-gateway-hook.sh start` from a terminal, or check `/container-gateway.log` for why it did not start | +| `dial unix //podman.sock: connect: no such file or directory` | The gateway is not running for this project. It exits after its idle timeout (4 h), when another session on the project ends, or when it crashes; the `PreToolUse` `ensure` hook restarts it before the next container command, so this error means that hook is not wired or could not start it | Wire the `ensure` hook per [Container gateway](secure-agent-setup.md#container-gateway), run `~/.claude/scripts/container-gateway-hook.sh start /container-gateway.log` for why it did not start | | `dial unix //podman.sock: connect: operation not permitted` | The gateway is running but its socket is missing from `sandbox.network.allowUnixSockets` | Add both gateway sockets as absolute paths, per [Container gateway](secure-agent-setup.md#container-gateway) | | `no podman or docker backend found; nothing to serve` in the gateway log, while `podman` works by hand | On macOS the gateway asked `podman machine inspect` for the socket path, and that command renders it from the **caller's** `TMPDIR` | Update the framework: discovery now also probes `getconf DARWIN_USER_TEMP_DIR`/`podman/`, so a hook whose `TMPDIR` differs from the machine's still finds the socket | diff --git a/docs/setup/secure-agent-setup.md b/docs/setup/secure-agent-setup.md index 3e961b92c..c98c5b646 100644 --- a/docs/setup/secure-agent-setup.md +++ b/docs/setup/secure-agent-setup.md @@ -378,7 +378,7 @@ sandbox flags don't depend on a specific bubblewrap version (the `denyRead`/`allowRead` API has been stable since `0.6.x`). The framework's `tools/agent-isolation/check-tool-updates.sh` will -still report upstream `0.13.0` / `1.8.1.3` as the pinned versions — +still report upstream `0.13.1` / `1.8.1.3` as the pinned versions — that's the manifest's view of what's *upstream-current*, not what your distro shipped. If you want to silence the drift, override the manifest locally with a `pinned-versions.local.toml` (gitignored) @@ -1051,7 +1051,7 @@ uv tool upgrade --all --reinstall The old `~/.cache/uv/` stays as the sandbox's cache; the host never reads it again. -**prek has the same problem.** The git hooks of a commit you make in a terminal run prek outside the sandbox, from hook environments under its home: `~/.cache/prek/` by default, which the `~/.cache/` grant makes sandbox-writable. Nothing excluded from the sandbox runs prek, so the settings `env` (which only Claude Code's own commands see, never your terminal) does the split: `"PREK_HOME": "~/.cache/prek-sandbox"` gives sandboxed prek a home of its own, and `Edit(~/.cache/prek/**)` keeps sandboxed commands out of the terminal's. prek expands the `~`. The first sandboxed `prek run` after the switch rebuilds its hook environments there once. `sandbox-lint` fails a settings file whose `PREK_HOME` is missing or overlaps `~/.cache/prek`. The same split applies to every hook manager with a home in the [hook-manager registry](../../tools/hook-manager/registry.json); see the [contract](../../tools/hook-manager/README.md#home). +**prek has the same problem.** The git hooks of a commit you make in a terminal run prek outside the sandbox, from hook environments under its home: `~/.cache/prek/` by default, which the `~/.cache/` grant makes sandbox-writable. Nothing excluded from the sandbox runs prek, so the settings `env` (which only Claude Code's own commands see, never your terminal) does the split: `"PREK_HOME": "~/.cache/prek-sandbox"` gives sandboxed prek a home of its own, and `Edit(~/.cache/prek/**)` keeps sandboxed commands out of the terminal's. prek expands the `~`. The first sandboxed `prek run` after the switch rebuilds its hook environments there once. When the project uses prek (a prek config at its root, or an installed git hook that runs prek), `sandbox-lint` fails a settings file whose `PREK_HOME` is missing or overlaps `~/.cache/prek`; with no project to inspect, it assumes prek is in use. The same split applies to every hook manager with a home in the [hook-manager registry](../../tools/hook-manager/registry.json); see the [contract](../../tools/hook-manager/README.md#home). The `env` also reaches a command Claude Code runs *outside* the sandbox (an approved bypass, often a signed commit). The whole-user [git-hook dispatcher](#whole-user-with-the-per-repo-dispatcher) covers that: a hook it runs with no `SANDBOX_RUNTIME` in the environment gets `PREK_HOME=~/.local/share/prek-host` and a host-only `XDG_CACHE_HOME` (for the pip, go, npm and uv caches the hooks use), whatever the env said. It only runs when git reaches it: a repository-level `core.hooksPath` (some `prek install` runs set one) overrides the global one and skips the dispatcher. magpie-setup's session-start hook removes one that points at the repository's own `.git/hooks` (redundant, since the dispatcher chains there anyway) and says so; any other value is reported, and `setup-isolated-setup-verify` flags it. With per-project scope there is no dispatcher, so do not bypass the sandbox for a commit there. diff --git a/plugins/magpie-agent-guard/tools/agent-guard/src/agent_guard/__init__.py b/plugins/magpie-agent-guard/tools/agent-guard/src/agent_guard/__init__.py index 60fa91060..a7fc0e580 100644 --- a/plugins/magpie-agent-guard/tools/agent-guard/src/agent_guard/__init__.py +++ b/plugins/magpie-agent-guard/tools/agent-guard/src/agent_guard/__init__.py @@ -79,9 +79,11 @@ file that defines a module-level ``guard(ctx)`` returning a deny string or ``None`` into any discovered guard directory — see ``GuardContext`` and ``guards.d/no_verify_commit.py`` for the template. Three sources are discovered, -in this order: every dir in ``$MAGPIE_GUARD_DIRS``, every -``skills//guards`` in the framework tree this file is running from, and -the ``guards.d`` sibling of this file. A skill therefore owns its guards in its +in this order: every dir in ``$MAGPIE_GUARD_DIRS``; every +``plugins//skills//guards`` and ``skills//guards`` in the +framework tree this file is running from, or, from a marketplace install, the +skill guards of the sibling family plugins; and the ``guards.d`` sibling of this +file. A skill therefore owns its guards in its own directory and they take effect as soon as the framework is installed — nothing collects, copies, or syncs them. """ diff --git a/plugins/magpie-repo-health/skills/workflow-optimization/SKILL.md b/plugins/magpie-repo-health/skills/workflow-optimization/SKILL.md index b7679ff13..18e819899 100644 --- a/plugins/magpie-repo-health/skills/workflow-optimization/SKILL.md +++ b/plugins/magpie-repo-health/skills/workflow-optimization/SKILL.md @@ -18,7 +18,7 @@ argument-hint: "--repo owner/name" capability: capability:triage surface_hash: sha256:bbfe83b236640f9e license: Apache-2.0 -measured_tokens: 3094 +measured_tokens: 3091 --- # workflow-optimization diff --git a/plugins/magpie-security-tools/tools/cve-tool-vulnogram/generate-cve-json/README.md b/plugins/magpie-security-tools/tools/cve-tool-vulnogram/generate-cve-json/README.md index d7bc7545c..6b1dc7127 100644 --- a/plugins/magpie-security-tools/tools/cve-tool-vulnogram/generate-cve-json/README.md +++ b/plugins/magpie-security-tools/tools/cve-tool-vulnogram/generate-cve-json/README.md @@ -56,7 +56,7 @@ placeholder so the path resolves in either context: uv run --project /tools/cve-tool-vulnogram/generate-cve-json generate-cve-json ``` -`` substitutes to `.apache-magpie/apache-magpie` in +`` substitutes to `.apache-magpie/` in adopting projects and to `.` (the repository root) in framework standalone — see the placeholder convention in [`AGENTS.md`](https://github.com/apache/magpie/blob/main/AGENTS.md#placeholder-convention-used-in-skill-files). diff --git a/plugins/magpie-security-tools/tools/cve-tool-vulnogram/generate-cve-json/src/generate_cve_json/layers.py b/plugins/magpie-security-tools/tools/cve-tool-vulnogram/generate-cve-json/src/generate_cve_json/layers.py index 679ce3721..46278ffa8 100644 --- a/plugins/magpie-security-tools/tools/cve-tool-vulnogram/generate-cve-json/src/generate_cve_json/layers.py +++ b/plugins/magpie-security-tools/tools/cve-tool-vulnogram/generate-cve-json/src/generate_cve_json/layers.py @@ -26,9 +26,11 @@ * Adopted repository (a committed `.apache-magpie.lock`): the personal layer is `/.apache-magpie-local/`. * Not adopted: it is `/apache-magpie/` — inside the git - directory, never the working tree, shared by every worktree. Outside a - git repository there is none. A legacy in-tree `.apache-magpie-local/` - is still read after it. + directory, never the working tree, shared by every worktree. In a + Subversion working copy it is `<.svn>/apache-magpie/` for the same + reasons. With no version control at all there is nothing it could be + committed to, so it is the in-tree `/.apache-magpie-local/`. A + legacy in-tree `.apache-magpie-local/` is still read after it. * A linked worktree of an adopted repository falls back to its main checkout's `.apache-magpie-local/`, file by file (`main_worktree`). * The committed layer, `/.apache-magpie-overrides/`, comes last. diff --git a/plugins/magpie-security-tools/tools/cve-tool-vulnogram/oauth-api/README.md b/plugins/magpie-security-tools/tools/cve-tool-vulnogram/oauth-api/README.md index fcd92873a..16e4b3441 100644 --- a/plugins/magpie-security-tools/tools/cve-tool-vulnogram/oauth-api/README.md +++ b/plugins/magpie-security-tools/tools/cve-tool-vulnogram/oauth-api/README.md @@ -34,7 +34,7 @@ Console scripts: |---|---| | `vulnogram-api-setup` | Interactive token capture — approved in your browser via `--pmc ` (recommended) or copied from `/users/token` and pasted back. | | `vulnogram-api-record-update` | POST a CVE JSON to `/cve5/` (the upsert endpoint). Replaces the release-manager copy-paste-into-`#source` step. | -| `vulnogram-api-record-publish` | Move a record `REVIEW` → `PUBLIC` by re-POSTing it with the new `CNA_private.state`. | +| `vulnogram-api-record-publish` | Move a record `REVIEW` → `PUBLIC` by re-POSTing it with the new `CNA_private.state`. Refuses (exit 4) a record with no `references[]` entry tagged `vendor-advisory`; `--allow-state` accepts only `REVIEW` or `READY` and replaces the `REVIEW` default (repeat it to accept both). | | `vulnogram-api-record-fetch` | Read a record back — full stored JSON, or just `CNA_private.state` (`--state-only`), or just the reviewer-comment array (`--comments-only`). Read-only; never POSTs. | | `vulnogram-api-check` | Probe the stored token and report `valid` / `expired` / `not-configured`. Used by the agentic skills before proposing the API path. `--server` checks whether the Vulnogram supports browser-approved tokens and JSON allocation; `--allocate` checks the allocate token. | | `vulnogram-api-allocate` | Reserve a CVE ID through `/allocatecve` with an allocate token, without opening the form. Prints the bare `CVE-YYYY-NNNNN`. | @@ -70,7 +70,7 @@ uv run --project /tools/cve-tool-vulnogram/oauth-api vulnogram-api-re --json-file ``` -`` substitutes to `.apache-magpie/apache-magpie` in +`` substitutes to `.apache-magpie/` in adopting projects and to `.` in framework standalone — see the placeholder convention in [`AGENTS.md`](https://github.com/apache/magpie/blob/main/AGENTS.md#placeholder-convention-used-in-skill-files). diff --git a/plugins/magpie-security-tools/tools/gmail/oauth-draft/README.md b/plugins/magpie-security-tools/tools/gmail/oauth-draft/README.md index b0ed082a4..f3f54aee7 100644 --- a/plugins/magpie-security-tools/tools/gmail/oauth-draft/README.md +++ b/plugins/magpie-security-tools/tools/gmail/oauth-draft/README.md @@ -77,7 +77,7 @@ Skill files and framework docs reference the same invocation via the uv run --project /tools/gmail/oauth-draft oauth-draft-create ... ``` -`` substitutes to `.apache-magpie/apache-magpie` in +`` substitutes to `.apache-magpie/` in adopting projects and to `.` (the repository root) in framework standalone — see the placeholder convention in [`AGENTS.md`](https://github.com/apache/magpie/blob/main/AGENTS.md#placeholder-convention-used-in-skill-files). diff --git a/plugins/magpie-security-tools/tools/privacy-llm/checker/README.md b/plugins/magpie-security-tools/tools/privacy-llm/checker/README.md index fd55c0a59..fab81520e 100644 --- a/plugins/magpie-security-tools/tools/privacy-llm/checker/README.md +++ b/plugins/magpie-security-tools/tools/privacy-llm/checker/README.md @@ -76,7 +76,7 @@ uv run --project /tools/privacy-llm/checker privacy-llm-check ... ``` `` substitutes to the snapshot path inside an adopting -project (typically `.apache-magpie/apache-magpie/`) and to `.` +project (typically `.apache-magpie/`) and to `.` when running standalone — see the placeholder convention in [`AGENTS.md`](https://github.com/apache/magpie/blob/main/AGENTS.md#placeholder-convention-used-in-skill-files). diff --git a/plugins/magpie-security-tools/tools/privacy-llm/checker/src/checker/layers.py b/plugins/magpie-security-tools/tools/privacy-llm/checker/src/checker/layers.py index 679ce3721..46278ffa8 100644 --- a/plugins/magpie-security-tools/tools/privacy-llm/checker/src/checker/layers.py +++ b/plugins/magpie-security-tools/tools/privacy-llm/checker/src/checker/layers.py @@ -26,9 +26,11 @@ * Adopted repository (a committed `.apache-magpie.lock`): the personal layer is `/.apache-magpie-local/`. * Not adopted: it is `/apache-magpie/` — inside the git - directory, never the working tree, shared by every worktree. Outside a - git repository there is none. A legacy in-tree `.apache-magpie-local/` - is still read after it. + directory, never the working tree, shared by every worktree. In a + Subversion working copy it is `<.svn>/apache-magpie/` for the same + reasons. With no version control at all there is nothing it could be + committed to, so it is the in-tree `/.apache-magpie-local/`. A + legacy in-tree `.apache-magpie-local/` is still read after it. * A linked worktree of an adopted repository falls back to its main checkout's `.apache-magpie-local/`, file by file (`main_worktree`). * The committed layer, `/.apache-magpie-overrides/`, comes last. diff --git a/plugins/magpie-security/skills/issue-fix/outcomes/preflight.md b/plugins/magpie-security/skills/issue-fix/outcomes/preflight.md index b1a6d085e..aa6914b04 100644 --- a/plugins/magpie-security/skills/issue-fix/outcomes/preflight.md +++ b/plugins/magpie-security/skills/issue-fix/outcomes/preflight.md @@ -10,7 +10,7 @@ Relative links are rooted one level deeper than in `SKILL.md`. A 401/403 on the first means no `` access; on the second it is a quota/auth issue — both need user action, stop. 2. **Fork exists and is pushable** — `gh repo view / --json name --jq .name` returns the bare repo name (the segment after the `/` in ``). If there is no fork, tell the user to run `gh repo fork --clone=false` and re-invoke. -3. **Local clone is found and clean** — resolve the clone path from [the resolved `user.md` ([order](../../../../../AGENTS.md#usermd-resolution-order))](../../../../../docs/setup/agentic-overrides.md) → `environment.upstream_clone` (per [`AGENTS.md` § Per-project and per-user configuration](../../../../../AGENTS.md#per-project-and-per-user-configuration)). +3. **Local clone is found and clean** — resolve the clone path from the resolved [`user.md`](../../../../../docs/setup/agentic-overrides.md) ([order](../../../../../AGENTS.md#usermd-resolution-order)) → `environment.upstream_clone` (per [`AGENTS.md` § Per-project and per-user configuration](../../../../../AGENTS.md#per-project-and-per-user-configuration)). Verify its `origin` remote points at `` and `git status --porcelain` is empty. On uncommitted work, stop and ask the user to stash / commit / clean first. Do not probe hard-coded filesystem paths. diff --git a/plugins/magpie-security/skills/issue-sync/apply-and-push.md b/plugins/magpie-security/skills/issue-sync/apply-and-push.md index cc63d9783..b3faef720 100644 --- a/plugins/magpie-security/skills/issue-sync/apply-and-push.md +++ b/plugins/magpie-security/skills/issue-sync/apply-and-push.md @@ -158,7 +158,7 @@ Use: [`vulnogram-api-record-publish`](../../../../tools/cve-tool-vulnogram/oauth-api/README.md) CLI to flip the record's `CNA_private.state` over the OAuth API. It refuses the transition unless the current state is `REVIEW` and the record already lists the archived advisory URL as a `vendor-advisory` reference (re-push the CVE JSON after capturing the URL, before this step); - `--allow-state READY` also accepts a record moved to `READY` manually, and no earlier state can be published: + `--allow-state REVIEW --allow-state READY` also accepts a record moved to `READY` manually, and no earlier state can be published: ```bash uv run --project /tools/cve-tool-vulnogram/oauth-api \ diff --git a/plugins/magpie-security/skills/submit-to-oss-scan/SKILL.md b/plugins/magpie-security/skills/submit-to-oss-scan/SKILL.md index 6624c52b9..9014daf9d 100644 --- a/plugins/magpie-security/skills/submit-to-oss-scan/SKILL.md +++ b/plugins/magpie-security/skills/submit-to-oss-scan/SKILL.md @@ -20,7 +20,7 @@ argument-hint: "[enrol | update] [project-name]" capability: capability:authoring surface_hash: sha256:cefbd533dc1009f2 license: Apache-2.0 -measured_tokens: 4996 +measured_tokens: 4993 --- # submit-to-oss-scan diff --git a/plugins/magpie-setup/hooks/check-upgrade.sh b/plugins/magpie-setup/hooks/check-upgrade.sh index e2af84e98..e567b90d7 100755 --- a/plugins/magpie-setup/hooks/check-upgrade.sh +++ b/plugins/magpie-setup/hooks/check-upgrade.sh @@ -5,7 +5,7 @@ # Session-start hook for the Apache Magpie plugin. Wired by the Claude Code # plugin (SessionStart) and by the Codex CLI plugin, which uses the same event # schema. Agent Plugins 1.0 defines no hook component, so an AP1-only client -# does not run this at all — see docs/setup/marketplaces.md. +# does not run this at all — see docs/setup/marketplace.md. # # Also warns, once per session, when the isolated setup is not configured on # this machine (see `setup_preflight.isolated.session_start`). diff --git a/plugins/magpie-setup/skills/setup/setup_preflight/isolated_fingerprint.py b/plugins/magpie-setup/skills/setup/setup_preflight/isolated_fingerprint.py index ef2046922..4aaec5b47 100644 --- a/plugins/magpie-setup/skills/setup/setup_preflight/isolated_fingerprint.py +++ b/plugins/magpie-setup/skills/setup/setup_preflight/isolated_fingerprint.py @@ -21,4 +21,4 @@ for installs that do not carry the framework source (see `isolated.py`). """ -FRAMEWORK_FINGERPRINT = "sha256:dd8b20fc597eabae" +FRAMEWORK_FINGERPRINT = "sha256:b45b2c81a7f1bd64" diff --git a/plugins/magpie-utilities/skills/list-skills/SKILL.md b/plugins/magpie-utilities/skills/list-skills/SKILL.md index af87897be..54763407f 100644 --- a/plugins/magpie-utilities/skills/list-skills/SKILL.md +++ b/plugins/magpie-utilities/skills/list-skills/SKILL.md @@ -21,7 +21,7 @@ when_to_use: | capability: capability:stats surface_hash: sha256:5b9c9751b398f81b license: Apache-2.0 -measured_tokens: 2370 +measured_tokens: 2367 --- # list-skills diff --git a/plugins/magpie-utilities/skills/optimize-skill/SKILL.md b/plugins/magpie-utilities/skills/optimize-skill/SKILL.md index e8b92060a..40faf2a7d 100644 --- a/plugins/magpie-utilities/skills/optimize-skill/SKILL.md +++ b/plugins/magpie-utilities/skills/optimize-skill/SKILL.md @@ -15,7 +15,7 @@ when_to_use: >- capability: capability:authoring surface_hash: sha256:be9968c266788028 license: Apache-2.0 -measured_tokens: 3394 +measured_tokens: 3391 --- # optimize-skill diff --git a/plugins/magpie-utilities/skills/report-framework-issue/SKILL.md b/plugins/magpie-utilities/skills/report-framework-issue/SKILL.md index 58a02d401..8c6966f56 100644 --- a/plugins/magpie-utilities/skills/report-framework-issue/SKILL.md +++ b/plugins/magpie-utilities/skills/report-framework-issue/SKILL.md @@ -23,7 +23,7 @@ argument-hint: "[what broke, or a problem description]" capability: capability:platform surface_hash: sha256:f14640fa1249c172 license: Apache-2.0 -measured_tokens: 4661 +measured_tokens: 4658 --- # skill-reconciler diff --git a/plugins/magpie-utilities/skills/write-skill/SKILL.md b/plugins/magpie-utilities/skills/write-skill/SKILL.md index 3489520eb..d4226c0ef 100644 --- a/plugins/magpie-utilities/skills/write-skill/SKILL.md +++ b/plugins/magpie-utilities/skills/write-skill/SKILL.md @@ -17,7 +17,7 @@ when_to_use: >- capability: capability:authoring surface_hash: sha256:31626428a2545bce license: Apache-2.0 -measured_tokens: 2641 +measured_tokens: 2638 --- # write-skill diff --git a/plugins/magpie-utilities/skills/write-skill/scripts/init_skill.py b/plugins/magpie-utilities/skills/write-skill/scripts/init_skill.py index 16d27dbb7..fc0124e3a 100755 --- a/plugins/magpie-utilities/skills/write-skill/scripts/init_skill.py +++ b/plugins/magpie-utilities/skills/write-skill/scripts/init_skill.py @@ -89,7 +89,7 @@ → per file: the personal layer, else `.apache-magpie-overrides/` → value of `tracker_repo:` in /project.md → value of `upstream_repo:` in /project.md - → `.` standalone, `.apache-magpie/apache-magpie` (snapshot), + → `.` standalone, `.apache-magpie/` (snapshot), `~/.cache/apache-magpie/framework/current` (marketplace) --> # {name} diff --git a/plugins/magpie-vetted-ops/tools/vetted-ops/src/vetted_ops/layers.py b/plugins/magpie-vetted-ops/tools/vetted-ops/src/vetted_ops/layers.py index 679ce3721..46278ffa8 100644 --- a/plugins/magpie-vetted-ops/tools/vetted-ops/src/vetted_ops/layers.py +++ b/plugins/magpie-vetted-ops/tools/vetted-ops/src/vetted_ops/layers.py @@ -26,9 +26,11 @@ * Adopted repository (a committed `.apache-magpie.lock`): the personal layer is `/.apache-magpie-local/`. * Not adopted: it is `/apache-magpie/` — inside the git - directory, never the working tree, shared by every worktree. Outside a - git repository there is none. A legacy in-tree `.apache-magpie-local/` - is still read after it. + directory, never the working tree, shared by every worktree. In a + Subversion working copy it is `<.svn>/apache-magpie/` for the same + reasons. With no version control at all there is nothing it could be + committed to, so it is the in-tree `/.apache-magpie-local/`. A + legacy in-tree `.apache-magpie-local/` is still read after it. * A linked worktree of an adopted repository falls back to its main checkout's `.apache-magpie-local/`, file by file (`main_worktree`). * The committed layer, `/.apache-magpie-overrides/`, comes last. diff --git a/tools/adversarial-review/src/adversarial_review/layers.py b/tools/adversarial-review/src/adversarial_review/layers.py index 679ce3721..46278ffa8 100644 --- a/tools/adversarial-review/src/adversarial_review/layers.py +++ b/tools/adversarial-review/src/adversarial_review/layers.py @@ -26,9 +26,11 @@ * Adopted repository (a committed `.apache-magpie.lock`): the personal layer is `/.apache-magpie-local/`. * Not adopted: it is `/apache-magpie/` — inside the git - directory, never the working tree, shared by every worktree. Outside a - git repository there is none. A legacy in-tree `.apache-magpie-local/` - is still read after it. + directory, never the working tree, shared by every worktree. In a + Subversion working copy it is `<.svn>/apache-magpie/` for the same + reasons. With no version control at all there is nothing it could be + committed to, so it is the in-tree `/.apache-magpie-local/`. A + legacy in-tree `.apache-magpie-local/` is still read after it. * A linked worktree of an adopted repository falls back to its main checkout's `.apache-magpie-local/`, file by file (`main_worktree`). * The committed layer, `/.apache-magpie-overrides/`, comes last. diff --git a/tools/agent-guard/src/agent_guard/__init__.py b/tools/agent-guard/src/agent_guard/__init__.py index 60fa91060..a7fc0e580 100644 --- a/tools/agent-guard/src/agent_guard/__init__.py +++ b/tools/agent-guard/src/agent_guard/__init__.py @@ -79,9 +79,11 @@ file that defines a module-level ``guard(ctx)`` returning a deny string or ``None`` into any discovered guard directory — see ``GuardContext`` and ``guards.d/no_verify_commit.py`` for the template. Three sources are discovered, -in this order: every dir in ``$MAGPIE_GUARD_DIRS``, every -``skills//guards`` in the framework tree this file is running from, and -the ``guards.d`` sibling of this file. A skill therefore owns its guards in its +in this order: every dir in ``$MAGPIE_GUARD_DIRS``; every +``plugins//skills//guards`` and ``skills//guards`` in the +framework tree this file is running from, or, from a marketplace install, the +skill guards of the sibling family plugins; and the ``guards.d`` sibling of this +file. A skill therefore owns its guards in its own directory and they take effect as soon as the framework is installed — nothing collects, copies, or syncs them. """ diff --git a/tools/agent-isolation/container-gateway-hook.sh b/tools/agent-isolation/container-gateway-hook.sh index cfca273bc..3c3834b09 100755 --- a/tools/agent-isolation/container-gateway-hook.sh +++ b/tools/agent-isolation/container-gateway-hook.sh @@ -149,9 +149,9 @@ log() { printf '%s: %s\n' "${0##*/}" "$*" >&2; } git() { command git -c safe.bareRepository=explicit "$@"; } payload="$(cat 2>/dev/null || true)" -# `ensure` runs before every Bash command the hook's `if` filter lets through, -# and that filter is best-effort: anything not naming docker or podman leaves -# here, before any of the checks below. The word may follow a path or an +# `ensure` runs before every Bash command, with no filter in the hook wiring: +# this word check is the only one, so anything not naming docker or podman +# leaves here, before any of the checks below. The word may follow a path or an # operator (`/usr/local/bin/docker`, `cd x && podman run`). if [[ $action == ensure ]]; then command_line="$(printf '%s' "$payload" | jq -r '.tool_input.command // empty' 2>/dev/null || true)" diff --git a/tools/container-gateway/src/container_gateway/layers.py b/tools/container-gateway/src/container_gateway/layers.py index b71dce216..3eeedccb6 100644 --- a/tools/container-gateway/src/container_gateway/layers.py +++ b/tools/container-gateway/src/container_gateway/layers.py @@ -26,9 +26,11 @@ * Adopted repository (a committed `.apache-magpie.lock`): the personal layer is `/.apache-magpie-local/`. * Not adopted: it is `/apache-magpie/` — inside the git - directory, never the working tree, shared by every worktree. Outside a - git repository there is none. A legacy in-tree `.apache-magpie-local/` - is still read after it. + directory, never the working tree, shared by every worktree. In a + Subversion working copy it is `<.svn>/apache-magpie/` for the same + reasons. With no version control at all there is nothing it could be + committed to, so it is the in-tree `/.apache-magpie-local/`. A + legacy in-tree `.apache-magpie-local/` is still read after it. * A linked worktree of an adopted repository falls back to its main checkout's `.apache-magpie-local/`, file by file (`main_worktree`). * The committed layer, `/.apache-magpie-overrides/`, comes last. diff --git a/tools/cve-tool-vulnogram/generate-cve-json/README.md b/tools/cve-tool-vulnogram/generate-cve-json/README.md index 4e23445a0..85df4a1c5 100644 --- a/tools/cve-tool-vulnogram/generate-cve-json/README.md +++ b/tools/cve-tool-vulnogram/generate-cve-json/README.md @@ -56,7 +56,7 @@ placeholder so the path resolves in either context: uv run --project /tools/cve-tool-vulnogram/generate-cve-json generate-cve-json ``` -`` substitutes to `.apache-magpie/apache-magpie` in +`` substitutes to `.apache-magpie/` in adopting projects and to `.` (the repository root) in framework standalone — see the placeholder convention in [`AGENTS.md`](../../../AGENTS.md#placeholder-convention-used-in-skill-files). diff --git a/tools/cve-tool-vulnogram/generate-cve-json/src/generate_cve_json/layers.py b/tools/cve-tool-vulnogram/generate-cve-json/src/generate_cve_json/layers.py index 679ce3721..46278ffa8 100644 --- a/tools/cve-tool-vulnogram/generate-cve-json/src/generate_cve_json/layers.py +++ b/tools/cve-tool-vulnogram/generate-cve-json/src/generate_cve_json/layers.py @@ -26,9 +26,11 @@ * Adopted repository (a committed `.apache-magpie.lock`): the personal layer is `/.apache-magpie-local/`. * Not adopted: it is `/apache-magpie/` — inside the git - directory, never the working tree, shared by every worktree. Outside a - git repository there is none. A legacy in-tree `.apache-magpie-local/` - is still read after it. + directory, never the working tree, shared by every worktree. In a + Subversion working copy it is `<.svn>/apache-magpie/` for the same + reasons. With no version control at all there is nothing it could be + committed to, so it is the in-tree `/.apache-magpie-local/`. A + legacy in-tree `.apache-magpie-local/` is still read after it. * A linked worktree of an adopted repository falls back to its main checkout's `.apache-magpie-local/`, file by file (`main_worktree`). * The committed layer, `/.apache-magpie-overrides/`, comes last. diff --git a/tools/cve-tool-vulnogram/oauth-api/README.md b/tools/cve-tool-vulnogram/oauth-api/README.md index 507cea850..b31669dfe 100644 --- a/tools/cve-tool-vulnogram/oauth-api/README.md +++ b/tools/cve-tool-vulnogram/oauth-api/README.md @@ -34,7 +34,7 @@ Console scripts: |---|---| | `vulnogram-api-setup` | Interactive token capture — approved in your browser via `--pmc ` (recommended) or copied from `/users/token` and pasted back. | | `vulnogram-api-record-update` | POST a CVE JSON to `/cve5/` (the upsert endpoint). Replaces the release-manager copy-paste-into-`#source` step. | -| `vulnogram-api-record-publish` | Move a record `REVIEW` → `PUBLIC` by re-POSTing it with the new `CNA_private.state`. | +| `vulnogram-api-record-publish` | Move a record `REVIEW` → `PUBLIC` by re-POSTing it with the new `CNA_private.state`. Refuses (exit 4) a record with no `references[]` entry tagged `vendor-advisory`; `--allow-state` accepts only `REVIEW` or `READY` and replaces the `REVIEW` default (repeat it to accept both). | | `vulnogram-api-record-fetch` | Read a record back — full stored JSON, or just `CNA_private.state` (`--state-only`), or just the reviewer-comment array (`--comments-only`). Read-only; never POSTs. | | `vulnogram-api-check` | Probe the stored token and report `valid` / `expired` / `not-configured`. Used by the agentic skills before proposing the API path. `--server` checks whether the Vulnogram supports browser-approved tokens and JSON allocation; `--allocate` checks the allocate token. | | `vulnogram-api-allocate` | Reserve a CVE ID through `/allocatecve` with an allocate token, without opening the form. Prints the bare `CVE-YYYY-NNNNN`. | @@ -70,7 +70,7 @@ uv run --project /tools/cve-tool-vulnogram/oauth-api vulnogram-api-re --json-file ``` -`` substitutes to `.apache-magpie/apache-magpie` in +`` substitutes to `.apache-magpie/` in adopting projects and to `.` in framework standalone — see the placeholder convention in [`AGENTS.md`](../../../AGENTS.md#placeholder-convention-used-in-skill-files). diff --git a/tools/cve-tool-vulnogram/record.md b/tools/cve-tool-vulnogram/record.md index e2da269e5..9f1c6dba2 100644 --- a/tools/cve-tool-vulnogram/record.md +++ b/tools/cve-tool-vulnogram/record.md @@ -103,6 +103,11 @@ which arrow you're crossing: the publish unless the current state is `REVIEW` (widen with `--allow-state` for the rare cases where the RM has already moved to `READY` manually). + `--allow-state` accepts only `REVIEW` or `READY` and replaces + the default rather than adding to it, so pass + `--allow-state REVIEW --allow-state READY` to accept both. + It also refuses (exit 4) a record with no `references[]` entry + tagged `vendor-advisory` — the archived advisory URL. ## `#source` paste flow diff --git a/tools/dev/check-family-plugins.py b/tools/dev/check-family-plugins.py index ebca98023..af4707d1d 100644 --- a/tools/dev/check-family-plugins.py +++ b/tools/dev/check-family-plugins.py @@ -71,7 +71,7 @@ "hooks": [ { "type": "command", - "command": "${CLAUDE_PLUGIN_ROOT}/hooks/check-upgrade.sh", + "command": '/bin/bash -p "${CLAUDE_PLUGIN_ROOT}/hooks/check-upgrade.sh"', "timeout": 10, } ], diff --git a/tools/dev/ci-pytest-batches.py b/tools/dev/ci-pytest-batches.py index f1282214c..8a5995d7a 100644 --- a/tools/dev/ci-pytest-batches.py +++ b/tools/dev/ci-pytest-batches.py @@ -20,8 +20,8 @@ A member gets pytest when it has a `[tool.pytest.ini_options]` section and does not opt out with `[tool.magpie.checks] skip = [..., "pytest"]` — the same rule as `tools/dev/run-workspace-check.sh`. On a pull request only the members with a -changed file other than Markdown (directly or through a symlinked source) are -picked, together with every member that depends on one of them, unless +changed file other than Markdown or a `.claude-plugin/` manifest (directly or +through a symlinked source) are picked, together with every member that depends on one of them, unless a shared build input changed; on any other event every member is. Most of a pytest job is setup (checkout, uv, a workspace sync), so the picked diff --git a/tools/gmail/oauth-draft/README.md b/tools/gmail/oauth-draft/README.md index b03bc9e7a..b0ec1db38 100644 --- a/tools/gmail/oauth-draft/README.md +++ b/tools/gmail/oauth-draft/README.md @@ -77,7 +77,7 @@ Skill files and framework docs reference the same invocation via the uv run --project /tools/gmail/oauth-draft oauth-draft-create ... ``` -`` substitutes to `.apache-magpie/apache-magpie` in +`` substitutes to `.apache-magpie/` in adopting projects and to `.` (the repository root) in framework standalone — see the placeholder convention in [`AGENTS.md`](../../../AGENTS.md#placeholder-convention-used-in-skill-files). diff --git a/tools/permission-audit/README.md b/tools/permission-audit/README.md index c3602e7aa..7ce1ebfdd 100644 --- a/tools/permission-audit/README.md +++ b/tools/permission-audit/README.md @@ -127,12 +127,18 @@ Stdlib-only runtime; the dev group adds `pytest`, `ruff`, `mypy`. ## CLI ```bash -permission-audit audit-any [--dir ] [--families security,issue] -permission-audit audit [--families security,issue] +permission-audit audit-any [--dir ] [--families security,issue] [--organization ASF] +permission-audit audit [--families security,issue] [--organization ASF] permission-audit apply [--add ]... [--remove ]... [--create-if-missing] permission-audit list-known ``` +`--organization` takes the project's `organization` from `project.md` +(default: none). +Recommendations specific to one organization — the ASF services, for +`ASF` — are added only when it names that organization; without it they +are dropped from `missing_recommended`. + ### `audit-any` (harness-neutral) Scans `` (default: `.`) for every known settings file and @@ -269,7 +275,8 @@ this tool is the engine behind it. The skill calls ```bash uv run --project /tools/permission-audit \ permission-audit audit /.claude/settings.local.json \ - --families + --families \ + --organization ``` for each of `.claude/settings.json` and `.claude/settings.local.json`, diff --git a/tools/pr-management/src/pr_management/layers.py b/tools/pr-management/src/pr_management/layers.py index 679ce3721..46278ffa8 100644 --- a/tools/pr-management/src/pr_management/layers.py +++ b/tools/pr-management/src/pr_management/layers.py @@ -26,9 +26,11 @@ * Adopted repository (a committed `.apache-magpie.lock`): the personal layer is `/.apache-magpie-local/`. * Not adopted: it is `/apache-magpie/` — inside the git - directory, never the working tree, shared by every worktree. Outside a - git repository there is none. A legacy in-tree `.apache-magpie-local/` - is still read after it. + directory, never the working tree, shared by every worktree. In a + Subversion working copy it is `<.svn>/apache-magpie/` for the same + reasons. With no version control at all there is nothing it could be + committed to, so it is the in-tree `/.apache-magpie-local/`. A + legacy in-tree `.apache-magpie-local/` is still read after it. * A linked worktree of an adopted repository falls back to its main checkout's `.apache-magpie-local/`, file by file (`main_worktree`). * The committed layer, `/.apache-magpie-overrides/`, comes last. diff --git a/tools/privacy-llm/checker/README.md b/tools/privacy-llm/checker/README.md index 4d76baae3..17e4485f1 100644 --- a/tools/privacy-llm/checker/README.md +++ b/tools/privacy-llm/checker/README.md @@ -76,7 +76,7 @@ uv run --project /tools/privacy-llm/checker privacy-llm-check ... ``` `` substitutes to the snapshot path inside an adopting -project (typically `.apache-magpie/apache-magpie/`) and to `.` +project (typically `.apache-magpie/`) and to `.` when running standalone — see the placeholder convention in [`AGENTS.md`](../../../AGENTS.md#placeholder-convention-used-in-skill-files). diff --git a/tools/privacy-llm/checker/src/checker/layers.py b/tools/privacy-llm/checker/src/checker/layers.py index 679ce3721..46278ffa8 100644 --- a/tools/privacy-llm/checker/src/checker/layers.py +++ b/tools/privacy-llm/checker/src/checker/layers.py @@ -26,9 +26,11 @@ * Adopted repository (a committed `.apache-magpie.lock`): the personal layer is `/.apache-magpie-local/`. * Not adopted: it is `/apache-magpie/` — inside the git - directory, never the working tree, shared by every worktree. Outside a - git repository there is none. A legacy in-tree `.apache-magpie-local/` - is still read after it. + directory, never the working tree, shared by every worktree. In a + Subversion working copy it is `<.svn>/apache-magpie/` for the same + reasons. With no version control at all there is nothing it could be + committed to, so it is the in-tree `/.apache-magpie-local/`. A + legacy in-tree `.apache-magpie-local/` is still read after it. * A linked worktree of an adopted repository falls back to its main checkout's `.apache-magpie-local/`, file by file (`main_worktree`). * The committed layer, `/.apache-magpie-overrides/`, comes last. diff --git a/tools/privacy-llm/redactor/README.md b/tools/privacy-llm/redactor/README.md index bc4c77b5e..2902d3ca3 100644 --- a/tools/privacy-llm/redactor/README.md +++ b/tools/privacy-llm/redactor/README.md @@ -80,7 +80,7 @@ uv run --project /tools/privacy-llm/redactor pii-redact ... ``` `` substitutes to the snapshot path inside an adopting -project (typically `.apache-magpie/apache-magpie/`) and to `.` +project (typically `.apache-magpie/`) and to `.` when running standalone — see the placeholder convention in [`AGENTS.md`](../../../AGENTS.md#placeholder-convention-used-in-skill-files). diff --git a/tools/release-config/src/release_config/layers.py b/tools/release-config/src/release_config/layers.py index 679ce3721..46278ffa8 100644 --- a/tools/release-config/src/release_config/layers.py +++ b/tools/release-config/src/release_config/layers.py @@ -26,9 +26,11 @@ * Adopted repository (a committed `.apache-magpie.lock`): the personal layer is `/.apache-magpie-local/`. * Not adopted: it is `/apache-magpie/` — inside the git - directory, never the working tree, shared by every worktree. Outside a - git repository there is none. A legacy in-tree `.apache-magpie-local/` - is still read after it. + directory, never the working tree, shared by every worktree. In a + Subversion working copy it is `<.svn>/apache-magpie/` for the same + reasons. With no version control at all there is nothing it could be + committed to, so it is the in-tree `/.apache-magpie-local/`. A + legacy in-tree `.apache-magpie-local/` is still read after it. * A linked worktree of an adopted repository falls back to its main checkout's `.apache-magpie-local/`, file by file (`main_worktree`). * The committed layer, `/.apache-magpie-overrides/`, comes last. diff --git a/tools/sandbox-lint/src/sandbox_lint/layers.py b/tools/sandbox-lint/src/sandbox_lint/layers.py index b71dce216..3eeedccb6 100644 --- a/tools/sandbox-lint/src/sandbox_lint/layers.py +++ b/tools/sandbox-lint/src/sandbox_lint/layers.py @@ -26,9 +26,11 @@ * Adopted repository (a committed `.apache-magpie.lock`): the personal layer is `/.apache-magpie-local/`. * Not adopted: it is `/apache-magpie/` — inside the git - directory, never the working tree, shared by every worktree. Outside a - git repository there is none. A legacy in-tree `.apache-magpie-local/` - is still read after it. + directory, never the working tree, shared by every worktree. In a + Subversion working copy it is `<.svn>/apache-magpie/` for the same + reasons. With no version control at all there is nothing it could be + committed to, so it is the in-tree `/.apache-magpie-local/`. A + legacy in-tree `.apache-magpie-local/` is still read after it. * A linked worktree of an adopted repository falls back to its main checkout's `.apache-magpie-local/`, file by file (`main_worktree`). * The committed layer, `/.apache-magpie-overrides/`, comes last. diff --git a/tools/skill-evals/README.md b/tools/skill-evals/README.md index 6ec7ffbe6..8b0b0b592 100644 --- a/tools/skill-evals/README.md +++ b/tools/skill-evals/README.md @@ -11,7 +11,7 @@ Behavioral eval harness for Apache Magpie skills. Each eval suite tests a skill Suites are currently implemented for: -- **setup** — 150 cases across 32 steps (step-verify-drift, step-overrides-surface, step-override-bypass, step-m3-baseline-pick, step-m4-install-gates, step-m5-no-repo-offer, step-m5-companion-offer, step-upgrade-companion-offer, step-adopt-settings-merge, verify-default-set, uninstall-default-set, lock-marketplace-parse, adopt-write-floor, setup-prefill-from-floor, preflight-floor, upgrade-adoption-split, verify-floor, adopt-review-process, adopt-security-list, step-reconcile, step-verify, step-config-stamp, step-config-adversarial, step-config-mail, step-adopt-stamp, step-upgrade-stamp, step-delegate-propose, config-vcs-backend, config-local-custom-parser) +- **setup** — 150 cases across 32 steps (step-verify-drift, step-overrides-surface, step-override-bypass, step-m3-baseline-pick, step-m4-install-gates, step-m5-no-repo-offer, step-m5-companion-offer, step-upgrade-companion-offer, step-adopt-settings-merge, verify-default-set, uninstall-default-set, lock-marketplace-parse, adopt-write-floor, setup-prefill-from-floor, preflight-floor, upgrade-adoption-split, verify-floor, adopt-review-process, adopt-security-list, step-reconcile, step-verify, step-config-stamp, step-config-adversarial, step-config-mail, step-adopt-stamp, step-upgrade-stamp, step-delegate-propose, config-vcs-backend, config-local-custom-parser, adopt-isolation-warning, step-vetted-ops-no-policy, step-unknown-subaction) - **setup-isolated-setup-install** — 19 cases across 5 steps (runtime-routing, step-snapshot-drift, step-scope-confirm, step-hardware-key, step-roborev-exclusion) - **setup-privacy-llm** — 6 cases across 2 steps (step-1-resolve, step-4-gate) - **setup-shared-config-sync** — 12 cases across 2 steps (step-3-decide-action, step-5-draft-commit) @@ -21,7 +21,7 @@ Suites are currently implemented for: - **security-issue-triage** — 19 cases across 6 steps (2, 2.5, 2.6, 3, 4, 6); Steps 1, 5 and 7 and the Step 6 bare-name scrub are decided and pytest-tested in `tools/security-management` - **security-issue-deduplicate** — 3 cases across 1 step (3, the merge inputs); Steps 1, 2, 3 (the merged body), 4, 5 and 6 are decided and pytest-tested in `tools/security-management` - **security-cve-allocate** — 3 cases across 1 step (4, the reporter draft); Steps 1, 2, 3, 4 (proposal and rollup), 5 and 7 are decided and pytest-tested in `tools/security-management` -- **security-issue-sync**: 44 cases across 9 steps (1d, 1f, 2a, 2b, 2c, 5b judged gates, handoff-delegate, D4 dashboard proposals); bulk selection and pre-flight, the buckets, Steps 3 and 6, the Guardrails check, the security CC, the drafting backend, the GHSA tier and the Step 5b flow are decided and pytest-tested in `tools/security-management` +- **security-issue-sync**: 44 cases across 9 steps (1d, 1f, 2a, 2b, 2c, 5b judged gates, handoff-delegate, D0 dashboard ASF-only gate, D4 dashboard proposals); bulk selection and pre-flight, the buckets, Steps 3 and 6, the Guardrails check, the security CC, the drafting backend, the GHSA tier and the Step 5b flow are decided and pytest-tested in `tools/security-management` - **security-issue-fix** — 31 cases across 8 steps (2, 3, 5b, 5d, 5g, 7, and Subversion steps 8 and 9); the flow choice, 5a, 5c, 5e, 5f, 6 and 11 are decided and pytest-tested in `tools/security-management` - **security-issue-invalidate** — 7 cases across 2 steps (3, 4); Steps 2, 5a, 5b, 5d, 5e, 5f and 7 are decided and pytest-tested in `tools/security-management` - **security-issue-import-from-md** — 7 cases across 4 steps (1, 2, 4, 6); the Step 1 parser and Step 2 keyword clean are pytest-tested in `tools/security-management` diff --git a/tools/skill-evals/evals/committer-onboarding/README.md b/tools/skill-evals/evals/committer-onboarding/README.md index 759d670d5..30a0981df 100644 --- a/tools/skill-evals/evals/committer-onboarding/README.md +++ b/tools/skill-evals/evals/committer-onboarding/README.md @@ -3,7 +3,7 @@ # committer-onboarding — eval suite -26 cases across 4 steps covering the post-vote onboarding workflow, +27 cases across 4 steps covering the post-vote onboarding workflow, including intake-model and governance-model flag branches. ## Case inventory diff --git a/tools/skill-evals/evals/setup/README.md b/tools/skill-evals/evals/setup/README.md index 41e7271e8..05158aeb1 100644 --- a/tools/skill-evals/evals/setup/README.md +++ b/tools/skill-evals/evals/setup/README.md @@ -25,7 +25,7 @@ Behavioral evals for the `setup` skill. | adopt-review-process | adopt.md § Step 4c | 5 | a fresh adopt finding two deviations in the confirmed documents where one is accepted and one rejected, and a release policy left alone because that family is not in the floor; a re-adoption reviewing only the one family the floor diff added; a re-adoption that adds no family, where edited process documents are still not re-read; a sentence that would weaken a merge confirmation gate, dropped and named while a label deviation beside it is written; and a repo whose only candidate document the maintainer un-ticks, skipping the step | | adopt-security-list | adopt.md § Step 4b | 4 | an ASF project whose dedicated security list is in its docs and on the ASF page (recommend `security@`); an ASF project with no dedicated list (no recommendation, `private@` only as a flagged fallback); a non-ASF project, which is not asked; and conflicting evidence between `SECURITY.md` and the ASF page (no recommendation, flagged fallback) | | setup-prefill-from-floor | install.md § Step M0b | 4 | adopted (propose the floor), unadopted (framework defaults), a foreign marketplace called out, and a snapshot lock falling through | -| preflight-floor | preflight-block.md § Pre-flight | 22 | at floor (silent), below floor (update), plugin missing (install), foreign marketplace (ask first, run nothing), no `claude` CLI (print), unadopted (propose setup), `apache/magpie` in an alarming context (update anyway, unasked), unreadable `claude plugin list --json` (silent, treated as unknown not absent), first Magpie run (show the general welcome guide, record it, carry on), first utilities run (show the utilities welcome guide, record it, carry on), first mentoring run (show the mentoring welcome guide, record it, carry on), first pairing run (show the pairing welcome guide, record it, carry on), first issue run (show the issue welcome guide, record it, carry on), first pr-management run (show the pr-management welcome guide, record it, carry on), first contributor-growth run (show the contributor-growth welcome guide, record it, carry on), below floor on Codex (marketplace upgrade), below floor on Gemini (update the extension once), at floor on Gemini (silent), first repo-health run (show the repo-health welcome guide, record it, carry on), first setup run (show the setup welcome guide, record it, carry on), first release-management run (show the release-management welcome guide, record it, carry on) | +| preflight-floor | preflight-block.md § Pre-flight | 22 | at floor (silent), below floor (update), plugin missing (install), foreign marketplace (ask first, run nothing), no `claude` CLI (print), unadopted (propose setup), `apache/magpie` in an alarming context (update anyway, unasked), unreadable `claude plugin list --json` (silent, treated as unknown not absent), first Magpie run (show the general welcome guide, record it, carry on), first utilities run (show the utilities welcome guide, record it, carry on), first mentoring run (show the mentoring welcome guide, record it, carry on), first pairing run (show the pairing welcome guide, record it, carry on), first issue run (show the issue welcome guide, record it, carry on), first pr-management run (show the pr-management welcome guide, record it, carry on), first contributor-growth run (show the contributor-growth welcome guide, record it, carry on), below floor on Codex (marketplace upgrade), below floor on Gemini (update the extension once), at floor on Gemini (silent), first repo-health run (show the repo-health welcome guide, record it, carry on), first setup run (show the setup welcome guide, record it, carry on), first release-management run (show the release-management welcome guide, record it, carry on), a lock committed before `magpie-vetted-ops` joined the seeded floor (install it anyway, blocking, and mention the restart) | | upgrade-adoption-split | upgrade.md § Step 0b | 4 | not adopted (nothing staged), adopted (floor raised and staged), already ahead (floor unchanged), snapshot method (falls through) | | verify-floor | verify.md § Adoption floor | 4 | no lock (not a fault), ahead of floor with extra plugins (not a fault), a shortfall (a fault), a floor plugin the marketplace no longer ships (a fault, not installed around) | | step-reconcile | reconcile.md § The sweep | 3 | a clean sweep on a pinned-snapshot install (anchor present, config resolved — stamp written, nothing proposed), a renamed step heading stranding an override's anchor (one re-anchor proposal named), a marketplace install whose plugin cache is sandbox-denied (anchor resolution left `unchecked`, config resolution still completes) | diff --git a/tools/vetted-ops/src/vetted_ops/layers.py b/tools/vetted-ops/src/vetted_ops/layers.py index 679ce3721..46278ffa8 100644 --- a/tools/vetted-ops/src/vetted_ops/layers.py +++ b/tools/vetted-ops/src/vetted_ops/layers.py @@ -26,9 +26,11 @@ * Adopted repository (a committed `.apache-magpie.lock`): the personal layer is `/.apache-magpie-local/`. * Not adopted: it is `/apache-magpie/` — inside the git - directory, never the working tree, shared by every worktree. Outside a - git repository there is none. A legacy in-tree `.apache-magpie-local/` - is still read after it. + directory, never the working tree, shared by every worktree. In a + Subversion working copy it is `<.svn>/apache-magpie/` for the same + reasons. With no version control at all there is nothing it could be + committed to, so it is the in-tree `/.apache-magpie-local/`. A + legacy in-tree `.apache-magpie-local/` is still read after it. * A linked worktree of an adopted repository falls back to its main checkout's `.apache-magpie-local/`, file by file (`main_worktree`). * The committed layer, `/.apache-magpie-overrides/`, comes last. From 3c3a2441a5d3b1656317eb350db6ede1c0587d71 Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Sun, 25 Oct 2026 21:05:11 +0100 Subject: [PATCH 2/3] fix(setup): show the setup welcome guide, find the Subversion layer, re-point the Codex hook Follow-ups to the same spec-sync pass, each a gap a recent change left: - The setup family is exempt from the shared pre-flight, so its welcome guide never showed. The `setup` skill now runs a welcome-only check (`setup_preflight.welcome due --skill setup`) before any sub-action; the exemption stays. The first-run eval case moves into its own `welcome-first-run` suite built from that step. - #1779 added a Subversion personal layer at `.svn/apache-magpie/`, but the pre-flight path was git-only, so a checker installed there was never found, and `setup config` stopped outside git. The path now includes `.svn/apache-magpie` and no longer errors outside git; `config` Step 0 handles git, Subversion and no-VCS working copies as `layers.py` does. A test runs the block's path in all three. - The root Codex plugin wired SessionStart to a `hooks/check-upgrade.sh` that has not existed since #1208; it now runs the magpie-setup script with `/bin/bash -p`, and check-family-plugins pins that wiring. - generate-cve-json's README documents its config file (lookup order, every key, an example), which its error messages already pointed at. - tools/hook-manager's README gains Operations and Configuration sections. Generated-by: Claude Opus 5 --- .codex-plugin/plugin.json | 2 +- .pre-commit-config.yaml | 2 +- docs/mode-economics.md | 3 +- docs/setup/README.md | 6 +- docs/setup/marketplace.md | 2 +- .../skills/activity-sweep/SKILL.md | 13 +-- .../skills/calibrate/SKILL.md | 13 +-- .../skills/candidate-screen/SKILL.md | 13 +-- .../skills/committer-onboarding/SKILL.md | 13 +-- .../skills/contributor-to-committer/SKILL.md | 13 +-- .../skills/identity-map/SKILL.md | 13 +-- .../skills/nomination/SKILL.md | 13 +-- .../skills/onboarding-concierge/SKILL.md | 13 +-- .../skills/sentiment/SKILL.md | 13 +-- .../skills/backlog-stats/SKILL.md | 13 +-- .../magpie-issue/skills/deduplicate/SKILL.md | 13 +-- .../magpie-issue/skills/fix-workflow/SKILL.md | 13 +-- .../skills/reassess-stats/SKILL.md | 13 +-- plugins/magpie-issue/skills/reassess/SKILL.md | 13 +-- .../magpie-issue/skills/reproducer/SKILL.md | 13 +-- .../magpie-issue/skills/stale-sweep/SKILL.md | 13 +-- plugins/magpie-issue/skills/triage/SKILL.md | 13 +-- .../skills/good-first-issue-author/SKILL.md | 13 +-- .../skills/good-first-issue-sweep/SKILL.md | 13 +-- .../skills/newcomer-issue-explainer/SKILL.md | 13 +-- .../magpie-mentoring/skills/welcome/SKILL.md | 13 +-- .../skills/multi-agent-review/SKILL.md | 13 +-- .../skills/self-review/SKILL.md | 13 +-- .../skills/code-review/SKILL.md | 13 +-- .../skills/mentor/SKILL.md | 13 +-- .../skills/pr-stale-sweep/SKILL.md | 13 +-- .../skills/pr-triage/SKILL.md | 13 +-- .../skills/pre-first-pr-check/SKILL.md | 13 +-- .../skills/quick-merge/SKILL.md | 13 +-- .../skills/reviewer-routing/SKILL.md | 13 +-- .../skills/stack-review/SKILL.md | 13 +-- .../skills/stats/SKILL.md | 13 +-- .../skills/announce-draft/SKILL.md | 13 +-- .../skills/archive-sweep/SKILL.md | 13 +-- .../skills/audit-report/SKILL.md | 13 +-- .../skills/keys-sync/SKILL.md | 13 +-- .../skills/prepare/SKILL.md | 13 +-- .../skills/promote/SKILL.md | 13 +-- .../skills/rc-cut/SKILL.md | 13 +-- .../skills/verify-rc/SKILL.md | 13 +-- .../skills/vote-draft/SKILL.md | 13 +-- .../skills/vote-tally/SKILL.md | 13 +-- .../skills/audit-finding-fix/SKILL.md | 13 +-- .../skills/ci-runner-audit/SKILL.md | 13 +-- .../skills/dependency-audit/SKILL.md | 13 +-- .../skills/dependency-license-audit/SKILL.md | 13 +-- .../skills/flaky-test-triage/SKILL.md | 13 +-- .../skills/license-compliance-audit/SKILL.md | 13 +-- .../skills/workflow-optimization/SKILL.md | 13 +-- .../skills/workflow-security-audit/SKILL.md | 13 +-- .../generate-cve-json/README.md | 86 +++++++++++++++++++ .../src/generate_cve_json/cve_json.py | 7 +- .../skills/cve-allocate/SKILL.md | 13 +-- .../skills/issue-deduplicate/SKILL.md | 13 +-- .../magpie-security/skills/issue-fix/SKILL.md | 13 +-- .../skills/issue-import-from-md/SKILL.md | 13 +-- .../skills/issue-import-from-pr/SKILL.md | 13 +-- .../skills/issue-import-from-scan/SKILL.md | 13 +-- .../issue-import-via-forwarder/SKILL.md | 13 +-- .../skills/issue-import/SKILL.md | 13 +-- .../skills/issue-invalidate/SKILL.md | 13 +-- .../skills/issue-sync/SKILL.md | 13 +-- .../skills/issue-triage/SKILL.md | 13 +-- .../skills/model-prepare/SKILL.md | 13 +-- .../skills/model-update/SKILL.md | 13 +-- .../skills/model-verify/SKILL.md | 13 +-- .../skills/submit-to-oss-scan/SKILL.md | 13 +-- .../skills/tracker-stats-dashboard/SKILL.md | 13 +-- plugins/magpie-setup/hooks/check-upgrade.sh | 5 +- .../skills/complete-upgrade/SKILL.md | 4 +- .../skills/isolated-setup-install/SKILL.md | 4 +- .../skills/isolated-setup-update/SKILL.md | 4 +- plugins/magpie-setup/skills/setup/SKILL.md | 22 ++++- plugins/magpie-setup/skills/setup/config.md | 49 +++++++---- .../magpie-setup/skills/setup/delegates.md | 2 +- .../setup/setup_preflight/guides/_footer.md | 2 +- .../setup/setup_preflight/sections/step-11.md | 2 +- .../setup/setup_preflight/sections/welcome.md | 2 +- .../skills/setup/setup_preflight/welcome.py | 17 ++++ plugins/magpie-setup/skills/setup/upgrade.md | 2 +- .../skills/welcome-guide/SKILL.md | 6 +- .../skills/list-skills/SKILL.md | 13 +-- .../skills/optimize-skill/SKILL.md | 13 +-- .../skills/report-framework-issue/SKILL.md | 13 +-- .../skills/skill-reconciler/SKILL.md | 13 +-- .../skills/write-skill/SKILL.md | 13 +-- .../generate-cve-json/README.md | 86 +++++++++++++++++++ .../generate-cve-json/SKILL.md | 3 +- .../src/generate_cve_json/cve_json.py | 7 +- tools/dev/README.md | 2 +- tools/dev/check-family-plugins.py | 29 ++++++- tools/dev/preflight-block.md | 11 +-- tools/dev/render-preflight-fixtures.py | 55 +++++++++--- .../tests/test_render_preflight_fixtures.py | 27 +++++- tools/hook-manager/README.md | 28 ++++++ tools/setup-preflight/tests/test_layers.py | 48 +++++++++++ tools/setup-preflight/tests/test_welcome.py | 44 ++++++++++ tools/skill-evals/README.md | 2 +- tools/skill-evals/evals/setup/README.md | 5 +- .../case-10-utilities-first-run/report.md | 4 +- .../case-11-mentoring-first-run/report.md | 4 +- .../case-12-pairing-first-run/report.md | 4 +- .../case-13-issue-first-run/report.md | 4 +- .../case-14-pr-management-first-run/report.md | 4 +- .../report.md | 4 +- .../case-19-repo-health-first-run/report.md | 4 +- .../case-20-setup-first-run/expected.json | 1 - .../case-20-setup-first-run/state.json | 20 ----- .../report.md | 4 +- .../case-9-first-magpie-run/report.md | 4 +- .../case-1-first-magpie-run}/case-meta.json | 0 .../case-1-first-magpie-run/expected.json | 1 + .../case-1-first-magpie-run/report.md | 34 ++++++++ .../case-1-first-magpie-run/state.json | 1 + .../case-meta.json | 1 + .../expected.json | 1 + .../report.md | 14 ++- .../state.json | 1 + .../case-3-nothing-due/case-meta.json | 1 + .../fixtures/case-3-nothing-due/expected.json | 1 + .../fixtures/case-3-nothing-due/report.md | 19 ++++ .../fixtures/case-3-nothing-due/state.json | 1 + .../welcome-first-run/fixtures/output-spec.md | 36 ++++++++ .../fixtures/step-config.json | 4 + .../fixtures/user-prompt-template.md | 9 ++ tools/spec-loop/specs/adoption-and-setup.md | 2 +- 131 files changed, 1132 insertions(+), 550 deletions(-) delete mode 100644 tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/expected.json delete mode 100644 tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/state.json rename tools/skill-evals/evals/setup/{preflight-floor/fixtures/case-20-setup-first-run => welcome-first-run/fixtures/case-1-first-magpie-run}/case-meta.json (100%) create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/expected.json create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/report.md create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/state.json create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/case-meta.json create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/expected.json rename tools/skill-evals/evals/setup/{preflight-floor/fixtures/case-20-setup-first-run => welcome-first-run/fixtures/case-2-setup-guide-after-general}/report.md (78%) create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/state.json create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/case-meta.json create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/expected.json create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/report.md create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/state.json create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/output-spec.md create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/step-config.json create mode 100644 tools/skill-evals/evals/setup/welcome-first-run/fixtures/user-prompt-template.md diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index 14f171797..e0791993f 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -9,7 +9,7 @@ "hooks": [ { "type": "command", - "command": "${PLUGIN_ROOT}/hooks/check-upgrade.sh", + "command": "/bin/bash -p \"${PLUGIN_ROOT}/plugins/magpie-setup/hooks/check-upgrade.sh\"", "timeout": 10 } ] diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 61af30a29..f4ba1b4e2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -565,7 +565,7 @@ repos: name: render-preflight-fixtures (pre-flight eval cases vs the real checker) language: system entry: python3 tools/dev/render-preflight-fixtures.py - files: ^(plugins/magpie-setup/skills/setup/setup_preflight/.*|tools/skill-evals/evals/setup/preflight-floor/fixtures/.*|tools/dev/render-preflight-fixtures\.py)$ + files: ^(plugins/magpie-setup/skills/setup/setup_preflight/.*|tools/skill-evals/evals/setup/(preflight-floor|welcome-first-run)/fixtures/.*|tools/dev/render-preflight-fixtures\.py)$ pass_filenames: false # something else. - repo: local diff --git a/docs/mode-economics.md b/docs/mode-economics.md index 9cc02c745..1e79f3aec 100644 --- a/docs/mode-economics.md +++ b/docs/mode-economics.md @@ -95,7 +95,8 @@ block runs as one command. Then the rules prose moved there too, and the command now emits the sections its own findings name, so there is no second file to read and no per-skill copy of one. -The block is **585 tokens**, against 1,679 before the check existed and +The block is **635 tokens** (585 before the Subversion personal layer +joined its path), against 1,679 before the check existed and 3,271 at its peak. Each of the 65 skills is **1,075–1,081 tokens cheaper than on `main`** while carrying the whole check: `ci-runner-audit` 3,281 → 2,203 (−32.9%), and the sidecar that briefly cost 2,516 tokens × 65 copies diff --git a/docs/setup/README.md b/docs/setup/README.md index afe0d199b..4c146a421 100644 --- a/docs/setup/README.md +++ b/docs/setup/README.md @@ -63,9 +63,11 @@ New to Magpie? The [quick start](../quick-start.md) walks the whole path in one place — install, the first `/magpie-setup:setup` run, and a recording of it happening — plus the other agents and the secure-isolation setup to run next. -The first setup skill you run opens with a one-minute +The `setup` skill (`/magpie-setup:setup`) opens with a one-minute [welcome guide](../../plugins/magpie-setup/skills/setup/setup_preflight/guides/setup.md): the typical flow, what needs configuring, what to ask it, and how to make it yours. +If no Magpie skill has run here before, the general Magpie welcome comes first and this one on the next `setup` run. +The other setup-family skills do not show it. Dismiss it, or hide it for good, from its last line; *"show the setup welcome again"* or `/magpie-setup:welcome-guide setup` brings it back. @@ -157,7 +159,7 @@ for the complete rule. | [`setup-isolated-setup-update`](../../skills/setup-isolated-setup-update/SKILL.md) | Surface drift between the installed setup and the framework's latest. | | [`setup-privacy-llm`](../../skills/setup-privacy-llm/SKILL.md) | Configure which LLMs may see this project's private foundation mail, then prove it: detect the stack, write `privacy-llm.md` from the matching variant, and run the approved-LLM gate and the PII redactor end to end. | | [`setup`](../../skills/setup/SKILL.md) | Adopt and maintain the framework in a project repo through installation, verification, updates, overrides, and unadoption. | -| [`setup upgrade`](../../skills/setup/upgrade.md) | Pull the framework checkout to latest `origin/main`. | +| [`setup upgrade`](../../skills/setup/upgrade.md) | Pinned-snapshot install: re-fetch the snapshot per the committed lock, refresh symlinks, reconcile overrides, and refresh the personal layer's pre-flight checker. A marketplace install upgrades through the agent's plugin update instead. | | [`setup-complete-upgrade`](../../skills/setup-complete-upgrade/SKILL.md) | Finish a Magpie upgrade in one run: check this machine and project against the installed version, apply one approved plan, re-check, and print exact commands for what is out of reach. | | [`setup verify`](../../skills/setup/verify.md) | Verify the framework is integrated correctly into an adopter tracker. | | [`setup-status`](../../skills/setup-status/SKILL.md) | Render a Markdown adoption dashboard (install pin, drift, wired agent targets, installed skill families, symlink health) and adjust the wiring in place. | diff --git a/docs/setup/marketplace.md b/docs/setup/marketplace.md index 560dfb8a5..b8faa5bfb 100644 --- a/docs/setup/marketplace.md +++ b/docs/setup/marketplace.md @@ -610,7 +610,7 @@ automatic while the *changes* stay confirmed. | Agent | Mechanism | |---|---| | **Claude Code** | `SessionStart` hook [`plugins/magpie-setup/hooks/check-upgrade.sh`](../../plugins/magpie-setup/hooks/check-upgrade.sh) compares the installed version to a marker in the plugin's persistent data dir and prompts on change. Deterministic. | -| **Codex CLI** | The same [`plugins/magpie-setup/hooks/check-upgrade.sh`](../../plugins/magpie-setup/hooks/check-upgrade.sh), wired inline via the plugin's `hooks` block — Codex uses the same event schema and the same `SessionStart` event. Codex sets `PLUGIN_ROOT`/`PLUGIN_DATA` (and the `CLAUDE_*` pair for compatibility), which the script reads. See the caveat below. | +| **Codex CLI** | The same [`plugins/magpie-setup/hooks/check-upgrade.sh`](../../plugins/magpie-setup/hooks/check-upgrade.sh), wired inline in the `hooks` block of the root plugin's [`.codex-plugin/plugin.json`](../../.codex-plugin/plugin.json) as `/bin/bash -p "${PLUGIN_ROOT}/plugins/magpie-setup/hooks/check-upgrade.sh"` — Codex uses the same event schema and the same `SessionStart` event. For the root plugin `PLUGIN_ROOT` is the repo root, where the script finds the version manifests and the `skills/setup` symlink it needs. Codex sets `PLUGIN_ROOT`/`PLUGIN_DATA` (and the `CLAUDE_*` pair for compatibility), which the script reads. See the caveat below. | | **VS Code / Copilot, Cursor, Kiro (AP1)** | None. Agent Plugins 1.0 specifies no hook component and VS Code ignores client extension directories, so there is nothing to fire. Run `/magpie-setup:complete-upgrade` after updating. | | **Gemini CLI** | No lifecycle hook; the extension context file [`GEMINI.md`](../../GEMINI.md) instructs the agent to compare the extension version to a recorded marker and prompt on change (LLM-driven, advisory). | | Other agents | Run `/magpie-setup:complete-upgrade` manually after updating the package. | diff --git a/plugins/magpie-contributor-growth/skills/activity-sweep/SKILL.md b/plugins/magpie-contributor-growth/skills/activity-sweep/SKILL.md index 8e709ab97..579c3a8e7 100644 --- a/plugins/magpie-contributor-growth/skills/activity-sweep/SKILL.md +++ b/plugins/magpie-contributor-growth/skills/activity-sweep/SKILL.md @@ -20,7 +20,7 @@ argument-hint: " [window:Nm]" capability: capability:stats surface_hash: sha256:a39919af92a37e2d license: Apache-2.0 -measured_tokens: 3524 +measured_tokens: 3574 --- @@ -45,14 +45,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -64,12 +65,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-contributor-growth/skills/sentiment/SKILL.md b/plugins/magpie-contributor-growth/skills/sentiment/SKILL.md index 4f6e2d328..e4cb6b35a 100644 --- a/plugins/magpie-contributor-growth/skills/sentiment/SKILL.md +++ b/plugins/magpie-contributor-growth/skills/sentiment/SKILL.md @@ -20,7 +20,7 @@ argument-hint: "[window:Nm] [baseline:YYYY-MM-DD..YYYY-MM-DD]" capability: capability:stats surface_hash: sha256:c325db1d99634a51 license: Apache-2.0 -measured_tokens: 4660 +measured_tokens: 4710 --- @@ -50,14 +50,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -69,12 +70,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-mentoring/skills/good-first-issue-sweep/SKILL.md b/plugins/magpie-mentoring/skills/good-first-issue-sweep/SKILL.md index e0c1d8acf..6e89999d6 100644 --- a/plugins/magpie-mentoring/skills/good-first-issue-sweep/SKILL.md +++ b/plugins/magpie-mentoring/skills/good-first-issue-sweep/SKILL.md @@ -27,7 +27,7 @@ capability: - capability:triage surface_hash: sha256:591ae352325ca83d license: Apache-2.0 -measured_tokens: 4361 +measured_tokens: 4411 --- @@ -52,14 +52,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -71,12 +72,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-mentoring/skills/newcomer-issue-explainer/SKILL.md b/plugins/magpie-mentoring/skills/newcomer-issue-explainer/SKILL.md index d575054f7..2869e0c79 100644 --- a/plugins/magpie-mentoring/skills/newcomer-issue-explainer/SKILL.md +++ b/plugins/magpie-mentoring/skills/newcomer-issue-explainer/SKILL.md @@ -24,7 +24,7 @@ argument-hint: "[issue-number or issue-URL]" capability: capability:review surface_hash: sha256:8cfe453a3113abe2 license: Apache-2.0 -measured_tokens: 3607 +measured_tokens: 3657 --- @@ -48,14 +48,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -67,12 +68,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-mentoring/skills/welcome/SKILL.md b/plugins/magpie-mentoring/skills/welcome/SKILL.md index b1d036047..38ee06cce 100644 --- a/plugins/magpie-mentoring/skills/welcome/SKILL.md +++ b/plugins/magpie-mentoring/skills/welcome/SKILL.md @@ -24,7 +24,7 @@ argument-hint: "[issue-or-pr-number]" capability: capability:review surface_hash: sha256:a61c6575d69da08a license: Apache-2.0 -measured_tokens: 3493 +measured_tokens: 3543 --- @@ -48,14 +48,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -67,12 +68,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-pairing/skills/multi-agent-review/SKILL.md b/plugins/magpie-pairing/skills/multi-agent-review/SKILL.md index 5dc5e7575..58e48a8e9 100644 --- a/plugins/magpie-pairing/skills/multi-agent-review/SKILL.md +++ b/plugins/magpie-pairing/skills/multi-agent-review/SKILL.md @@ -21,7 +21,7 @@ argument-hint: "[base:] [staged] [path:]" capability: capability:review surface_hash: sha256:d1b0ba75f03a00c1 license: Apache-2.0 -measured_tokens: 3747 +measured_tokens: 3797 --- @@ -47,14 +47,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -66,12 +67,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-pairing/skills/self-review/SKILL.md b/plugins/magpie-pairing/skills/self-review/SKILL.md index 0afbb2ad3..c30a8a4a1 100644 --- a/plugins/magpie-pairing/skills/self-review/SKILL.md +++ b/plugins/magpie-pairing/skills/self-review/SKILL.md @@ -20,7 +20,7 @@ argument-hint: "[base:] [staged] [path:]" capability: capability:review surface_hash: sha256:ea0a2e29bb2aa0e0 license: Apache-2.0 -measured_tokens: 3730 +measured_tokens: 3780 --- @@ -46,14 +46,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -65,12 +66,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-pr-management/skills/code-review/SKILL.md b/plugins/magpie-pr-management/skills/code-review/SKILL.md index c77a4ca09..ba2be662e 100644 --- a/plugins/magpie-pr-management/skills/code-review/SKILL.md +++ b/plugins/magpie-pr-management/skills/code-review/SKILL.md @@ -24,7 +24,7 @@ argument-hint: "[pr:N] [area:LBL] [collab:true|false] [team:NAME] [ready] [dry-r capability: capability:review surface_hash: sha256:0e09164d15647a70 license: Apache-2.0 -measured_tokens: 3826 +measured_tokens: 3876 --- @@ -49,14 +49,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -68,12 +69,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-pr-management/skills/mentor/SKILL.md b/plugins/magpie-pr-management/skills/mentor/SKILL.md index 43a8bfc07..b846a6ae7 100644 --- a/plugins/magpie-pr-management/skills/mentor/SKILL.md +++ b/plugins/magpie-pr-management/skills/mentor/SKILL.md @@ -25,7 +25,7 @@ argument-hint: "[issue-or-pr-number]" capability: capability:review surface_hash: sha256:bdf8343d503d01ef license: Apache-2.0 -measured_tokens: 2759 +measured_tokens: 2809 --- @@ -49,14 +49,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -68,12 +69,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-pr-management/skills/pr-stale-sweep/SKILL.md b/plugins/magpie-pr-management/skills/pr-stale-sweep/SKILL.md index b23790e43..27326c9fa 100644 --- a/plugins/magpie-pr-management/skills/pr-stale-sweep/SKILL.md +++ b/plugins/magpie-pr-management/skills/pr-stale-sweep/SKILL.md @@ -22,7 +22,7 @@ when_to_use: | capability: capability:triage surface_hash: sha256:086e859fb8751476 license: Apache-2.0 -measured_tokens: 2974 +measured_tokens: 3024 --- @@ -52,14 +52,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -71,12 +72,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-pr-management/skills/pre-first-pr-check/SKILL.md b/plugins/magpie-pr-management/skills/pre-first-pr-check/SKILL.md index 97b2e94d9..3d6350b87 100644 --- a/plugins/magpie-pr-management/skills/pre-first-pr-check/SKILL.md +++ b/plugins/magpie-pr-management/skills/pre-first-pr-check/SKILL.md @@ -24,7 +24,7 @@ argument-hint: "[base:] [path:]" capability: capability:review surface_hash: sha256:4219bd5fdce4e81d license: Apache-2.0 -measured_tokens: 2639 +measured_tokens: 2689 --- @@ -50,14 +50,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -69,12 +70,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-pr-management/skills/quick-merge/SKILL.md b/plugins/magpie-pr-management/skills/quick-merge/SKILL.md index 490ea928b..46bb2d326 100644 --- a/plugins/magpie-pr-management/skills/quick-merge/SKILL.md +++ b/plugins/magpie-pr-management/skills/quick-merge/SKILL.md @@ -28,7 +28,7 @@ capability: - capability:review surface_hash: sha256:99ac70a7b7f1228c license: Apache-2.0 -measured_tokens: 3145 +measured_tokens: 3195 --- @@ -51,14 +51,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -70,12 +71,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/plugins/magpie-pr-management/skills/stats/SKILL.md b/plugins/magpie-pr-management/skills/stats/SKILL.md index 38d7038bf..f763e9a35 100644 --- a/plugins/magpie-pr-management/skills/stats/SKILL.md +++ b/plugins/magpie-pr-management/skills/stats/SKILL.md @@ -21,7 +21,7 @@ argument-hint: "[repo:owner/name] [since:date] [clear-cache]" capability: capability:stats surface_hash: sha256:9e5dedfbf2f9f716 license: Apache-2.0 -measured_tokens: 2561 +measured_tokens: 2611 --- ` region (empty or filled), and this tool only ever fills that region — it never inserts one, and a target naming a block with no matching source is a hard error, never a silent skip. Declared targets are restricted to the `skills/` tree. `--fix` propagates; bare invocation reports and exits non-zero on drift. | diff --git a/tools/dev/check-family-plugins.py b/tools/dev/check-family-plugins.py index af4707d1d..a492fcd12 100644 --- a/tools/dev/check-family-plugins.py +++ b/tools/dev/check-family-plugins.py @@ -12,7 +12,8 @@ `pyproject.toml`'s `project.version` verbatim — including a `.devN` suffix; - `magpie-setup`'s manifest wires the `hooks/check-upgrade.sh` SessionStart hook (which must exist) -- it rides on the one plugin the recommended floor - always installs; + always installs -- and the root `.codex-plugin/plugin.json` wires the same + script for Codex, through `plugins/magpie-setup/` from the repo root; - the root `plugin.json` conforms to Agent Plugins 1.0 — the pinned `$schema`, the name pattern, the closed ten-field set (so a Claude-only component path never leaks in), and the same shared metadata as the Claude manifest; @@ -78,6 +79,24 @@ } ] } +# The same script, wired for Codex in the root plugin's `.codex-plugin/plugin.json` +# (the overlay Codex merges over the root `plugin.json`). `${PLUGIN_ROOT}` is the +# repo root there, so the path runs through `plugins/magpie-setup/`; the script +# finds the root's manifests and its `skills/setup` symlink from that root. +CODEX_MANIFEST = Path(".codex-plugin/plugin.json") +CODEX_HOOKS = { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": f'/bin/bash -p "${{PLUGIN_ROOT}}/{UPGRADE_HOOK.as_posix()}"', + "timeout": 10, + } + ], + } + ] +} # Every skill's pre-flight runs `setup_preflight`, and `setup config` installs it # from the plugin on a marketplace install, so the package has to be inside # magpie-setup's root: a symlink out to `tools/` would put magpie-setup, which the @@ -1100,6 +1119,14 @@ def check(fam: dict[str, set[str]]) -> list[str]: else: if setup_data is not None and "check-upgrade.sh" not in json.dumps(setup_data.get("hooks", {})): errors.append(f"{setup_manifest}: SessionStart hook does not reference check-upgrade.sh") + codex_data, codex_err = load_json(CODEX_MANIFEST) + if codex_err: + errors.append(codex_err) + elif isinstance(codex_data, dict) and codex_data.get("hooks") != CODEX_HOOKS: + errors.append( + f"{CODEX_MANIFEST}: 'hooks' must be exactly {json.dumps(CODEX_HOOKS)} " + "(the root plugin's PLUGIN_ROOT is the repo root, and the hook runs as `/bin/bash -p `)" + ) errors += check_setup_preflight_package() errors += welcome_families("check-constant") diff --git a/tools/dev/preflight-block.md b/tools/dev/preflight-block.md index 16eb38002..e2e7011ab 100644 --- a/tools/dev/preflight-block.md +++ b/tools/dev/preflight-block.md @@ -11,14 +11,15 @@ Run the checker with this skill's own frontmatter `name:` and `surface_hash:`, and one `--requires` for each `requires_config:` entry: ```bash -PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \ +PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie" \ python3 -m setup_preflight --skill --hash [--requires ]... ``` The path finds the checker `/magpie-setup:setup config` installed in the personal layer: this checkout's `.apache-magpie-local/`, the main -checkout's when this is a linked worktree, or the git directory's -`apache-magpie/` when Magpie is only installed. +checkout's when this is a linked worktree, or, when Magpie is only +installed, the git directory's `apache-magpie/` (`.svn/apache-magpie/` +in a Subversion working copy). - **`{"verdict": "ok"}`** → **silent**. Continue into the work the user asked for and say nothing about pre-flight. This is the ordinary answer. @@ -30,12 +31,12 @@ checkout's when this is a linked worktree, or the git directory's `python3` — → never read that as a pass, and do not re-derive the check by hand: it lives in code so that there is one version of it. If the project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`, - or personal layer (any of the three directories above), + or personal layer (any of the directories above), nothing has been set up here and there is nothing to reconcile — resolve this skill's `requires_config:` entries yourself (first match wins: `.apache-magpie-local/`, the main checkout's `.apache-magpie-local/`, `/apache-magpie/`, - then `.apache-magpie-overrides/`), stay silent if they all resolve, and + `.svn/apache-magpie/`, then `.apache-magpie-overrides/`), stay silent if they all resolve, and run `/magpie-setup:setup config` for this skill if any does not, which also installs the checker. Otherwise the project *is* set up and its checker is missing or stale: say so, propose `/magpie-setup:setup config` to install diff --git a/tools/dev/render-preflight-fixtures.py b/tools/dev/render-preflight-fixtures.py index 9966176ba..e57244423 100644 --- a/tools/dev/render-preflight-fixtures.py +++ b/tools/dev/render-preflight-fixtures.py @@ -42,6 +42,13 @@ * `welcome` — `true` to include the skill family's first-run welcome guide. Left out otherwise (`--no-welcome`), so a floor case is about the floor and not about which family its skill happens to belong to. +* `check` — `"welcome-due"` runs `python3 -m setup_preflight.welcome due` + instead of the full pre-flight: the hard-coded welcome check the `setup` + skill runs, since the setup family carries no shared pre-flight block. + Only `skill` and `reconciled` apply to it. + +Each suite in `SUITES` is rendered the same way; a `welcome-due` case's +verdict follows `WELCOME_MARKER` rather than `MARKER`. Usage: @@ -59,9 +66,14 @@ import tempfile from pathlib import Path -SUITE = Path("tools/skill-evals/evals/setup/preflight-floor/fixtures") +SUITES = ( + Path("tools/skill-evals/evals/setup/preflight-floor/fixtures"), + Path("tools/skill-evals/evals/setup/welcome-first-run/fixtures"), +) CHECKER = Path("plugins/magpie-setup/skills/setup") MARKER = "\nThe pre-flight command printed:\n" +WELCOME_MARKER = "\nThe welcome check printed:\n" +WELCOME_DUE = "welcome-due" DEFAULT_SKILL = "issue-triage" DEFAULT_HASH = "sha256:2edc90a1b7f3440d" @@ -101,6 +113,21 @@ def run_checker(state: dict[str, object], repo_root: Path, scratch: Path) -> str personal.mkdir(parents=True, exist_ok=True) (personal / "reconciled.json").write_text(json.dumps(reconciled), encoding="utf-8") + check = state.get("check") + if check is not None and check != WELCOME_DUE: + raise ValueError(f"`check` must be {WELCOME_DUE!r} or left out") + if check == WELCOME_DUE: + env = _env(scratch) + env["PYTHONPATH"] = str(repo_root / CHECKER) + skill = str(state.get("skill", "setup")) + due = [sys.executable, "-m", "setup_preflight.welcome", "due", "--skill", skill] + due += ["--project-root", str(project)] + result = subprocess.run(due, capture_output=True, text=True, env=env, cwd=project, check=False) + if result.returncode != 0: + detail = result.stderr.strip() + raise RuntimeError(f"setup_preflight.welcome due exited {result.returncode}: {detail}") + return result.stdout.rstrip("\n") + harness = state.get("harness") listing = scratch / "plugins.json" plugins = state.get("plugins") @@ -201,23 +228,24 @@ def _env(scratch: Path) -> dict[str, str]: return env -def render_report(prose: str, verdict: str) -> str: +def render_report(prose: str, verdict: str, marker: str = MARKER) -> str: """The case's own prose, then the verdict block. Idempotent.""" - if MARKER in prose: - prose = prose[: prose.index(MARKER)] - return prose.rstrip("\n") + "\n" + MARKER + "\n```json\n" + verdict + "\n```\n" + if marker in prose: + prose = prose[: prose.index(marker)] + return prose.rstrip("\n") + "\n" + marker + "\n```json\n" + verdict + "\n```\n" def render_suite(repo_root: Path) -> dict[Path, str]: """Every case's report as it should read now.""" - suite = repo_root / SUITE out: dict[Path, str] = {} - for state_file in sorted(suite.glob("case-*/state.json")): - state = json.loads(state_file.read_text(encoding="utf-8")) - report = state_file.parent / "report.md" - with tempfile.TemporaryDirectory() as tmp: - verdict = run_checker(state, repo_root, Path(tmp)) - out[report] = render_report(report.read_text(encoding="utf-8"), verdict) + for suite in SUITES: + for state_file in sorted((repo_root / suite).glob("case-*/state.json")): + state = json.loads(state_file.read_text(encoding="utf-8")) + report = state_file.parent / "report.md" + with tempfile.TemporaryDirectory() as tmp: + verdict = run_checker(state, repo_root, Path(tmp)) + marker = WELCOME_MARKER if state.get("check") == WELCOME_DUE else MARKER + out[report] = render_report(report.read_text(encoding="utf-8"), verdict, marker) return out @@ -228,8 +256,7 @@ def main(argv: list[str] | None = None) -> int: args = parser.parse_args(argv) root: Path = args.repo_root.resolve() - suite = root / SUITE - cases = sorted(p for p in suite.glob("case-*") if p.is_dir()) + cases = sorted(p for suite in SUITES for p in (root / suite).glob("case-*") if p.is_dir()) missing = [c.name for c in cases if not (c / "state.json").is_file()] if missing: print(f"render-preflight-fixtures: no state.json in {', '.join(missing)}", file=sys.stderr) diff --git a/tools/dev/tests/test_render_preflight_fixtures.py b/tools/dev/tests/test_render_preflight_fixtures.py index 406375eb5..f5eb8314f 100644 --- a/tools/dev/tests/test_render_preflight_fixtures.py +++ b/tools/dev/tests/test_render_preflight_fixtures.py @@ -33,6 +33,7 @@ def _load() -> ModuleType: mod = _load() +FLOOR, WELCOME = mod.SUITES @pytest.fixture @@ -43,7 +44,8 @@ def repo(tmp_path: Path) -> Path: tmp_path / mod.CHECKER / "setup_preflight", ignore=shutil.ignore_patterns("__pycache__"), ) - shutil.copytree(_REPO / mod.SUITE, tmp_path / mod.SUITE) + for suite in mod.SUITES: + shutil.copytree(_REPO / suite, tmp_path / suite) return tmp_path @@ -59,12 +61,12 @@ def test_a_changed_rule_makes_the_suite_stale(repo: Path) -> None: # Rendering repairs it, and leaves the suite clean for the next check. assert mod.main(["--repo-root", str(repo)]) == 1 assert mod.main(["--check", "--repo-root", str(repo)]) == 0 - report = repo / mod.SUITE / "case-6-unadopted/report.md" + report = repo / FLOOR / "case-6-unadopted/report.md" assert "A new rule." in report.read_text(encoding="utf-8") def test_a_changed_state_makes_its_case_stale(repo: Path) -> None: - state_file = repo / mod.SUITE / "case-2-below-floor/state.json" + state_file = repo / FLOOR / "case-2-below-floor/state.json" state = json.loads(state_file.read_text(encoding="utf-8")) state["plugins"] = [["magpie-setup", "0.3.0"], ["magpie-pr-management", "0.3.0"]] state_file.write_text(json.dumps(state), encoding="utf-8") @@ -73,7 +75,7 @@ def test_a_changed_state_makes_its_case_stale(repo: Path) -> None: def test_a_case_without_state_is_refused(repo: Path) -> None: - (repo / mod.SUITE / "case-9-new").mkdir() + (repo / FLOOR / "case-9-new").mkdir() assert mod.main(["--check", "--repo-root", str(repo)]) == 1 @@ -81,3 +83,20 @@ def test_render_keeps_the_prose_and_is_idempotent() -> None: once = mod.render_report("Some state.\n", '{"verdict": "ok"}') assert once.startswith("Some state.\n") assert mod.render_report(once, '{"verdict": "ok"}') == once + + +def test_a_changed_welcome_rule_makes_the_welcome_check_suite_stale(repo: Path) -> None: + """The `setup` skill's own welcome check is rendered from the real checker too.""" + section = repo / mod.CHECKER / "setup_preflight/sections/welcome.md" + section.write_text(section.read_text(encoding="utf-8") + "\nA new rule.\n", encoding="utf-8") + + assert mod.main(["--repo-root", str(repo)]) == 1 + assert mod.main(["--check", "--repo-root", str(repo)]) == 0 + texts = [r.read_text(encoding="utf-8") for r in sorted((repo / WELCOME).glob("case-*/report.md"))] + assert texts and all(mod.WELCOME_MARKER in text for text in texts) + assert any("A new rule." in text for text in texts) + + +def test_an_unknown_check_is_refused(tmp_path: Path) -> None: + with pytest.raises(ValueError, match="check"): + mod.run_checker({"check": "everything", "plugins": []}, _REPO, tmp_path) diff --git a/tools/hook-manager/README.md b/tools/hook-manager/README.md index 88fe9c032..e337f985c 100644 --- a/tools/hook-manager/README.md +++ b/tools/hook-manager/README.md @@ -12,6 +12,8 @@ - [Home](#home) - [Detection](#detection) - [Registry](#registry) + - [Operations](#operations) + - [Configuration](#configuration) - [Adapters](#adapters) - [Adding an adapter](#adding-an-adapter) - [Consumers](#consumers) @@ -140,6 +142,32 @@ The two YAML names are shared with pre-commit, so a repository with one uses bot It also checks, without writing, that [`.claude/settings.json`](../../.claude/settings.json) and [`tools/sandbox-lint/expected.json`](../sandbox-lint/expected.json) deny every manager's default home and carry the sandbox home of each manager this repository uses. It runs as the `sync-hook-managers` prek hook. +## Operations + +The contract has no binary of its own. +Its operations are carried out by the scripts generated from the registry: + +| Operation | Run by | Invocation | Behaviour | +|---|---|---|---| +| Install rewrite | [`hook-manager-shim.sh`](../agent-isolation/hook-manager-shim.sh), installed as `~/.claude/bin/` | ` [args…]`, e.g. `prek install` | Applies the adapter's install strategy — for prek, runs `prek install --git-dir [args…]`. Left unchanged when `args` already carry the flag or `-h` / `--help`, or outside a git work tree. Every other subcommand passes through to the real binary, the next `` on `PATH` that is not the shim. Exits 127 when the name it is installed under has no adapter or no real binary is found. | +| Host home | [`git-hook-dispatcher.sh`](../agent-isolation/git-hook-dispatcher.sh), from `~/.claude/git-hooks/` | Every hook git runs, before it chains to the repository's own hook | Outside the sandbox (no `SANDBOX_RUNTIME`), exports `=~/.local/share/` for every registered manager unless the operator's value lies outside `~/.cache`, and moves `XDG_CACHE_HOME` to `~/.local/share/prek-host/cache` by the same rule. Sandboxed hooks keep their values. | +| Home check | [`sandbox-lint`](../sandbox-lint/) | `uv run --project tools/sandbox-lint sandbox-lint` | Fails a settings file whose `permissions.deny` lacks `Edit(/**)` for any registered manager, and, for a project that uses a manager (see [Detection](#detection)), one whose `env.` is missing or overlaps the default home. | +| Registry sync | [`tools/dev/sync-hook-managers.py`](../dev/sync-hook-managers.py) | `tools/dev/sync-hook-managers.py [--check]`; the `sync-hook-managers` prek hook | Validates `registry.json`, rewrites the generated blocks of the three scripts above, and checks the committed settings and the sandbox-lint baseline. Exits 1 when a block changed (re-stage and commit), or, with `--check`, when one would. | + +## Configuration + +The registry is framework-side: an adopter does not edit it. +What a repository or an operator configures is where each manager's environments live and which binary answers to the manager's name: + +| Setting | Where | Value for prek | Required | +|---|---|---|---| +| `permissions.deny` entry `Edit(/**)` | `.claude/settings.json` (and `tools/sandbox-lint/expected.json` in this repository) | `Edit(~/.cache/prek/**)` | Always, for every registered manager. | +| `env.` | `.claude/settings.json` | `"PREK_HOME": "~/.cache/prek-sandbox"` | Only when the repository uses the manager; it must not overlap the default home. | +| `` in the operator's environment | the shell the operator commits from | unset, or a directory outside `~/.cache` | Optional: a value outside `~/.cache` is kept by the dispatcher; one under it is replaced with the host home. | +| `PATH` | the operator's shell profile | `~/.claude/bin` ahead of the real `prek` | Only under whole-user scope, where the shim is installed; removing `~/.claude/bin` from `PATH` restores the stock binary. | + +[`setup-isolated-setup-install`](../../plugins/magpie-setup/skills/isolated-setup-install/SKILL.md) brings in the first two with its copy of the framework's `.claude/settings.json` and the `PATH` entry in [Step P](../../plugins/magpie-setup/skills/isolated-setup-install/step-p-sandbox-allowlists.md); `sandbox-lint` checks the first two. + ## Adapters | Adapter | Language | Install strategy | Home | Status | diff --git a/tools/setup-preflight/tests/test_layers.py b/tools/setup-preflight/tests/test_layers.py index e4ca3a2b0..81d2e0fe9 100644 --- a/tools/setup-preflight/tests/test_layers.py +++ b/tools/setup-preflight/tests/test_layers.py @@ -377,3 +377,51 @@ def test_the_two_run_dir_copies_match() -> None: lint = _functions(REPO_ROOT / "tools/sandbox-lint/src/sandbox_lint/layers.py") for name in ("default_run_dir", "run_dir_candidates"): assert gateway[name] == lint[name] + + +# --- the documented PYTHONPATH finds the checker wherever `config` installs it ---- + +PREFLIGHT_BLOCK = REPO_ROOT / "tools" / "dev" / "preflight-block.md" + + +def _documented_pythonpath() -> str: + import re + + match = re.search(r'^PYTHONPATH="([^"]+)"', PREFLIGHT_BLOCK.read_text(encoding="utf-8"), re.M) + assert match, "the pre-flight block names no PYTHONPATH" + return match.group(1) + + +@pytest.mark.skipif(not PREFLIGHT_BLOCK.is_file(), reason="needs the framework tree") +@pytest.mark.parametrize("vcs", ["git", "svn", "none"]) +def test_the_block_pythonpath_finds_the_checker_in_every_personal_home(tmp_path: Path, vcs: str) -> None: + """Install the checker where `config` would, then resolve it exactly as the block does.""" + import os + import shutil + import subprocess + + root = tmp_path / "project" + root.mkdir() + if vcs == "git": + subprocess.run(["git", "init", "-q", str(root)], check=True, capture_output=True) + elif vcs == "svn": + _svn_working_copy(root) + package = Path(layers.__file__).resolve().parent + shutil.copytree(package, layers.personal_dir(root) / "setup_preflight") + env = { + "PATH": os.environ.get("PATH", "/usr/bin:/bin"), + "HOME": str(tmp_path), + # Never let `git` find a repository above the test project. + "GIT_CEILING_DIRECTORIES": str(tmp_path), + } + script = ( + f'PYTHONPATH="{_documented_pythonpath()}" python3 -P -c ' + "'import pathlib, setup_preflight; print(pathlib.Path(setup_preflight.__file__).parent)'" + ) + done = subprocess.run( + ["sh", "-c", script], cwd=root, env=env, capture_output=True, text=True, check=False + ) + assert done.returncode == 0, done.stderr + assert done.stderr == "" + found = Path(done.stdout.strip()).resolve() + assert found == (layers.personal_dir(root) / "setup_preflight").resolve() diff --git a/tools/setup-preflight/tests/test_welcome.py b/tools/setup-preflight/tests/test_welcome.py index 5f20a737e..3b0cbaf8c 100644 --- a/tools/setup-preflight/tests/test_welcome.py +++ b/tools/setup-preflight/tests/test_welcome.py @@ -323,6 +323,50 @@ def test_no_welcome_leaves_it_out(project: Path, capsys, version) -> None: assert json.loads(capsys.readouterr().out) == {"verdict": "ok"} +def due_command(project: Path, capsys, skill: str = "setup") -> dict: + assert welcome.main(["due", "--skill", skill, "--project-root", str(project)]) == 0 + return json.loads(capsys.readouterr().out) + + +def test_due_carries_the_same_finding_and_rules_as_the_pre_flight(project: Path, capsys, version) -> None: + run(project) + via_preflight = json.loads(capsys.readouterr().out) + payload = due_command(project, capsys, SECURITY_SKILL) + assert payload["verdict"] == "action" + assert payload["findings"] == via_preflight["findings"][:1] + assert payload["rules"] == {"welcome": via_preflight["rules"]["welcome"]} + + +def test_due_for_the_setup_skill_walks_general_then_setup(project: Path, capsys, version) -> None: + """The setup family runs no pre-flight; `due` is how `setup` opens its first run.""" + first = due_command(project, capsys) + assert [(f["code"], f["facts"]["family"]) for f in first["findings"]] == [("welcome", "general")] + welcome.record(project, "general", "seen") + second = due_command(project, capsys) + assert [(f["facts"]["family"], f["facts"]["reason"]) for f in second["findings"]] == [ + ("setup", "first-run") + ] + + +def test_due_is_ok_and_silent_when_nothing_is_due(project: Path, capsys, version) -> None: + welcome.record(project, "general", "never") + welcome.record(project, "setup", "never") + assert due_command(project, capsys) == {"verdict": "ok"} + + +def test_due_is_ok_for_a_skill_outside_magpie(project: Path, capsys, version) -> None: + assert due_command(project, capsys, "not-a-magpie-skill") == {"verdict": "ok"} + + +def test_due_reads_no_setup_state_beyond_the_guide(project: Path, capsys, version) -> None: + """A missing `requires_config` file is the pre-flight's business, not `due`'s.""" + welcome.record(project, "general", "never") + welcome.record(project, "setup", "never") + run(project, "--requires", "project.md") + assert json.loads(capsys.readouterr().out)["verdict"] == "action" + assert due_command(project, capsys) == {"verdict": "ok"} + + # --- the three answers ---------------------------------------------------------------- diff --git a/tools/skill-evals/README.md b/tools/skill-evals/README.md index 8b0b0b592..b356d83d9 100644 --- a/tools/skill-evals/README.md +++ b/tools/skill-evals/README.md @@ -11,7 +11,7 @@ Behavioral eval harness for Apache Magpie skills. Each eval suite tests a skill Suites are currently implemented for: -- **setup** — 150 cases across 32 steps (step-verify-drift, step-overrides-surface, step-override-bypass, step-m3-baseline-pick, step-m4-install-gates, step-m5-no-repo-offer, step-m5-companion-offer, step-upgrade-companion-offer, step-adopt-settings-merge, verify-default-set, uninstall-default-set, lock-marketplace-parse, adopt-write-floor, setup-prefill-from-floor, preflight-floor, upgrade-adoption-split, verify-floor, adopt-review-process, adopt-security-list, step-reconcile, step-verify, step-config-stamp, step-config-adversarial, step-config-mail, step-adopt-stamp, step-upgrade-stamp, step-delegate-propose, config-vcs-backend, config-local-custom-parser, adopt-isolation-warning, step-vetted-ops-no-policy, step-unknown-subaction) +- **setup** — 152 cases across 33 steps (step-verify-drift, step-overrides-surface, step-override-bypass, step-m3-baseline-pick, step-m4-install-gates, step-m5-no-repo-offer, step-m5-companion-offer, step-upgrade-companion-offer, step-adopt-settings-merge, verify-default-set, uninstall-default-set, lock-marketplace-parse, adopt-write-floor, setup-prefill-from-floor, preflight-floor, upgrade-adoption-split, verify-floor, adopt-review-process, adopt-security-list, step-reconcile, step-verify, step-config-stamp, step-config-adversarial, step-config-mail, step-adopt-stamp, step-upgrade-stamp, step-delegate-propose, config-vcs-backend, config-local-custom-parser, adopt-isolation-warning, step-vetted-ops-no-policy, step-unknown-subaction) - **setup-isolated-setup-install** — 19 cases across 5 steps (runtime-routing, step-snapshot-drift, step-scope-confirm, step-hardware-key, step-roborev-exclusion) - **setup-privacy-llm** — 6 cases across 2 steps (step-1-resolve, step-4-gate) - **setup-shared-config-sync** — 12 cases across 2 steps (step-3-decide-action, step-5-draft-commit) diff --git a/tools/skill-evals/evals/setup/README.md b/tools/skill-evals/evals/setup/README.md index 05158aeb1..c22bdea14 100644 --- a/tools/skill-evals/evals/setup/README.md +++ b/tools/skill-evals/evals/setup/README.md @@ -5,7 +5,7 @@ Behavioral evals for the `setup` skill. -## Suites (150 cases total) +## Suites (152 cases total) | Suite | Step | Cases | What it covers | |---|---|---|---| @@ -25,7 +25,8 @@ Behavioral evals for the `setup` skill. | adopt-review-process | adopt.md § Step 4c | 5 | a fresh adopt finding two deviations in the confirmed documents where one is accepted and one rejected, and a release policy left alone because that family is not in the floor; a re-adoption reviewing only the one family the floor diff added; a re-adoption that adds no family, where edited process documents are still not re-read; a sentence that would weaken a merge confirmation gate, dropped and named while a label deviation beside it is written; and a repo whose only candidate document the maintainer un-ticks, skipping the step | | adopt-security-list | adopt.md § Step 4b | 4 | an ASF project whose dedicated security list is in its docs and on the ASF page (recommend `security@`); an ASF project with no dedicated list (no recommendation, `private@` only as a flagged fallback); a non-ASF project, which is not asked; and conflicting evidence between `SECURITY.md` and the ASF page (no recommendation, flagged fallback) | | setup-prefill-from-floor | install.md § Step M0b | 4 | adopted (propose the floor), unadopted (framework defaults), a foreign marketplace called out, and a snapshot lock falling through | -| preflight-floor | preflight-block.md § Pre-flight | 22 | at floor (silent), below floor (update), plugin missing (install), foreign marketplace (ask first, run nothing), no `claude` CLI (print), unadopted (propose setup), `apache/magpie` in an alarming context (update anyway, unasked), unreadable `claude plugin list --json` (silent, treated as unknown not absent), first Magpie run (show the general welcome guide, record it, carry on), first utilities run (show the utilities welcome guide, record it, carry on), first mentoring run (show the mentoring welcome guide, record it, carry on), first pairing run (show the pairing welcome guide, record it, carry on), first issue run (show the issue welcome guide, record it, carry on), first pr-management run (show the pr-management welcome guide, record it, carry on), first contributor-growth run (show the contributor-growth welcome guide, record it, carry on), below floor on Codex (marketplace upgrade), below floor on Gemini (update the extension once), at floor on Gemini (silent), first repo-health run (show the repo-health welcome guide, record it, carry on), first setup run (show the setup welcome guide, record it, carry on), first release-management run (show the release-management welcome guide, record it, carry on), a lock committed before `magpie-vetted-ops` joined the seeded floor (install it anyway, blocking, and mention the restart) | +| preflight-floor | preflight-block.md § Pre-flight | 21 | at floor (silent), below floor (update), plugin missing (install), foreign marketplace (ask first, run nothing), no `claude` CLI (print), unadopted (propose setup), `apache/magpie` in an alarming context (update anyway, unasked), unreadable `claude plugin list --json` (silent, treated as unknown not absent), first Magpie run (show the general welcome guide, record it, carry on), first utilities run (show the utilities welcome guide, record it, carry on), first mentoring run (show the mentoring welcome guide, record it, carry on), first pairing run (show the pairing welcome guide, record it, carry on), first issue run (show the issue welcome guide, record it, carry on), first pr-management run (show the pr-management welcome guide, record it, carry on), first contributor-growth run (show the contributor-growth welcome guide, record it, carry on), below floor on Codex (marketplace upgrade), below floor on Gemini (update the extension once), at floor on Gemini (silent), first repo-health run (show the repo-health welcome guide, record it, carry on), first release-management run (show the release-management welcome guide, record it, carry on), a lock committed before `magpie-vetted-ops` joined the seeded floor (install it anyway, blocking, and mention the restart) | +| welcome-first-run | SKILL.md § First — the welcome guide | 3 | the `setup` skill's own hard-coded welcome check (the setup family runs no shared pre-flight): first Magpie run (show the general guide), general already seen (show the setup guide), both hidden (silent, and no setup finding sneaks in because only the welcome is checked) | | upgrade-adoption-split | upgrade.md § Step 0b | 4 | not adopted (nothing staged), adopted (floor raised and staged), already ahead (floor unchanged), snapshot method (falls through) | | verify-floor | verify.md § Adoption floor | 4 | no lock (not a fault), ahead of floor with extra plugins (not a fault), a shortfall (a fault), a floor plugin the marketplace no longer ships (a fault, not installed around) | | step-reconcile | reconcile.md § The sweep | 3 | a clean sweep on a pinned-snapshot install (anchor present, config resolved — stamp written, nothing proposed), a renamed step heading stranding an override's anchor (one re-anchor proposal named), a marketplace install whose plugin cache is sandbox-denied (anchor resolution left `unchecked`, config resolution still completes) | diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-10-utilities-first-run/report.md b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-10-utilities-first-run/report.md index eb36e7909..65cb2221b 100644 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-10-utilities-first-run/report.md +++ b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-10-utilities-first-run/report.md @@ -20,7 +20,7 @@ The pre-flight command printed: "code": "welcome", "facts": { "family": "utilities", - "guide": "# \ud83d\udc26 Magpie here \u2014 your skill-authoring sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83d\udccb **List** the skills installed here, grouped by family \u2014 *\"list skills\"*\n2. \u270d\ufe0f **Write** a new skill against framework conventions, with evals \u2014 *\"write a skill\"*\n3. \u26a1 **Optimize** an existing skill for brevity and token efficiency \u2014 *\"optimize a skill\"*\n4. \ud83d\udc1b **Report a framework issue** from where you hit it, after checking duplicates \u2014 *\"report an issue\"*\n5. \ud83d\udd01 **Reconcile** two near-duplicate skills and classify where they drifted \u2014 *\"reconcile and \"*\n\nNothing is written, modified, or posted without your OK.\n\n## \u2699\ufe0f Configure it\n\nNothing here has to be configured:\n\n- \ud83d\udee0\ufe0f **Authoring & help** \u2014 meta-skills work straight away in any directory or worktree\n- \ud83d\udcd6 **Optional project settings** \u2014 reads `project.md` when present, otherwise uses built-in framework defaults\n\nTwo ways to run Magpie when you are ready: personal install (`/magpie-setup:setup config`) or project adoption (`/magpie-setup:setup adopt`).\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"what skills are installed here?\"*\n- *\"write a skill that drafts PR release notes\"*\n- *\"optimize the write-skill instructions\"*\n- *\"file a bug about preflight caching\"*\n- *\"have these two skill copies drifted?\"*\n\n## \ud83c\udfa8 Make it yours\n\nMagpie ships default workflows and conventions.\nChange them by describing the change:\n\n- *\"from now on, always add a smoke test when writing a skill\"*\n- *\"group the skill list by capability instead of family\"*\n\nEach becomes an override for the utility skill it changes.\nUseful to everyone? *\"Upstream this change to Magpie\"* opens a generic `apache/magpie` PR for you to review first.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the utilities welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide utilities`\n(`/magpie-setup-welcome-guide utilities` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" python3 -m setup_preflight.welcome show --family utilities --color=always\n```\n", + "guide": "# \ud83d\udc26 Magpie here \u2014 your skill-authoring sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83d\udccb **List** the skills installed here, grouped by family \u2014 *\"list skills\"*\n2. \u270d\ufe0f **Write** a new skill against framework conventions, with evals \u2014 *\"write a skill\"*\n3. \u26a1 **Optimize** an existing skill for brevity and token efficiency \u2014 *\"optimize a skill\"*\n4. \ud83d\udc1b **Report a framework issue** from where you hit it, after checking duplicates \u2014 *\"report an issue\"*\n5. \ud83d\udd01 **Reconcile** two near-duplicate skills and classify where they drifted \u2014 *\"reconcile and \"*\n\nNothing is written, modified, or posted without your OK.\n\n## \u2699\ufe0f Configure it\n\nNothing here has to be configured:\n\n- \ud83d\udee0\ufe0f **Authoring & help** \u2014 meta-skills work straight away in any directory or worktree\n- \ud83d\udcd6 **Optional project settings** \u2014 reads `project.md` when present, otherwise uses built-in framework defaults\n\nTwo ways to run Magpie when you are ready: personal install (`/magpie-setup:setup config`) or project adoption (`/magpie-setup:setup adopt`).\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"what skills are installed here?\"*\n- *\"write a skill that drafts PR release notes\"*\n- *\"optimize the write-skill instructions\"*\n- *\"file a bug about preflight caching\"*\n- *\"have these two skill copies drifted?\"*\n\n## \ud83c\udfa8 Make it yours\n\nMagpie ships default workflows and conventions.\nChange them by describing the change:\n\n- *\"from now on, always add a smoke test when writing a skill\"*\n- *\"group the skill list by capability instead of family\"*\n\nEach becomes an override for the utility skill it changes.\nUseful to everyone? *\"Upstream this change to Magpie\"* opens a generic `apache/magpie` PR for you to review first.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the utilities welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide utilities`\n(`/magpie-setup-welcome-guide utilities` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" python3 -m setup_preflight.welcome show --family utilities --color=always\n```\n", "max_shown": 3, "reason": "first-run", "shown": 0 @@ -30,7 +30,7 @@ The pre-flight command printed: } ], "rules": { - "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." + "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." }, "verdict": "action" } diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-11-mentoring-first-run/report.md b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-11-mentoring-first-run/report.md index c64530b58..e0a21ab42 100644 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-11-mentoring-first-run/report.md +++ b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-11-mentoring-first-run/report.md @@ -20,7 +20,7 @@ The pre-flight command printed: "code": "welcome", "facts": { "family": "mentoring", - "guide": "# \ud83d\udc26 Magpie here \u2014 your newcomer-mentoring sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83d\udc4b **Welcome** a first-time contributor with project guidance \u2014 *\"welcome the newcomer on PR 123\"*\n2. \ud83d\udd0e **Sweep** the backlog for newcomer-ready tasks \u2014 *\"find good first issues\"*\n3. \u270d\ufe0f **Author** one self-contained beginner issue \u2014 *\"draft a good first issue for this small task\"*\n4. \ud83d\udcd6 **Explain** an existing issue in beginner terms \u2014 *\"explain issue 123 to a newcomer\"*\n\nMagpie drafts first. Comments, new issues, and labels require explicit maintainer confirmation.\n\n## \u2699\ufe0f Configure it\n\nSet up the project context before using these skills:\n\n- \ud83d\uddc2\ufe0f **Project** \u2014 `project.md` identifies the repository and project context for every mentoring skill\n- \ud83c\udff7\ufe0f **Good first issues** \u2014 `good-first-issue-config.md` and `issue-tracker-config.md` are required for sweep and author\n- \ud83d\udcac **Optional guidance** \u2014 `mentoring-welcome-config.md` controls welcomes; `newcomer-issue-explainer-config.md` shapes explanations\n\nConfigure personally with `/magpie-setup:setup config`.\nProject adoption with `/magpie-setup:setup adopt` is a maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"welcome the first-time contributor on issue 123\"*\n- *\"find newcomer-ready issues in the backlog\"*\n- *\"which issues need changes before getting a good first issue label?\"*\n- *\"draft a good first issue from this small task\"*\n- *\"explain issue 123 with the files to read and what done looks like\"*\n\nSecurity-sensitive threads are not suitable for these newcomer workflows.\nContributors who were already welcomed, and threads already handled, are skipped.\n\n## \ud83c\udfa8 Make it yours\n\nDescribe how your project's mentoring should work:\n\n- *\"make newcomer explanations include a first test to run\"*\n- *\"use our contribution guide when drafting welcome messages\"*\n\nReview the proposed override before using it.\nUseful to others? Ask *\"upstream this change to Magpie\"* to prepare a reusable contribution for review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the mentoring welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide mentoring`\n(`/magpie-setup-welcome-guide mentoring` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" python3 -m setup_preflight.welcome show --family mentoring --color=always\n```\n", + "guide": "# \ud83d\udc26 Magpie here \u2014 your newcomer-mentoring sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83d\udc4b **Welcome** a first-time contributor with project guidance \u2014 *\"welcome the newcomer on PR 123\"*\n2. \ud83d\udd0e **Sweep** the backlog for newcomer-ready tasks \u2014 *\"find good first issues\"*\n3. \u270d\ufe0f **Author** one self-contained beginner issue \u2014 *\"draft a good first issue for this small task\"*\n4. \ud83d\udcd6 **Explain** an existing issue in beginner terms \u2014 *\"explain issue 123 to a newcomer\"*\n\nMagpie drafts first. Comments, new issues, and labels require explicit maintainer confirmation.\n\n## \u2699\ufe0f Configure it\n\nSet up the project context before using these skills:\n\n- \ud83d\uddc2\ufe0f **Project** \u2014 `project.md` identifies the repository and project context for every mentoring skill\n- \ud83c\udff7\ufe0f **Good first issues** \u2014 `good-first-issue-config.md` and `issue-tracker-config.md` are required for sweep and author\n- \ud83d\udcac **Optional guidance** \u2014 `mentoring-welcome-config.md` controls welcomes; `newcomer-issue-explainer-config.md` shapes explanations\n\nConfigure personally with `/magpie-setup:setup config`.\nProject adoption with `/magpie-setup:setup adopt` is a maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"welcome the first-time contributor on issue 123\"*\n- *\"find newcomer-ready issues in the backlog\"*\n- *\"which issues need changes before getting a good first issue label?\"*\n- *\"draft a good first issue from this small task\"*\n- *\"explain issue 123 with the files to read and what done looks like\"*\n\nSecurity-sensitive threads are not suitable for these newcomer workflows.\nContributors who were already welcomed, and threads already handled, are skipped.\n\n## \ud83c\udfa8 Make it yours\n\nDescribe how your project's mentoring should work:\n\n- *\"make newcomer explanations include a first test to run\"*\n- *\"use our contribution guide when drafting welcome messages\"*\n\nReview the proposed override before using it.\nUseful to others? Ask *\"upstream this change to Magpie\"* to prepare a reusable contribution for review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the mentoring welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide mentoring`\n(`/magpie-setup-welcome-guide mentoring` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" python3 -m setup_preflight.welcome show --family mentoring --color=always\n```\n", "max_shown": 3, "reason": "first-run", "shown": 0 @@ -30,7 +30,7 @@ The pre-flight command printed: } ], "rules": { - "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." + "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." }, "verdict": "action" } diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-12-pairing-first-run/report.md b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-12-pairing-first-run/report.md index 758656596..2f547d0c7 100644 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-12-pairing-first-run/report.md +++ b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-12-pairing-first-run/report.md @@ -20,7 +20,7 @@ The pre-flight command printed: "code": "welcome", "facts": { "family": "pairing", - "guide": "# \ud83d\udc26 Magpie here \u2014 your pre-PR review sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83d\udd0d **Self-review** your local diff before pushing \u2014 *\"review my diff before I push\"*\n2. \ud83d\udee1\ufe0f **Multi-agent review** the diff with independent correctness, security, and conventions passes \u2014 *\"run independent reviews of my branch\"*\n\nBoth skills return review reports. They never edit files, post comments, open PRs, push, or merge.\n\n## \u2699\ufe0f Configure it\n\nNothing is required before your first review:\n\n- \ud83d\udcd6 **Project context** \u2014 optionally use `project.md` for project-scoped references; otherwise the skills use their defaults\n- \ud83c\udfaf **Review scope** \u2014 choose a base ref, staged changes, or a path filter when needed\n\nConfigure it for yourself with `/magpie-setup:setup config`.\nAdopting shared configuration with `/magpie-setup:setup adopt` is a project maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"review my diff before I push\"*\n- *\"check my staged changes for correctness and security\"*\n- *\"review only the files under this directory\"*\n- *\"run three independent review passes on my branch\"*\n- *\"compare the correctness, security, and conventions findings\"*\n\nFor an already-open PR, use the PR-management code-review workflow instead.\n\n## \ud83c\udfa8 Make it yours\n\nDescribe how you want the review workflow to behave:\n\n- *\"focus my self-review on error handling and security risks\"*\n- *\"make the conventions review check our project's documented style\"*\n\nReview the proposed skill override before applying it.\nUseful to others? Ask *\"upstream this change to Magpie\"* to prepare a reusable contribution for your review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the pairing welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide pairing`\n(`/magpie-setup-welcome-guide pairing` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" python3 -m setup_preflight.welcome show --family pairing --color=always\n```\n", + "guide": "# \ud83d\udc26 Magpie here \u2014 your pre-PR review sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83d\udd0d **Self-review** your local diff before pushing \u2014 *\"review my diff before I push\"*\n2. \ud83d\udee1\ufe0f **Multi-agent review** the diff with independent correctness, security, and conventions passes \u2014 *\"run independent reviews of my branch\"*\n\nBoth skills return review reports. They never edit files, post comments, open PRs, push, or merge.\n\n## \u2699\ufe0f Configure it\n\nNothing is required before your first review:\n\n- \ud83d\udcd6 **Project context** \u2014 optionally use `project.md` for project-scoped references; otherwise the skills use their defaults\n- \ud83c\udfaf **Review scope** \u2014 choose a base ref, staged changes, or a path filter when needed\n\nConfigure it for yourself with `/magpie-setup:setup config`.\nAdopting shared configuration with `/magpie-setup:setup adopt` is a project maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"review my diff before I push\"*\n- *\"check my staged changes for correctness and security\"*\n- *\"review only the files under this directory\"*\n- *\"run three independent review passes on my branch\"*\n- *\"compare the correctness, security, and conventions findings\"*\n\nFor an already-open PR, use the PR-management code-review workflow instead.\n\n## \ud83c\udfa8 Make it yours\n\nDescribe how you want the review workflow to behave:\n\n- *\"focus my self-review on error handling and security risks\"*\n- *\"make the conventions review check our project's documented style\"*\n\nReview the proposed skill override before applying it.\nUseful to others? Ask *\"upstream this change to Magpie\"* to prepare a reusable contribution for your review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the pairing welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide pairing`\n(`/magpie-setup-welcome-guide pairing` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" python3 -m setup_preflight.welcome show --family pairing --color=always\n```\n", "max_shown": 3, "reason": "first-run", "shown": 0 @@ -30,7 +30,7 @@ The pre-flight command printed: } ], "rules": { - "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." + "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." }, "verdict": "action" } diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-13-issue-first-run/report.md b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-13-issue-first-run/report.md index e4c42fd74..c44e052c0 100644 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-13-issue-first-run/report.md +++ b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-13-issue-first-run/report.md @@ -20,7 +20,7 @@ The pre-flight command printed: "code": "welcome", "facts": { "family": "issue", - "guide": "# \ud83d\udc26 Magpie here \u2014 your issue-management sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83c\udff7\ufe0f **Triage** incoming issues and draft tracker replies \u2014 *\"triage the open issues\"*\n2. \ud83d\udd01 **Deduplicate** related reports and propose which to keep \u2014 *\"find duplicate issues\"*\n3. \ud83e\uddea **Reproduce** a reported bug from its code \u2014 *\"reproduce issue ABC-123\"*\n4. \ud83d\udd0d **Reassess** resolved or end-of-life issues against today's code \u2014 *\"re-assess old issues\"*\n5. \ud83d\udee0\ufe0f **Draft a fix** with tests and a hand-back \u2014 *\"draft a fix for ABC-123\"*\n6. \ud83e\uddf9 **Sweep stale issues** and review proposed actions \u2014 *\"find stale issues\"*\n7. \ud83d\udcca **Report** backlog and reassessment statistics \u2014 *\"show backlog statistics\"*\n\n`reassess-stats` reports on reassessment results; `backlog-stats` reports on the backlog.\nTracker comments and issue closures require confirmation.\nStale closures need a second confirmation.\nThe fix workflow opens a draft PR only with `--draft-pr` and explicit approval.\n\n## \u2699\ufe0f Configure it\n\nDifferent skills need different project settings:\n\n- \ud83d\uddc2\ufe0f **Tracker** \u2014 `issue-tracker-config.md` for triage, deduplication, reproduction, stale sweep, reassessment and statistics\n- \ud83d\udcd6 **Project** \u2014 `project.md` additionally for triage and stale sweep\n- \ud83e\uddea **Investigation** \u2014 `reproducer-conventions.md` and `runtime-invocation.md` for reproduction; `reassess-pool-defaults.md` for reassessment\n- \ud83d\udee0\ufe0f **Fixes** \u2014 `fix-workflow.md` and `runtime-invocation.md` for drafting fixes\n\nConfigure personally with `/magpie-setup:setup config`.\nShared adoption with `/magpie-setup:setup adopt` is a maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"triage these incoming bugs and show me draft replies\"*\n- *\"find duplicates without closing anything\"*\n- *\"reproduce this issue and explain what you found\"*\n- *\"reassess the issue backlog and summarize the results\"*\n- *\"draft a fix for this confirmed bug\"*\n- *\"review stale issues before posting or closing\"*\n- *\"show backlog and reassessment statistics\"*\n\n## \ud83c\udfa8 Make it yours\n\nDescribe how you want the issue workflow to behave:\n\n- *\"use our tracker conventions when drafting triage replies\"*\n- *\"adjust the stale-issue thresholds for this project\"*\n\nReview configuration or override proposals before applying them.\nUseful elsewhere? Ask *\"upstream this change to Magpie\"* to prepare a contribution for review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the issue welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide issue`\n(`/magpie-setup-welcome-guide issue` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" python3 -m setup_preflight.welcome show --family issue --color=always\n```\n", + "guide": "# \ud83d\udc26 Magpie here \u2014 your issue-management sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83c\udff7\ufe0f **Triage** incoming issues and draft tracker replies \u2014 *\"triage the open issues\"*\n2. \ud83d\udd01 **Deduplicate** related reports and propose which to keep \u2014 *\"find duplicate issues\"*\n3. \ud83e\uddea **Reproduce** a reported bug from its code \u2014 *\"reproduce issue ABC-123\"*\n4. \ud83d\udd0d **Reassess** resolved or end-of-life issues against today's code \u2014 *\"re-assess old issues\"*\n5. \ud83d\udee0\ufe0f **Draft a fix** with tests and a hand-back \u2014 *\"draft a fix for ABC-123\"*\n6. \ud83e\uddf9 **Sweep stale issues** and review proposed actions \u2014 *\"find stale issues\"*\n7. \ud83d\udcca **Report** backlog and reassessment statistics \u2014 *\"show backlog statistics\"*\n\n`reassess-stats` reports on reassessment results; `backlog-stats` reports on the backlog.\nTracker comments and issue closures require confirmation.\nStale closures need a second confirmation.\nThe fix workflow opens a draft PR only with `--draft-pr` and explicit approval.\n\n## \u2699\ufe0f Configure it\n\nDifferent skills need different project settings:\n\n- \ud83d\uddc2\ufe0f **Tracker** \u2014 `issue-tracker-config.md` for triage, deduplication, reproduction, stale sweep, reassessment and statistics\n- \ud83d\udcd6 **Project** \u2014 `project.md` additionally for triage and stale sweep\n- \ud83e\uddea **Investigation** \u2014 `reproducer-conventions.md` and `runtime-invocation.md` for reproduction; `reassess-pool-defaults.md` for reassessment\n- \ud83d\udee0\ufe0f **Fixes** \u2014 `fix-workflow.md` and `runtime-invocation.md` for drafting fixes\n\nConfigure personally with `/magpie-setup:setup config`.\nShared adoption with `/magpie-setup:setup adopt` is a maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"triage these incoming bugs and show me draft replies\"*\n- *\"find duplicates without closing anything\"*\n- *\"reproduce this issue and explain what you found\"*\n- *\"reassess the issue backlog and summarize the results\"*\n- *\"draft a fix for this confirmed bug\"*\n- *\"review stale issues before posting or closing\"*\n- *\"show backlog and reassessment statistics\"*\n\n## \ud83c\udfa8 Make it yours\n\nDescribe how you want the issue workflow to behave:\n\n- *\"use our tracker conventions when drafting triage replies\"*\n- *\"adjust the stale-issue thresholds for this project\"*\n\nReview configuration or override proposals before applying them.\nUseful elsewhere? Ask *\"upstream this change to Magpie\"* to prepare a contribution for review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the issue welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide issue`\n(`/magpie-setup-welcome-guide issue` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" python3 -m setup_preflight.welcome show --family issue --color=always\n```\n", "max_shown": 3, "reason": "first-run", "shown": 0 @@ -30,7 +30,7 @@ The pre-flight command printed: } ], "rules": { - "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." + "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." }, "verdict": "action" } diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-14-pr-management-first-run/report.md b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-14-pr-management-first-run/report.md index bb0c73671..9fa1aadfb 100644 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-14-pr-management-first-run/report.md +++ b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-14-pr-management-first-run/report.md @@ -20,7 +20,7 @@ The pre-flight command printed: "code": "welcome", "facts": { "family": "pr-management", - "guide": "# \ud83d\udc26 Magpie here \u2014 your PR-management sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \u2699\ufe0f Configure it\n\nStart with ``, the project's review criteria and its area labels.\n`pr-management-code-review-criteria.md` names the criteria sources;\n`pr-management-config.md` carries the labels and queue rules.\n`reviewer-roster.md` tells reviewer routing who covers each area.\n\n- **Configure it for yourself** \u2014 personal configuration, nothing committed \u2014 `/magpie-setup:setup config`\n- **Adopted** \u2014 for your project: shared configuration committed to the repo \u2014 `/magpie-setup:setup adopt` (a maintainers' decision)\n\nOn a pinned-snapshot install, use `/magpie-setup config` or `/magpie-setup adopt`.\n\nOptional companion: roborev reviews your own branch before it becomes a PR;\nthis family helps you review and manage other people's PRs.\nNeither requires the other.\n\n## \ud83d\udd04 The typical flow\n\n1. **Triage the queue** \u2014 propose a disposition for each PR \u2014 *\"triage the open PRs\"*\n2. **Route reviewers** \u2014 use the roster to suggest the right people \u2014 *\"who should review this PR?\"*\n3. **Review** \u2014 inspect the diff and draft inline feedback \u2014 *\"review this PR against our criteria\"*\n4. **Quick-merge** \u2014 screen easy candidates and propose the command for you to run \u2014 *\"which PRs are ready for quick-merge?\"*\n5. **Mentor** \u2014 help a contributor through the next step \u2014 *\"draft helpful feedback for this contributor\"*\n6. **Stale sweep** \u2014 propose follow-ups for inactive PRs \u2014 *\"show me the stale PRs\"*\n7. **Stats** \u2014 see where the queue needs attention \u2014 *\"summarise the PR backlog by area\"*\n\nNothing is written, posted, labelled or closed without your explicit confirmation.\nQuick-merge never merges for you: it hands you the command.\n\n## \ud83d\udcac Just ask\n\n- *\"check my branch before I open my first PR\"*\n- *\"triage the PRs waiting for review\"*\n- *\"who should review this PR?\"*\n- *\"review this PR against our criteria\"*\n- *\"review this PR stack in dependency order\"*\n- *\"which PRs are ready for quick-merge?\"*\n- *\"help this contributor understand the requested change\"*\n- *\"what changed in the queue since the last sweep?\"*\n- *\"summarise the PR backlog by area\"*\n\n## \ud83c\udfa8 Make it yours\n\nChange a workflow by describing the change:\n\n- *\"from now on, group the backlog by our area labels\"*\n- *\"use our review criteria when drafting feedback\"*\n\nEach becomes an override for the PR-management skill it changes.\nUseful to other maintainers? *\"Upstream this change to Magpie\"* prepares a generic PR for you to review before it opens.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the pr-management welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide pr-management`\n(`/magpie-setup-welcome-guide pr-management` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" python3 -m setup_preflight.welcome show --family pr-management --color=always\n```\n", + "guide": "# \ud83d\udc26 Magpie here \u2014 your PR-management sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \u2699\ufe0f Configure it\n\nStart with ``, the project's review criteria and its area labels.\n`pr-management-code-review-criteria.md` names the criteria sources;\n`pr-management-config.md` carries the labels and queue rules.\n`reviewer-roster.md` tells reviewer routing who covers each area.\n\n- **Configure it for yourself** \u2014 personal configuration, nothing committed \u2014 `/magpie-setup:setup config`\n- **Adopted** \u2014 for your project: shared configuration committed to the repo \u2014 `/magpie-setup:setup adopt` (a maintainers' decision)\n\nOn a pinned-snapshot install, use `/magpie-setup config` or `/magpie-setup adopt`.\n\nOptional companion: roborev reviews your own branch before it becomes a PR;\nthis family helps you review and manage other people's PRs.\nNeither requires the other.\n\n## \ud83d\udd04 The typical flow\n\n1. **Triage the queue** \u2014 propose a disposition for each PR \u2014 *\"triage the open PRs\"*\n2. **Route reviewers** \u2014 use the roster to suggest the right people \u2014 *\"who should review this PR?\"*\n3. **Review** \u2014 inspect the diff and draft inline feedback \u2014 *\"review this PR against our criteria\"*\n4. **Quick-merge** \u2014 screen easy candidates and propose the command for you to run \u2014 *\"which PRs are ready for quick-merge?\"*\n5. **Mentor** \u2014 help a contributor through the next step \u2014 *\"draft helpful feedback for this contributor\"*\n6. **Stale sweep** \u2014 propose follow-ups for inactive PRs \u2014 *\"show me the stale PRs\"*\n7. **Stats** \u2014 see where the queue needs attention \u2014 *\"summarise the PR backlog by area\"*\n\nNothing is written, posted, labelled or closed without your explicit confirmation.\nQuick-merge never merges for you: it hands you the command.\n\n## \ud83d\udcac Just ask\n\n- *\"check my branch before I open my first PR\"*\n- *\"triage the PRs waiting for review\"*\n- *\"who should review this PR?\"*\n- *\"review this PR against our criteria\"*\n- *\"review this PR stack in dependency order\"*\n- *\"which PRs are ready for quick-merge?\"*\n- *\"help this contributor understand the requested change\"*\n- *\"what changed in the queue since the last sweep?\"*\n- *\"summarise the PR backlog by area\"*\n\n## \ud83c\udfa8 Make it yours\n\nChange a workflow by describing the change:\n\n- *\"from now on, group the backlog by our area labels\"*\n- *\"use our review criteria when drafting feedback\"*\n\nEach becomes an override for the PR-management skill it changes.\nUseful to other maintainers? *\"Upstream this change to Magpie\"* prepares a generic PR for you to review before it opens.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the pr-management welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide pr-management`\n(`/magpie-setup-welcome-guide pr-management` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" python3 -m setup_preflight.welcome show --family pr-management --color=always\n```\n", "max_shown": 3, "reason": "first-run", "shown": 0 @@ -30,7 +30,7 @@ The pre-flight command printed: } ], "rules": { - "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." + "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." }, "verdict": "action" } diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-15-contributor-growth-first-run/report.md b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-15-contributor-growth-first-run/report.md index 313d1cb9b..33ae6676e 100644 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-15-contributor-growth-first-run/report.md +++ b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-15-contributor-growth-first-run/report.md @@ -20,7 +20,7 @@ The pre-flight command printed: "code": "welcome", "facts": { "family": "contributor-growth", - "guide": "# \ud83d\udc26 Magpie here \u2014 your contributor-growth sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83d\udcca **Activity sweep** across code, reviews, and issues \u2014 *\"sweep activity for \"*\n2. \ud83e\udeaa **Identity map** across GitHub, mailing lists, and chat handles \u2014 *\"map identities for \"*\n3. \ud83d\udcc8 **Compare activity with reference levels** as plain numbers \u2014 *\"track 's path to committer\"*\n4. \ud83d\udcdd **Nomination brief** compiling evidence for a private list discussion \u2014 *\"build nomination brief for \"*\n5. \ud83d\udd0d **Candidate screen** across recent contributors without ranking \u2014 *\"screen contributor candidates\"*\n6. \ud83e\udd1d **Committer onboarding** walkthrough for ICLA and account setup \u2014 *\"onboard new committer \"*\n7. \ud83d\udcac **Sentiment check** to identify contributor friction or disengagement \u2014 *\"check contributor sentiment\"*\n\nNothing is ranked, decided, or posted without your OK.\n\n## \u2699\ufe0f Configure it\n\nEach skill reads `project.md`, plus the file for its own job:\n\n- \ud83d\udccf **Reference levels** \u2014 `committer-readiness.md` for the path-to-committer comparison, calibration and candidate screen; information only, never a readiness verdict\n- \ud83d\udcdd **Nominations** \u2014 `contributor-nomination-config.md` for briefs, calibration and screening\n- \ud83d\udd12 **Private governance** \u2014 calibration reads past votes on ``, so it also needs an approved model in `privacy-llm.md`; nothing from it reaches a public surface\n- \ud83e\udd1d **Onboarding and sentiment** \u2014 `committer-onboarding-config.md`, `onboarding-concierge-config.md` and `contributor-sentiment-config.md`\n\nConfigure it for yourself with `/magpie-setup:setup config`.\nProject adoption with `/magpie-setup:setup adopt` is a maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"sweep activity for over the last 6 months\"*\n- *\"map identities for \"*\n- *\"how does 's activity compare with reference levels?\"*\n- *\"assemble a nomination brief for \"*\n- *\"calibrate committer reference levels from past nominations\"*\n- *\"screen active contributors for mentoring candidates\"*\n- *\"guide a newcomer through first-time contributor onboarding\"*\n- *\"guide committer onboarding for \"*\n- *\"are contributors encountering friction in PR reviews?\"*\n\n## \ud83c\udfa8 Make it yours\n\nEvery workflow, threshold, and community policy can be tailored.\nDescribe what your project needs:\n\n- *\"evaluate activity across 12 months rather than 6\"*\n- *\"tune committer onboarding steps for our project\"*\n\nYour requests save as local skill overrides.\nThink an adjustment benefits other projects? Asking *\"Upstream this change to Magpie\"* prepares a contribution PR for review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the contributor-growth welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide contributor-growth`\n(`/magpie-setup-welcome-guide contributor-growth` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" python3 -m setup_preflight.welcome show --family contributor-growth --color=always\n```\n", + "guide": "# \ud83d\udc26 Magpie here \u2014 your contributor-growth sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83d\udcca **Activity sweep** across code, reviews, and issues \u2014 *\"sweep activity for \"*\n2. \ud83e\udeaa **Identity map** across GitHub, mailing lists, and chat handles \u2014 *\"map identities for \"*\n3. \ud83d\udcc8 **Compare activity with reference levels** as plain numbers \u2014 *\"track 's path to committer\"*\n4. \ud83d\udcdd **Nomination brief** compiling evidence for a private list discussion \u2014 *\"build nomination brief for \"*\n5. \ud83d\udd0d **Candidate screen** across recent contributors without ranking \u2014 *\"screen contributor candidates\"*\n6. \ud83e\udd1d **Committer onboarding** walkthrough for ICLA and account setup \u2014 *\"onboard new committer \"*\n7. \ud83d\udcac **Sentiment check** to identify contributor friction or disengagement \u2014 *\"check contributor sentiment\"*\n\nNothing is ranked, decided, or posted without your OK.\n\n## \u2699\ufe0f Configure it\n\nEach skill reads `project.md`, plus the file for its own job:\n\n- \ud83d\udccf **Reference levels** \u2014 `committer-readiness.md` for the path-to-committer comparison, calibration and candidate screen; information only, never a readiness verdict\n- \ud83d\udcdd **Nominations** \u2014 `contributor-nomination-config.md` for briefs, calibration and screening\n- \ud83d\udd12 **Private governance** \u2014 calibration reads past votes on ``, so it also needs an approved model in `privacy-llm.md`; nothing from it reaches a public surface\n- \ud83e\udd1d **Onboarding and sentiment** \u2014 `committer-onboarding-config.md`, `onboarding-concierge-config.md` and `contributor-sentiment-config.md`\n\nConfigure it for yourself with `/magpie-setup:setup config`.\nProject adoption with `/magpie-setup:setup adopt` is a maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"sweep activity for over the last 6 months\"*\n- *\"map identities for \"*\n- *\"how does 's activity compare with reference levels?\"*\n- *\"assemble a nomination brief for \"*\n- *\"calibrate committer reference levels from past nominations\"*\n- *\"screen active contributors for mentoring candidates\"*\n- *\"guide a newcomer through first-time contributor onboarding\"*\n- *\"guide committer onboarding for \"*\n- *\"are contributors encountering friction in PR reviews?\"*\n\n## \ud83c\udfa8 Make it yours\n\nEvery workflow, threshold, and community policy can be tailored.\nDescribe what your project needs:\n\n- *\"evaluate activity across 12 months rather than 6\"*\n- *\"tune committer onboarding steps for our project\"*\n\nYour requests save as local skill overrides.\nThink an adjustment benefits other projects? Asking *\"Upstream this change to Magpie\"* prepares a contribution PR for review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the contributor-growth welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide contributor-growth`\n(`/magpie-setup-welcome-guide contributor-growth` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" python3 -m setup_preflight.welcome show --family contributor-growth --color=always\n```\n", "max_shown": 3, "reason": "first-run", "shown": 0 @@ -30,7 +30,7 @@ The pre-flight command printed: } ], "rules": { - "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." + "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." }, "verdict": "action" } diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-19-repo-health-first-run/report.md b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-19-repo-health-first-run/report.md index edff9c542..e7f800027 100644 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-19-repo-health-first-run/report.md +++ b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-19-repo-health-first-run/report.md @@ -20,7 +20,7 @@ The pre-flight command printed: "code": "welcome", "facts": { "family": "repo-health", - "guide": "# \ud83d\udc26 Magpie here \u2014 your repository-health sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83c\udfc3 **Audit CI runners** for outdated labels \u2014 *\"audit our CI runners\"*\n2. \ud83d\udd12 **Check workflows** for security risks \u2014 *\"audit workflow security\"*\n3. \ud83d\udce6 **Audit dependencies** for vulnerabilities and licenses \u2014 *\"audit dependencies\"* / *\"check dependency licenses\"*\n4. \ud83d\udcdc **Check compliance** across LICENSE and NOTICE \u2014 *\"check license compliance\"*\n5. \ud83e\uddea **Triage flaky tests** to separate flakes from regressions \u2014 *\"find flaky tests\"*\n6. \ud83d\udee0\ufe0f **Draft a fix** for an audit finding \u2014 *\"draft a fix for this finding\"*\n\nThe six audit skills report findings without modifying project files.\n`audit-finding-fix` edits and commits a fix locally, asking before each write; `--draft-pr` opens a draft PR only after a further explicit OK.\n\n## \u2699\ufe0f Configure it\n\nSome skills need project-specific settings:\n\n- \u2699\ufe0f **Audit policy** \u2014 `repo-health-config.md` for dependency, workflow-security, license-compliance and flaky-test audits\n- \ud83d\udee0\ufe0f **Fix workflow** \u2014 `fix-workflow.md` and `runtime-invocation.md` for `audit-finding-fix`\n- \ud83d\udccb **Other audits** \u2014 CI runner and dependency-license audits have no required config\n\nConfigure personally with `/magpie-setup:setup config`.\nProject adoption with `/magpie-setup:setup adopt` is a maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"find obsolete CI runner labels\"*\n- *\"check GitHub Actions permissions and triggers\"*\n- *\"audit dependency vulnerabilities and licenses\"*\n- *\"check LICENSE and NOTICE compliance\"*\n- *\"investigate flaky tests in CI\"*\n- *\"draft a tested fix for this audit finding\"*\n\n## \ud83c\udfa8 Make it yours\n\nDescribe the checks or reporting style you prefer:\n\n- *\"use our project's flaky-test thresholds\"*\n- *\"focus workflow security findings on high-risk triggers\"*\n\nEach becomes an override for the repo-health skill it changes.\nUseful elsewhere? Ask *\"upstream this change to Magpie\"* to prepare a contribution for review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the repo-health welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide repo-health`\n(`/magpie-setup-welcome-guide repo-health` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" python3 -m setup_preflight.welcome show --family repo-health --color=always\n```\n", + "guide": "# \ud83d\udc26 Magpie here \u2014 your repository-health sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83c\udfc3 **Audit CI runners** for outdated labels \u2014 *\"audit our CI runners\"*\n2. \ud83d\udd12 **Check workflows** for security risks \u2014 *\"audit workflow security\"*\n3. \ud83d\udce6 **Audit dependencies** for vulnerabilities and licenses \u2014 *\"audit dependencies\"* / *\"check dependency licenses\"*\n4. \ud83d\udcdc **Check compliance** across LICENSE and NOTICE \u2014 *\"check license compliance\"*\n5. \ud83e\uddea **Triage flaky tests** to separate flakes from regressions \u2014 *\"find flaky tests\"*\n6. \ud83d\udee0\ufe0f **Draft a fix** for an audit finding \u2014 *\"draft a fix for this finding\"*\n\nThe six audit skills report findings without modifying project files.\n`audit-finding-fix` edits and commits a fix locally, asking before each write; `--draft-pr` opens a draft PR only after a further explicit OK.\n\n## \u2699\ufe0f Configure it\n\nSome skills need project-specific settings:\n\n- \u2699\ufe0f **Audit policy** \u2014 `repo-health-config.md` for dependency, workflow-security, license-compliance and flaky-test audits\n- \ud83d\udee0\ufe0f **Fix workflow** \u2014 `fix-workflow.md` and `runtime-invocation.md` for `audit-finding-fix`\n- \ud83d\udccb **Other audits** \u2014 CI runner and dependency-license audits have no required config\n\nConfigure personally with `/magpie-setup:setup config`.\nProject adoption with `/magpie-setup:setup adopt` is a maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"find obsolete CI runner labels\"*\n- *\"check GitHub Actions permissions and triggers\"*\n- *\"audit dependency vulnerabilities and licenses\"*\n- *\"check LICENSE and NOTICE compliance\"*\n- *\"investigate flaky tests in CI\"*\n- *\"draft a tested fix for this audit finding\"*\n\n## \ud83c\udfa8 Make it yours\n\nDescribe the checks or reporting style you prefer:\n\n- *\"use our project's flaky-test thresholds\"*\n- *\"focus workflow security findings on high-risk triggers\"*\n\nEach becomes an override for the repo-health skill it changes.\nUseful elsewhere? Ask *\"upstream this change to Magpie\"* to prepare a contribution for review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the repo-health welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide repo-health`\n(`/magpie-setup-welcome-guide repo-health` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" python3 -m setup_preflight.welcome show --family repo-health --color=always\n```\n", "max_shown": 3, "reason": "first-run", "shown": 0 @@ -30,7 +30,7 @@ The pre-flight command printed: } ], "rules": { - "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." + "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." }, "verdict": "action" } diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/expected.json b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/expected.json deleted file mode 100644 index 2adc36dfb..000000000 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/expected.json +++ /dev/null @@ -1 +0,0 @@ -{"action": "welcome", "commands": [], "blocks": false} diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/state.json b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/state.json deleted file mode 100644 index 18616267e..000000000 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/state.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "lock": null, - "plugins": [ - [ - "magpie-setup", - "0.4.0" - ] - ], - "reconciled": { - "welcome": { - "general": { - "choice": "seen", - "shown": 1 - } - } - }, - "skill": "status", - "welcome": true, - "hash": "sha256:85dfb8b48739fc11" -} diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-21-release-management-first-run/report.md b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-21-release-management-first-run/report.md index 7603b5939..8afa25ec1 100644 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-21-release-management-first-run/report.md +++ b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-21-release-management-first-run/report.md @@ -20,7 +20,7 @@ The pre-flight command printed: "code": "welcome", "facts": { "family": "release-management", - "guide": "# \ud83d\udc26 Magpie here \u2014 your release-management sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83d\udccb **Prepare** the release plan and version bump \u2014 *\"plan our next release\"*\n2. \ud83d\udd11 **Check KEYS** before RC signing \u2014 *\"sync the release signing key\"*\n3. \ud83d\udce6 **Cut an RC** and prepare signing/staging commands \u2014 *\"cut rc1 for this version\"*\n4. \u2705 **Verify the RC** before a vote \u2014 *\"verify the staged release candidate\"*\n5. \ud83d\uddf3\ufe0f **Draft the vote**, then tally results \u2014 *\"draft the vote email\"* / *\"tally the votes\"*\n6. \ud83d\ude80 **Promote** a release only after approval \u2014 *\"prepare promotion commands\"*\n7. \ud83d\udce3 **Draft the announcement**, then review archive cleanup \u2014 *\"draft the announcement\"*\n8. \ud83d\udcca **Audit** the completed release evidence \u2014 *\"prepare the release audit report\"*\n\nThese steps are guided workflows, not autonomous publishing.\nThe Release Manager keeps the signing key and runs signing and publication commands.\nVote and announcement emails are drafts, never automatically sent.\nReview and explicitly approve proposed external or repository changes.\n\n## \u2699\ufe0f Configure it\n\nRelease skills use project-specific configuration:\n\n- \u2699\ufe0f **Release policy** \u2014 `release-management-config.md` for planning, votes, announcements, archives, audit reports and KEYS\n- \ud83d\udce6 **Build and staging** \u2014 `release-build.md` for `rc-cut` and `verify-rc`\n- \ud83d\uddf3\ufe0f **Approval roster** \u2014 `pmc-roster.md` for `vote-tally` and `promote`\n- \ud83d\ude86 **Release trains** \u2014 `release-trains.md` for `prepare` and `archive-sweep`\n\nThe distribution, approval and announcement backends are set in `release-management-config.md`.\nConfigure personally with `/magpie-setup:setup config`.\nTeam adoption with `/magpie-setup:setup adopt` is a maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"prepare the release plan for our next version\"*\n- *\"check that my public signing key is in KEYS\"*\n- *\"give me the commands to cut and verify rc1\"*\n- *\"draft a vote email for this verified RC\"*\n- *\"tally the release vote and prepare the result draft\"*\n- *\"prepare promotion and announcement after the vote passes\"*\n- *\"review old release archives and generate an audit report\"*\n\n## \ud83c\udfa8 Make it yours\n\nDescribe your release policy and preferred backend:\n\n- *\"use a 96-hour vote window instead of 72\"*\n- *\"always run the KEYS check before cutting an RC\"*\n\nReview proposed configuration or override changes before applying them.\nUseful elsewhere? Ask *\"upstream this change to Magpie\"* to prepare a contribution for review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the release-management welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide release-management`\n(`/magpie-setup-welcome-guide release-management` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" python3 -m setup_preflight.welcome show --family release-management --color=always\n```\n", + "guide": "# \ud83d\udc26 Magpie here \u2014 your release-management sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83d\udccb **Prepare** the release plan and version bump \u2014 *\"plan our next release\"*\n2. \ud83d\udd11 **Check KEYS** before RC signing \u2014 *\"sync the release signing key\"*\n3. \ud83d\udce6 **Cut an RC** and prepare signing/staging commands \u2014 *\"cut rc1 for this version\"*\n4. \u2705 **Verify the RC** before a vote \u2014 *\"verify the staged release candidate\"*\n5. \ud83d\uddf3\ufe0f **Draft the vote**, then tally results \u2014 *\"draft the vote email\"* / *\"tally the votes\"*\n6. \ud83d\ude80 **Promote** a release only after approval \u2014 *\"prepare promotion commands\"*\n7. \ud83d\udce3 **Draft the announcement**, then review archive cleanup \u2014 *\"draft the announcement\"*\n8. \ud83d\udcca **Audit** the completed release evidence \u2014 *\"prepare the release audit report\"*\n\nThese steps are guided workflows, not autonomous publishing.\nThe Release Manager keeps the signing key and runs signing and publication commands.\nVote and announcement emails are drafts, never automatically sent.\nReview and explicitly approve proposed external or repository changes.\n\n## \u2699\ufe0f Configure it\n\nRelease skills use project-specific configuration:\n\n- \u2699\ufe0f **Release policy** \u2014 `release-management-config.md` for planning, votes, announcements, archives, audit reports and KEYS\n- \ud83d\udce6 **Build and staging** \u2014 `release-build.md` for `rc-cut` and `verify-rc`\n- \ud83d\uddf3\ufe0f **Approval roster** \u2014 `pmc-roster.md` for `vote-tally` and `promote`\n- \ud83d\ude86 **Release trains** \u2014 `release-trains.md` for `prepare` and `archive-sweep`\n\nThe distribution, approval and announcement backends are set in `release-management-config.md`.\nConfigure personally with `/magpie-setup:setup config`.\nTeam adoption with `/magpie-setup:setup adopt` is a maintainer decision.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"prepare the release plan for our next version\"*\n- *\"check that my public signing key is in KEYS\"*\n- *\"give me the commands to cut and verify rc1\"*\n- *\"draft a vote email for this verified RC\"*\n- *\"tally the release vote and prepare the result draft\"*\n- *\"prepare promotion and announcement after the vote passes\"*\n- *\"review old release archives and generate an audit report\"*\n\n## \ud83c\udfa8 Make it yours\n\nDescribe your release policy and preferred backend:\n\n- *\"use a 96-hour vote window instead of 72\"*\n- *\"always run the KEYS check before cutting an RC\"*\n\nReview proposed configuration or override changes before applying them.\nUseful elsewhere? Ask *\"upstream this change to Magpie\"* to prepare a contribution for review.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the release-management welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide release-management`\n(`/magpie-setup-welcome-guide release-management` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" python3 -m setup_preflight.welcome show --family release-management --color=always\n```\n", "max_shown": 3, "reason": "first-run", "shown": 0 @@ -30,7 +30,7 @@ The pre-flight command printed: } ], "rules": { - "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." + "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." }, "verdict": "action" } diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-9-first-magpie-run/report.md b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-9-first-magpie-run/report.md index ce1b5e8c9..0126025f3 100644 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-9-first-magpie-run/report.md +++ b/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-9-first-magpie-run/report.md @@ -20,7 +20,7 @@ The pre-flight command printed: "code": "welcome", "facts": { "family": "general", - "guide": "# \ud83d\udc26 Hello from Magpie \u2014 your project's maintainer sidekick\n\nOne minute, then straight back to what you asked for.\n\n## \ud83d\ude80 Getting started\n\n- \ud83d\udce6 **Install** from your agent's marketplace (Claude Code shown):\n `/plugin marketplace add apache/magpie`,\n then `/plugin install magpie-setup@apache-magpie` and one `/plugin install magpie-@apache-magpie` per family you want\n- \ud83d\ude4b **Configure it for yourself** \u2014 personal settings, nothing committed \u2014 `/magpie-setup:setup config`\n- \ud83d\udc65 **Adopt it for your project** \u2014 the configuration is committed to your repo and shared with every contributor \u2014\n `/magpie-setup:setup adopt` (a maintainers' decision)\n\nOn a pinned-snapshot install the commands are shorter: `/magpie-setup config`, `/magpie-setup adopt`.\n\n## \ud83d\udd04 Staying current\n\n- \u270b **By hand:** `claude plugin marketplace update apache-magpie`, then `claude plugin update @apache-magpie`\n- \ud83e\udd16 **Automatically (Claude Code):** `/plugin` \u2192 **Marketplaces** \u2192 **apache-magpie** \u2192 **Enable auto-update** \u2014\n it is off by default for third-party marketplaces like this one\n- \ud83e\udde9 Gemini CLI takes `--auto-update` at install time; Codex has no auto-update, so run `codex plugin marketplace upgrade apache-magpie`\n\nAfter an update, the next skill you run checks your configuration against it and proposes any fixes;\n`/magpie-setup:setup reconcile` checks everything at once (on a pinned snapshot, `/magpie-setup upgrade` does the update).\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language \u2014 no syntax to learn.\nNothing is written, posted, or sent without your OK.\nInterrupt at any time, say no, or change your mind halfway through.\n\n## \ud83c\udfa8 You are the creator\n\nDescribe what you want a skill to do for you:\n\n- *\"from now on, always ask me before closing a stale issue\"*\n- *\"when you triage PRs, leave the bot-authored ones alone\"*\n\nMagpie records it as an override for that skill (`/magpie-setup:setup override `).\nWorth sharing? Say *\"upstream this change to Magpie\"* \u2014 it makes the change generic and opens a PR to `apache/magpie` for you to review (`/magpie-setup:override-upstream`).\n\n## \ud83d\udcda More guides\n\nEach family can bring its own short guide, shown the first time you use it:\n\n- `contributor-growth` \u2014 `/magpie-setup:welcome-guide contributor-growth`\n- `issue` \u2014 `/magpie-setup:welcome-guide issue`\n- `mentoring` \u2014 `/magpie-setup:welcome-guide mentoring`\n- `pairing` \u2014 `/magpie-setup:welcome-guide pairing`\n- `pr-management` \u2014 `/magpie-setup:welcome-guide pr-management`\n- `release-management` \u2014 `/magpie-setup:welcome-guide release-management`\n- `repo-health` \u2014 `/magpie-setup:welcome-guide repo-health`\n- `security` \u2014 `/magpie-setup:welcome-guide security`\n- `setup` \u2014 `/magpie-setup:welcome-guide setup`\n- `utilities` \u2014 `/magpie-setup:welcome-guide utilities`\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the Magpie welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide []`\n(`/magpie-setup-welcome-guide []` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" python3 -m setup_preflight.welcome show --family general --color=always\n```\n", + "guide": "# \ud83d\udc26 Hello from Magpie \u2014 your project's maintainer sidekick\n\nOne minute, then straight back to what you asked for.\n\n## \ud83d\ude80 Getting started\n\n- \ud83d\udce6 **Install** from your agent's marketplace (Claude Code shown):\n `/plugin marketplace add apache/magpie`,\n then `/plugin install magpie-setup@apache-magpie` and one `/plugin install magpie-@apache-magpie` per family you want\n- \ud83d\ude4b **Configure it for yourself** \u2014 personal settings, nothing committed \u2014 `/magpie-setup:setup config`\n- \ud83d\udc65 **Adopt it for your project** \u2014 the configuration is committed to your repo and shared with every contributor \u2014\n `/magpie-setup:setup adopt` (a maintainers' decision)\n\nOn a pinned-snapshot install the commands are shorter: `/magpie-setup config`, `/magpie-setup adopt`.\n\n## \ud83d\udd04 Staying current\n\n- \u270b **By hand:** `claude plugin marketplace update apache-magpie`, then `claude plugin update @apache-magpie`\n- \ud83e\udd16 **Automatically (Claude Code):** `/plugin` \u2192 **Marketplaces** \u2192 **apache-magpie** \u2192 **Enable auto-update** \u2014\n it is off by default for third-party marketplaces like this one\n- \ud83e\udde9 Gemini CLI takes `--auto-update` at install time; Codex has no auto-update, so run `codex plugin marketplace upgrade apache-magpie`\n\nAfter an update, the next skill you run checks your configuration against it and proposes any fixes;\n`/magpie-setup:setup reconcile` checks everything at once (on a pinned snapshot, `/magpie-setup upgrade` does the update).\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language \u2014 no syntax to learn.\nNothing is written, posted, or sent without your OK.\nInterrupt at any time, say no, or change your mind halfway through.\n\n## \ud83c\udfa8 You are the creator\n\nDescribe what you want a skill to do for you:\n\n- *\"from now on, always ask me before closing a stale issue\"*\n- *\"when you triage PRs, leave the bot-authored ones alone\"*\n\nMagpie records it as an override for that skill (`/magpie-setup:setup override `).\nWorth sharing? Say *\"upstream this change to Magpie\"* \u2014 it makes the change generic and opens a PR to `apache/magpie` for you to review (`/magpie-setup:override-upstream`).\n\n## \ud83d\udcda More guides\n\nEach family can bring its own short guide, shown the first time you use it:\n\n- `contributor-growth` \u2014 `/magpie-setup:welcome-guide contributor-growth`\n- `issue` \u2014 `/magpie-setup:welcome-guide issue`\n- `mentoring` \u2014 `/magpie-setup:welcome-guide mentoring`\n- `pairing` \u2014 `/magpie-setup:welcome-guide pairing`\n- `pr-management` \u2014 `/magpie-setup:welcome-guide pr-management`\n- `release-management` \u2014 `/magpie-setup:welcome-guide release-management`\n- `repo-health` \u2014 `/magpie-setup:welcome-guide repo-health`\n- `security` \u2014 `/magpie-setup:welcome-guide security`\n- `setup` \u2014 `/magpie-setup:welcome-guide setup`\n- `utilities` \u2014 `/magpie-setup:welcome-guide utilities`\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the Magpie welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide []`\n(`/magpie-setup-welcome-guide []` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" python3 -m setup_preflight.welcome show --family general --color=always\n```\n", "max_shown": 3, "reason": "first-run", "shown": 0 @@ -30,7 +30,7 @@ The pre-flight command printed: } ], "rules": { - "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." + "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." }, "verdict": "action" } diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/case-meta.json b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/case-meta.json similarity index 100% rename from tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/case-meta.json rename to tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/case-meta.json diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/expected.json b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/expected.json new file mode 100644 index 000000000..0a0bc53db --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/expected.json @@ -0,0 +1 @@ +{"action": "welcome", "guide": "general", "commands": [], "blocks": false} diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/report.md b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/report.md new file mode 100644 index 000000000..ceb4ef0a0 --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/report.md @@ -0,0 +1,34 @@ + + +There is no `.apache-magpie.lock`, no `.apache-magpie-overrides/` and no +personal layer at `.git/apache-magpie/`. The running agent is Claude Code +with magpie-setup 0.4.0 installed. + +No Magpie skill has run here before. +The user invoked `/magpie-setup:setup config` to "configure Magpie for me". + +The welcome check printed: + +```json +{ + "findings": [ + { + "code": "welcome", + "facts": { + "family": "general", + "guide": "# \ud83d\udc26 Hello from Magpie \u2014 your project's maintainer sidekick\n\nOne minute, then straight back to what you asked for.\n\n## \ud83d\ude80 Getting started\n\n- \ud83d\udce6 **Install** from your agent's marketplace (Claude Code shown):\n `/plugin marketplace add apache/magpie`,\n then `/plugin install magpie-setup@apache-magpie` and one `/plugin install magpie-@apache-magpie` per family you want\n- \ud83d\ude4b **Configure it for yourself** \u2014 personal settings, nothing committed \u2014 `/magpie-setup:setup config`\n- \ud83d\udc65 **Adopt it for your project** \u2014 the configuration is committed to your repo and shared with every contributor \u2014\n `/magpie-setup:setup adopt` (a maintainers' decision)\n\nOn a pinned-snapshot install the commands are shorter: `/magpie-setup config`, `/magpie-setup adopt`.\n\n## \ud83d\udd04 Staying current\n\n- \u270b **By hand:** `claude plugin marketplace update apache-magpie`, then `claude plugin update @apache-magpie`\n- \ud83e\udd16 **Automatically (Claude Code):** `/plugin` \u2192 **Marketplaces** \u2192 **apache-magpie** \u2192 **Enable auto-update** \u2014\n it is off by default for third-party marketplaces like this one\n- \ud83e\udde9 Gemini CLI takes `--auto-update` at install time; Codex has no auto-update, so run `codex plugin marketplace upgrade apache-magpie`\n\nAfter an update, the next skill you run checks your configuration against it and proposes any fixes;\n`/magpie-setup:setup reconcile` checks everything at once (on a pinned snapshot, `/magpie-setup upgrade` does the update).\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language \u2014 no syntax to learn.\nNothing is written, posted, or sent without your OK.\nInterrupt at any time, say no, or change your mind halfway through.\n\n## \ud83c\udfa8 You are the creator\n\nDescribe what you want a skill to do for you:\n\n- *\"from now on, always ask me before closing a stale issue\"*\n- *\"when you triage PRs, leave the bot-authored ones alone\"*\n\nMagpie records it as an override for that skill (`/magpie-setup:setup override `).\nWorth sharing? Say *\"upstream this change to Magpie\"* \u2014 it makes the change generic and opens a PR to `apache/magpie` for you to review (`/magpie-setup:override-upstream`).\n\n## \ud83d\udcda More guides\n\nEach family can bring its own short guide, shown the first time you use it:\n\n- `contributor-growth` \u2014 `/magpie-setup:welcome-guide contributor-growth`\n- `issue` \u2014 `/magpie-setup:welcome-guide issue`\n- `mentoring` \u2014 `/magpie-setup:welcome-guide mentoring`\n- `pairing` \u2014 `/magpie-setup:welcome-guide pairing`\n- `pr-management` \u2014 `/magpie-setup:welcome-guide pr-management`\n- `release-management` \u2014 `/magpie-setup:welcome-guide release-management`\n- `repo-health` \u2014 `/magpie-setup:welcome-guide repo-health`\n- `security` \u2014 `/magpie-setup:welcome-guide security`\n- `setup` \u2014 `/magpie-setup:welcome-guide setup`\n- `utilities` \u2014 `/magpie-setup:welcome-guide utilities`\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the Magpie welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide []`\n(`/magpie-setup-welcome-guide []` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" python3 -m setup_preflight.welcome show --family general --color=always\n```\n", + "max_shown": 3, + "reason": "first-run", + "shown": 0 + }, + "scope": "family", + "section": "welcome" + } + ], + "rules": { + "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." + }, + "verdict": "action" +} +``` diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/state.json b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/state.json new file mode 100644 index 000000000..36fae1991 --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-1-first-magpie-run/state.json @@ -0,0 +1 @@ +{"check": "welcome-due", "skill": "setup", "reconciled": null} diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/case-meta.json b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/case-meta.json new file mode 100644 index 000000000..88c1f39aa --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/case-meta.json @@ -0,0 +1 @@ +{"tags":["local-smoke"]} diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/expected.json b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/expected.json new file mode 100644 index 000000000..4ce059290 --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/expected.json @@ -0,0 +1 @@ +{"action": "welcome", "guide": "setup", "commands": [], "blocks": false} diff --git a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/report.md b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/report.md similarity index 78% rename from tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/report.md rename to tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/report.md index cdc2b8437..6f9bd38d4 100644 --- a/tools/skill-evals/evals/setup/preflight-floor/fixtures/case-20-setup-first-run/report.md +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/report.md @@ -5,13 +5,11 @@ There is no `.apache-magpie.lock`, no `.apache-magpie-overrides/` and no `.apache-magpie-local/` at the repo root. The running agent is Claude Code with magpie-setup 0.4.0 installed. -The user has already seen the initial general welcome guide on an earlier run. -The invoked skill's own frontmatter reads `name: status` and -`surface_hash: sha256:85dfb8b48739fc11`; it belongs to the setup family. -This is the first time a setup skill has run here. -The user asked it to "show Magpie status". +The user has already seen the general welcome guide on an earlier run. +This is the first time the `setup` skill has run here. +The user invoked `/magpie-setup:setup verify`. -The pre-flight command printed: +The welcome check printed: ```json { @@ -20,7 +18,7 @@ The pre-flight command printed: "code": "welcome", "facts": { "family": "setup", - "guide": "# \ud83d\udc26 Magpie here \u2014 your setup sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83e\udded **Check status** \u2014 *\"show how Magpie is installed and adopted here\"*\n2. \ud83d\udee0\ufe0f **Install and configure** \u2014 *\"set up Magpie for me\"*\n3. \ud83d\udd10 **Isolate the agent** \u2014 *\"install the secure agent sandbox\"*\n4. \u2705 **Verify and diagnose** \u2014 *\"verify isolation\"* or *\"diagnose my sandbox\"*\n5. \ud83c\udd99 **Check for drift and upgrade** \u2014 *\"check my sandbox for drift\"* or *\"upgrade Magpie\"*\n6. \ud83c\udfd7\ufe0f **Adopt for the team** \u2014 *\"adopt Magpie for this repository\"*\n\nOther skills help configure LLM privacy, synchronize shared config, upstream useful overrides, propose framework bug fixes, and replay welcome guides.\n\nRead-only checks report findings.\nInstallation, adoption, upgrades, configuration writes, and repository changes follow their own approval steps.\nNever edit Magpie's gitignored, read-only framework snapshot directly.\n\n## \u2699\ufe0f Configure it\n\nNothing is required before using the Setup family:\n\n- \ud83d\udccb **Setup defaults** \u2014 optional `magpie-setup.md`\n- \ud83d\udd0f **Privacy policy** \u2014 optional `privacy-llm.md`\n- \ud83e\udde9 **Project identity** \u2014 optional `project.md`\n- \ud83d\udd17 **Trusted skill sources** \u2014 optional `skill-sources.md`\n\n`/magpie-setup:setup config` writes personal configuration.\n`/magpie-setup:setup adopt` proposes committed project-wide settings.\nReview the plan and confirm before any project-wide mutation.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"show Magpie status in this checkout\"*\n- *\"install Magpie and configure it just for me\"*\n- *\"secure the agent with a sandbox and verify it\"*\n- *\"set up privacy rules for model access\"*\n- *\"check for configuration drift after an upgrade\"*\n- *\"prepare a framework fix for this broken setup helper\"*\n\n## \ud83c\udfa8 Make it yours\n\nDescribe how your setup should behave:\n\n- *\"use our approved skill sources\"*\n- *\"keep my personal privacy rules separate from project policy\"*\n\nMagpie records each request as an override of the setup skill it touches.\nIf other projects would want it too, say *\"upstream this change to Magpie\"* and review the generic `apache/magpie` PR it prepares.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the setup welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide setup`\n(`/magpie-setup-welcome-guide setup` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" python3 -m setup_preflight.welcome show --family setup --color=always\n```\n", + "guide": "# \ud83d\udc26 Magpie here \u2014 your setup sidekick\n\nA one-minute tour, then straight back to what you asked for.\n\n## \ud83d\udd04 The typical flow\n\n1. \ud83e\udded **Check status** \u2014 *\"show how Magpie is installed and adopted here\"*\n2. \ud83d\udee0\ufe0f **Install and configure** \u2014 *\"set up Magpie for me\"*\n3. \ud83d\udd10 **Isolate the agent** \u2014 *\"install the secure agent sandbox\"*\n4. \u2705 **Verify and diagnose** \u2014 *\"verify isolation\"* or *\"diagnose my sandbox\"*\n5. \ud83c\udd99 **Check for drift and upgrade** \u2014 *\"check my sandbox for drift\"* or *\"upgrade Magpie\"*\n6. \ud83c\udfd7\ufe0f **Adopt for the team** \u2014 *\"adopt Magpie for this repository\"*\n\nOther skills help configure LLM privacy, synchronize shared config, upstream useful overrides, propose framework bug fixes, and replay welcome guides.\n\nRead-only checks report findings.\nInstallation, adoption, upgrades, configuration writes, and repository changes follow their own approval steps.\nNever edit Magpie's gitignored, read-only framework snapshot directly.\n\n## \u2699\ufe0f Configure it\n\nNothing is required before using the Setup family:\n\n- \ud83d\udccb **Setup defaults** \u2014 optional `magpie-setup.md`\n- \ud83d\udd0f **Privacy policy** \u2014 optional `privacy-llm.md`\n- \ud83e\udde9 **Project identity** \u2014 optional `project.md`\n- \ud83d\udd17 **Trusted skill sources** \u2014 optional `skill-sources.md`\n\n`/magpie-setup:setup config` writes personal configuration.\n`/magpie-setup:setup adopt` proposes committed project-wide settings.\nReview the plan and confirm before any project-wide mutation.\n\n## \ud83d\udcac Just ask\n\nTalk to Magpie in plain language:\n\n- *\"show Magpie status in this checkout\"*\n- *\"install Magpie and configure it just for me\"*\n- *\"secure the agent with a sandbox and verify it\"*\n- *\"set up privacy rules for model access\"*\n- *\"check for configuration drift after an upgrade\"*\n- *\"prepare a framework fix for this broken setup helper\"*\n\n## \ud83c\udfa8 Make it yours\n\nDescribe how your setup should behave:\n\n- *\"use our approved skill sources\"*\n- *\"keep my personal privacy rules separate from project policy\"*\n\nMagpie records each request as an override of the setup skill it touches.\nIf other projects would want it too, say *\"upstream this change to Magpie\"* and review the generic `apache/magpie` PR it prepares.\n\n## \ud83d\udc4b About this guide\n\n- **Continue** \u2014 show it again next time (three times at most)\n- **Dismiss** \u2014 hide it until the next Magpie upgrade\n- **Don't show again** \u2014 hide it for good; say *\"show the setup welcome again\"* to bring it back\n\nShow this again any time: `/magpie-setup:welcome-guide setup`\n(`/magpie-setup-welcome-guide setup` on a pinned snapshot).\n\n\ud83c\udf08 Prefer it in colour? Run this yourself \u2014 the `!` prefix runs it as a shell command:\n\n```text\n! PYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" python3 -m setup_preflight.welcome show --family setup --color=always\n```\n", "max_shown": 3, "reason": "first-run", "shown": 0 @@ -30,7 +28,7 @@ The pre-flight command printed: } ], "rules": { - "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." + "welcome": "## welcome \u2014 a first-run welcome guide is due\n\nA welcome guide is due on this run: `facts.family` names it\n(`general`, for the first Magpie skill this user runs here, or the skill's own family),\nand `facts.reason` says why (`first-run`, `again`, or `upgraded` after a dismissal).\n`facts.guide` is the guide. The checker shows at most one guide per run and has already picked it.\n\n1. **Show `facts.guide` to the user verbatim**, as Markdown, before the work they asked for.\n Do not summarise, reword, trim, or add to it, and substitute nothing in it:\n its placeholders (``, ``, ``, \u2026) are meant to be read as written.\n2. **Offer the three choices in one line**:\n **Continue** (show again next time) \u00b7 **Dismiss** (hide until the next Magpie upgrade) \u00b7 **Don't show again**.\n3. **Record `seen` at once**, which is what no answer means, then carry on with the user's request in the same turn.\n Never block the requested work on the guide, and never wait for an answer before starting it.\n4. **When the user picks Dismiss or Don't show again** \u2014 now or later in the session \u2014 record that choice;\n it replaces `seen`. Continue needs nothing further.\n\n```bash\nPYTHONPATH=\".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie\" \\\n python3 -m setup_preflight.welcome record --family --choice \n```\n\n`seen` brings the guide back on a later run, `facts.max_shown` recorded showings in all (`facts.shown` so far);\n`dismiss` hides it until the framework version changes; `never` hides it until re-enabled.\nEvery write merges into the personal layer's `reconciled.json` under `welcome.`, keeping every other key;\nnever write it by hand.\nIf the command exits non-zero, say nothing more about it and carry on.\n\nAny guide can be shown again on request with `/magpie-setup:welcome-guide []`,\nwhich also turns a hidden one back on." }, "verdict": "action" } diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/state.json b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/state.json new file mode 100644 index 000000000..477281b78 --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-2-setup-guide-after-general/state.json @@ -0,0 +1 @@ +{"check": "welcome-due", "skill": "setup", "reconciled": {"welcome": {"general": {"choice": "seen", "shown": 1}}}} diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/case-meta.json b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/case-meta.json new file mode 100644 index 000000000..88c1f39aa --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/case-meta.json @@ -0,0 +1 @@ +{"tags":["local-smoke"]} diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/expected.json b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/expected.json new file mode 100644 index 000000000..6193a5daf --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/expected.json @@ -0,0 +1 @@ +{"action": "silent", "guide": null, "commands": [], "blocks": false} diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/report.md b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/report.md new file mode 100644 index 000000000..d161a4f4e --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/report.md @@ -0,0 +1,19 @@ + + +There is no `.apache-magpie.lock` and no `.apache-magpie-overrides/`. +The personal layer at `.git/apache-magpie/` holds only a `reconciled.json` +recording the user's welcome-guide answers. The running agent is Claude Code +with magpie-setup 0.4.0 installed. + +The user hid both the general and the setup welcome guides for good on +earlier runs. No required configuration resolves here yet. +The user invoked `/magpie-setup:setup verify`. + +The welcome check printed: + +```json +{ + "verdict": "ok" +} +``` diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/state.json b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/state.json new file mode 100644 index 000000000..091388f30 --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/case-3-nothing-due/state.json @@ -0,0 +1 @@ +{"check": "welcome-due", "skill": "setup", "reconciled": {"welcome": {"general": {"choice": "never", "shown": 1}, "setup": {"choice": "never", "shown": 2}}}} diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/output-spec.md b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/output-spec.md new file mode 100644 index 000000000..1d53ad471 --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/output-spec.md @@ -0,0 +1,36 @@ + + +## Output format + +Return ONLY valid JSON with this structure: + +```json +{ + "action": "silent" | "welcome", + "guide": "general" | "setup" | null, + "commands": [...], + "blocks": true | false, + "reason": "" +} +``` + +`action` reports what this step does about the state described. The welcome +check's printed verdict is in the state: act on it through its `rules`. +`silent` means it prints nothing and the sub-action proceeds. +`welcome` means it showed a welcome guide, offered its three choices and +recorded the answer before carrying on. + +`guide` names the guide shown (`facts.family`), or `null` when none was. + +`commands` is the list of install, update or configuration commands this step +runs. Recording the welcome answer is not one, so it is `[]` whenever the step +only shows a guide; a step that ran the full pre-flight or `setup config` would +list it. + +`blocks` reports whether the step stops the sub-action rather than continuing +this turn. + +`reason` is one sentence saying why. + +Do not include any text outside the JSON object. diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/step-config.json b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/step-config.json new file mode 100644 index 000000000..2dd103f05 --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/step-config.json @@ -0,0 +1,4 @@ +{ + "skill_md": "plugins/magpie-setup/skills/setup/SKILL.md", + "step_heading": "## First — the welcome guide" +} diff --git a/tools/skill-evals/evals/setup/welcome-first-run/fixtures/user-prompt-template.md b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/user-prompt-template.md new file mode 100644 index 000000000..bd5e529e7 --- /dev/null +++ b/tools/skill-evals/evals/setup/welcome-first-run/fixtures/user-prompt-template.md @@ -0,0 +1,9 @@ + + +## Repo and machine state + +{report} + +You are at the start of the `setup` skill, before its sub-action. Report what +this first step does. Return JSON only. diff --git a/tools/spec-loop/specs/adoption-and-setup.md b/tools/spec-loop/specs/adoption-and-setup.md index 1fa20e66d..b1c52284f 100644 --- a/tools/spec-loop/specs/adoption-and-setup.md +++ b/tools/spec-loop/specs/adoption-and-setup.md @@ -82,7 +82,7 @@ acceptance: into `.apache-magpie-local/`. `worktree-init` copies or links no personal config: the fallback covers it. - Every skill's pre-flight runs the checker with - `PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie"`, + `PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/../.apache-magpie-local:$(git rev-parse --git-common-dir 2>/dev/null || echo .git)/apache-magpie:.svn/apache-magpie"`, so the copy is found in this checkout's `.apache-magpie-local/`, the main checkout's, or the git-directory home. The project-verdict cache is keyed on the checkout, since worktrees may share one From 02ef3756f93e3c14f98dfb46023a813b8475a24f Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Sun, 25 Oct 2026 21:33:43 +0100 Subject: [PATCH 3/3] fix(setup): build the welcome `due` answer without importing core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeQL flagged the `due` action's `from .core import …` as an import cycle: core already imports welcome for the pre-flight's welcome finding. `due_answer()` now builds the same JSON itself from `welcome_facts` and `sections.for_findings`, so welcome never imports core; the rendered eval fixtures confirm the output is unchanged. Generated-by: Claude Opus 5 --- .../skills/setup/setup_preflight/welcome.py | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/plugins/magpie-setup/skills/setup/setup_preflight/welcome.py b/plugins/magpie-setup/skills/setup/setup_preflight/welcome.py index 6e488c335..a05a89580 100644 --- a/plugins/magpie-setup/skills/setup/setup_preflight/welcome.py +++ b/plugins/magpie-setup/skills/setup/setup_preflight/welcome.py @@ -64,6 +64,7 @@ from pathlib import Path from typing import TextIO +from . import sections from .isolated import _load_stamp, _stamp_path HERE = Path(__file__).resolve().parent @@ -269,6 +270,24 @@ def welcome_facts(root: Path, skill: str) -> tuple[str, dict[str, object]] | Non } +def due_answer(root: Path, skill: str) -> dict[str, object]: + """The `due` answer: what the pre-flight's `welcome` finding would be, alone. + + The same JSON shape `core.Verdict.to_json` gives a lone welcome finding, + built here rather than through `core`, which already imports this module. + """ + try: + found = welcome_facts(root, skill) + except OSError: + # As in `core.welcome_findings`: an optional guide never fails the run. + found = None + if found is None: + return {"verdict": "ok"} + section, facts = found + finding = {"scope": "family", "code": "welcome", "section": section, "facts": facts} + return {"verdict": "action", "findings": [finding], "rules": sections.for_findings([section])} + + # --- recording ---------------------------------------------------------------------- @@ -507,10 +526,7 @@ def main(argv: list[str] | None = None) -> int: return 0 if args.action == "due": - from .core import Verdict, welcome_findings - - findings = welcome_findings(args.project_root, args.skill) - print(Verdict("action" if findings else "ok", findings).to_json()) + print(json.dumps(due_answer(args.project_root, args.skill), indent=2, sort_keys=True)) return 0 if guide(args.family) is None: