Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@
{
"name": "qe",
"source": "./qe",
"version": "0.2.0",
"version": "0.2.1",
"description": "QuantEcon's author-facing base skills — style checking, lecture editing support, and working through a PR's review feedback"
},
{
"name": "benchmark",
"source": "./benchmark",
"version": "0.3.0",
"version": "0.3.1",
"description": "Benchmarking and acceleration-evaluation tools for QuantEcon lecture code"
},
{
"name": "audit",
"source": "./audit",
"version": "0.1.2",
"version": "0.1.3",
"description": "Bulk, read-only audits of a QuantEcon repository — issue triage, PR review, technical debt, translation parity — each producing an evidence-cited report bundle"
}
]
Expand Down
70 changes: 70 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,41 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# The version-bump guard diffs the PR against its merge base and reads
# plugin.json as of that commit and as of the base tip. The default
# depth-1, single-ref checkout has neither the base ref nor shared
# history, and the guard exits 2 rather than passing blind — so full
# history is load-bearing for that step. It applies to the whole job
# rather than just the step that needs it; harmless for the others,
# since neither reads git history.
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Validate manifests and skill frontmatter
run: python scripts/validate.py

# A plugin's install cache is keyed by version string, and
# `claude plugin update` compares version strings only — so shipping an
# edited SKILL.md under an unchanged version publishes nothing: every
# consuming repo is told "already at the latest version" and keeps the old
# files. The bump is the delivery mechanism, which makes a missing one a
# build failure rather than a review nit. Three of this repo's first eleven
# merges would have been caught by it.
#
# Only a PR into the default branch publishes anything, so only those are
# checked: a stacked PR targeting another feature branch would otherwise be
# told to mint a second version for content that ships once. It gets
# checked the moment it is retargeted to main.
- name: Plugin changes carry a version bump
if: >-
github.event_name == 'pull_request' &&
github.base_ref == github.event.repository.default_branch
env:
BASE_REF: ${{ github.base_ref }}
run: python scripts/check-version-bump.py --base "origin/$BASE_REF"

# The benchmark plugin's claim is that no score is ever written by hand:
# every scorecard is a deterministic function of its evidence.json. That
# only stays true if it is checked. A non-empty diff here means either a
Expand All @@ -31,3 +60,44 @@ jobs:
python scripts/scoring/score.py references/fixtures/rubric_v2
git diff --exit-code -- 'references/examples/*/results/scorecard.json' \
'references/fixtures/*/results/scorecard.json'

# A separate job on purpose: this one installs an ~85 MB npm toolchain, and
# running it beside `validate` rather than inside it keeps that job four fast
# stdlib steps. The two also report independently, so a CLI-install failure
# cannot mask a manifest error.
#
# It earns its place by parsing what scripts/validate.py only pattern-matches.
# The repo's validator reads frontmatter with a regex, so it cannot see invalid
# YAML: `description: Audit every issue … Read-only: it recommends …` is a
# parse error — a `: ` inside an unquoted plain scalar — that shipped in
# audit/skills/issues/SKILL.md and passed CI until this PR. `--strict` also
# flags unknown plugin.json keys with a did-you-mean, so a typo'd `versoin` is
# caught rather than silently ignored.
#
# The CLI is pinned. Under --strict a new upstream warning becomes an error, so
# an unpinned install would let an upstream release redden an unrelated PR.
strict-validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install Claude Code CLI
run: npm install -g @anthropic-ai/claude-code@2.1.220

# Needs no credentials — a local manifest and frontmatter check that runs
# with no API key, no login and no network. Four targets because the scopes
# differ: only a plugin directory walks skills/, and only the marketplace
# root can compare an entry's version against the plugin.json it points at.
- name: Validate against the runtime's own parser
env:
DISABLE_AUTOUPDATER: "1"
run: |
rc=0
for target in qe benchmark audit .; do
echo "::group::claude plugin validate --strict $target"
claude plugin validate --strict "$target" || rc=1
echo "::endgroup::"
done
exit $rc
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ Before adding a paragraph, check whether it already exists. If it does, link to
|---|---|
| What the marketplace is, installation (local, lecture repos, CI) | [README.md](README.md) |
| Using the skills: setup, invocation, what to expect | [docs/using-skills.md](docs/using-skills.md) |
| Contributing: layout, conventions, dev loop, local testing, versioning, PR flow | [docs/developing-skills.md](docs/developing-skills.md) |
| Contributing: layout, conventions, dev loop, local testing, versioning, releases and tagging, PR flow | [docs/developing-skills.md](docs/developing-skills.md) |
| What changed in a plugin, release by release | `<plugin>/CHANGELOG.md` — one per plugin, since the plugin is the released artifact and ships only its own directory |
| Running an evaluation by hand, end to end | [docs/tutorial-run-an-evaluation.md](docs/tutorial-run-an-evaluation.md) |
| Running a whole-tracker audit, and reviewing what it produces | [docs/tutorial-run-an-audit.md](docs/tutorial-run-an-audit.md) |
| The benchmark skill: modes, report format, manual pipeline | [benchmark/README.md](benchmark/README.md) |
Expand All @@ -46,6 +47,7 @@ Before adding a paragraph, check whether it already exists. If it does, link to
## Working in this repo

- **Validate before committing**: `python scripts/validate.py`. A malformed manifest breaks installation silently in every consuming repo, so CI runs the same check.
- **Changing a file under `<plugin>/` means a version bump and a changelog entry, in the same PR.** The install cache is keyed by version string, so content merged without a bump reaches nobody who already has the plugin installed. CI enforces it; see [developing-skills § Versioning and releases](docs/developing-skills.md#versioning-and-releases).
- **Test from a real consuming project**, not from inside this repo — path-resolution bugs only surface when a plugin runs from an install location. Both tiers are in [developing-skills § Testing locally](docs/developing-skills.md#testing-locally).
- **The product principles** — report first, fix on request; deterministic before LLM; cited claims and computed scores; scaffolding as advice rather than instruction — are stated once in [CATALOG.md § Principles](CATALOG.md#principles) and elaborated in [developing-skills § Conventions](docs/developing-skills.md#conventions). Follow them; don't restate them in new files.
- **A new skill starts as an issue, not a doc entry.** CATALOG.md lists what has merged *and* is operational, so it stays true; the plan for something unbuilt — and the scaffolding for something merged but not yet operational — belongs in its plugin's tracking issue, where it can change without anyone mistaking it for a description of the repo.
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Each plugin bundles one area of work — a skill (the instructions Claude follow
|---|---|
| [AGENTS.md](AGENTS.md) | AI agents and contributors: canonical repo instructions — the single-source-of-truth principle, doc map, working conventions |
| [docs/using-skills.md](docs/using-skills.md) | Authors/reviewers: setup, invoking skills, what to expect |
| [docs/developing-skills.md](docs/developing-skills.md) | Contributors: layout, conventions, dev loop, testing locally, versioning, PR flow |
| [docs/developing-skills.md](docs/developing-skills.md) | Contributors: layout, conventions, dev loop, testing locally, versioning and releases, PR flow |
| [docs/tutorial-run-an-evaluation.md](docs/tutorial-run-an-evaluation.md) | Tutorial: the evaluation procedure by hand, with the ge_arrow validation run as the checkable example |
| [benchmark/README.md](benchmark/README.md) | The evaluation skill: review mode, triage mode, report format, manual pipeline |
| [audit/README.md](audit/README.md) | The audit family: what belongs in it, the shared method, running one |
Expand Down Expand Up @@ -103,4 +103,6 @@ Open a PR adding or modifying a plugin directory and registering it in `.claude-

Run `python scripts/validate.py` before pushing — it checks that every plugin resolves, that `plugin.json` agrees with `marketplace.json` on name, version, and description, and that each `SKILL.md` has frontmatter whose `name` matches its directory. CI runs the same script on every PR; a malformed manifest otherwise breaks installation silently in every consuming lecture repository.

CI also fails a PR that changes files under a plugin directory without bumping that plugin's version and adding its changelog entry — the install cache is keyed by version string, so an unbumped change reaches nobody ([developing-skills § Versioning and releases](docs/developing-skills.md#versioning-and-releases)).

Broader context for this repository: [QuantEcon/meta#304](https://github.com/QuantEcon/meta/issues/304) (toolkit proposal) and [QuantEcon/meta#335](https://github.com/QuantEcon/meta/issues/335) (benchmarking programme).
2 changes: 1 addition & 1 deletion audit/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "audit",
"description": "Bulk, read-only audits of a QuantEcon repository — issue triage, PR review, technical debt, translation parity — each producing an evidence-cited report bundle",
"version": "0.1.2",
"version": "0.1.3",
"author": { "name": "QuantEcon" }
}
70 changes: 70 additions & 0 deletions audit/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Changelog — `audit`

Every released version of this plugin, newest first. A version exists because the content below shipped in it: the plugin cache is keyed by version string, so what you have installed is exactly the entries down to the version `claude plugin list` reports for `audit`.

Versions are [semver](https://semver.org) as a user of this plugin experiences it — a new skill, or a procedure that now does something materially different, is a minor bump; a correction that leaves the procedure as it was is a patch. Nothing below 1.0.0 promises stability.

Repository: [QuantEcon/skills](https://github.com/QuantEcon/skills) ([every commit that touched this plugin](https://github.com/QuantEcon/skills/commits/main/audit)). How a release is made: [developing-skills § Versioning and releases](https://github.com/QuantEcon/skills/blob/main/docs/developing-skills.md#versioning-and-releases).

## 0.1.3 — 2026-08-03

**Added**

- This changelog.

**Fixed**

- `/audit:issues`'s frontmatter `description` was an unquoted YAML plain scalar containing `Read-only: it recommends…`. A `: ` inside a plain scalar is a parse error, so a strict loader drops the skill's metadata rather than reading it, and `claude plugin validate` rejects the file outright. The value is now quoted. Nothing about the procedure changed.

## 0.1.2 — 2026-07-28

Resolves the contradiction that told an audit to write its bundle into the repo it promised not to touch: the boundary is now mutation, not writing, and the skill says exactly where to put its working directory so a run leaves `git status` clean.

**Added**

- Discovery-ordered working-directory selection, taken from contact with a real repo: prefer a location the repo already ignores (`.dev/scratch/audit-<YYYY-MM-DD>/` in QuantEcon repos, where `.dev/scratch/*` is already gitignored), fall back to an untracked `.audit/<repo>-<YYYY-MM-DD>/` at the checkout root, then to somewhere outside the checkout entirely. Which one was used goes in the report's method section.
- Doctrine §3 now says explicitly that a run may write its own working directory, including inside the audited checkout — provided the directory stays untracked and nothing is added to `.gitignore`, since that would itself be an edit to a tracked file.

**Changed**

- Doctrine §3 narrowed from "no branch or file changes in the audited repo" to what it was always protecting — content and history: no commits, no pushes, no branches, no edits to tracked files. Mutation, not writing, is the boundary.
- `deliverables.md` states the split: writing the bundle is the audit's job, committing or publishing it is a human step taken after reading it.

**Fixed**

- The read-only/working-directory contradiction the plugin carried since 0.1.0 — §3 forbade file changes in the audited repo while `deliverables.md` made that repo's own notes system the bundle's first-choice destination, and 0.1.1's default `--out` wrote there too. A run following the docs literally could not satisfy both.

## 0.1.1 — 2026-07-28

An interrupted run can actually be resumed: the intermediate artifacts now have names and locations, phase 2 appends per item instead of writing at the end, and the bundle shrinks to fit a small tracker.

**Added**

- A stated working-directory layout under `--out` (`.audit/<repo>-<YYYY-MM-DD>/` by convention): `snapshot/` from phase 1, `findings.md` from phase 2, `links.md` from phase 3, and the delivered `01-…`/`02-…`/`03-…`/`README.md` bundle from phase 4. Previously phases 2 and 3 produced "per-item findings" and "the cluster map" with no filename and no location, so resuming worked only if two sessions independently invented the same file.
- A stated resume rule: on restart, read `findings.md` and resume at the lowest number in `issues.json` with no entry, re-verifying the last entry rather than trusting a possibly truncated write.
- `meta.json` records `fetched_by`, the account the snapshot was taken as — which matters because visibility on the org's private repos is per-account.

**Changed**

- Phase 2 appends each item's finding to `findings.md` as it is verified, in the catalog entry format, so phase 4 assembles the catalog instead of re-deriving it.
- The bundle scales to the tracker: below roughly 30 open issues, fold the catalog and the link graph into the report, keep the `README.md` index, and say which shape was used in the coverage statement. Four unconditional documents forced three files of padding on a small tracker, and padding makes a report less checkable.
- Doctrine §4 now states the general rule: a checkpoint owes a findable name and incremental writes, or it is a claim about resumability rather than the property itself.

**Fixed**

- `meta["authenticated"]` is removed, not deprecated. It could only ever be `true` (preflight exits on every unauthenticated path), so it was a provenance field carrying no evidence — in the plugin whose doctrine is that every claim carries its evidence class. **Anything reading that field must switch to `fetched_by`.**
- An interrupted phase 2 now loses one item rather than the whole phase — it was the phase specified to write on completion, and the phase a hundred-item run dies inside rather than between.

## 0.1.0 — 2026-07-27

First release. `/audit:issues` sweeps an entire GitHub tracker — open and closed — verifies each item against the code rather than the thread, tiers the open set into the repo's existing plan, and delivers an evidence-cited report bundle, without ever touching the tracker.

- `/audit:issues <owner/repo>` — a whole-tracker audit in five phases (snapshot, per-item verification, cross-link graph, tiered report, coverage self-audit). The four runbook fields (plan anchor, tier scheme, repo type, notes system) are optional arguments with documented discovery, so the usual invocation is just the repo.
- A deterministic snapshot step, `scripts/fetch_tracker.py OWNER/REPO --out <dir>`: every issue and PR in any state with full comment threads (and PR reviews, and `closingIssuesReferences`) in two `gh` round trips, written as `meta.json`, `issues.json`, `prs.json`, `coverage.json`. Closed threads cost nothing extra to read, and the snapshot freezes the audit's point in time so "events after the snapshot" is a stated property of the report instead of an unnoticed gap.
- `coverage.json` reconciliation: captured items against the number sequence `1..max`, discussion counts split open/closed, and an explicit truncation flag when a stream returns exactly at `--limit` (default 1000) — a case indistinguishable from truncation, so it is surfaced rather than swallowed. PR review bodies count toward captured discussion, not just comments: on the example repo, closed PRs carried 374 reviews against 28 comments.
- Snapshot files are written in issue/PR number order, so two runs over an unchanged tracker are byte-identical and a re-fetch diffs down to what actually changed.
- Thread payloads are shape-asserted at capture, so a `gh` build returning counts instead of lists fails by name at the point of capture rather than crashing later or silently under-reporting threads while the report still claims thread-completeness.
- Preflight that refuses to start without `gh` and an authenticated account, because the anonymous API is 60 req/h per IP and returns nothing at all for the org's private repos.
- Plugin-level method shared by every future audit skill: `references/doctrine.md` (trust rules, evidence classes `[verified]`/`[stated]`/`[inferred]`, the read-only boundary, checkpointing, the coverage self-audit), `references/quantecon-context.md` (repo types, label ownership, the cross-repo graph, access, and the caveat that an HTML-reconstructed thread may start mid-conversation), and `references/deliverables.md` (what an audit owes its reader, and where a bundle may land).
- QuantEcon-specific triage judgement: tier by repo type (a build break in a lecture repo and a consumer-visible change in an action repo outrank thread activity), check sibling repos before concluding, leave label application to `qe`, and keep GitHub closing keywords out of drafted cross-repo references so drafted text cannot close an upstream item when someone posts it.
- The four-document bundle, the five phases and "produces a bundle" are stated as a worked example rather than a requirement, after a single execution. What an audit owes its reader — coverage statement, evidence tag per claim, recommendations marked as proposals, drafted comments marked unsent, a date and a named snapshot — stays mandatory and presumes no file count.
2 changes: 1 addition & 1 deletion audit/skills/issues/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: issues
description: Audit every issue in a GitHub repository, open and closed — verify each status against the code rather than the thread, hunt fixed-but-open and never-landed-fix candidates, tier the open set into the repo's existing plan, and deliver a report bundle with a cross-link map. Read-only: it recommends tracker changes but never makes them. Use for a whole-tracker review, not a single issue.
description: "Audit every issue in a GitHub repository, open and closed — verify each status against the code rather than the thread, hunt fixed-but-open and never-landed-fix candidates, tier the open set into the repo's existing plan, and deliver a report bundle with a cross-link map. Read-only: it recommends tracker changes but never makes them. Use for a whole-tracker review, not a single issue."
---

# audit:issues
Expand Down
2 changes: 1 addition & 1 deletion benchmark/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "benchmark",
"description": "Benchmarking and acceleration-evaluation tools for QuantEcon lecture code",
"version": "0.3.0",
"version": "0.3.1",
"author": { "name": "QuantEcon" }
}
Loading
Loading