work-plan-toolkit
AGENTS.md1 starsChanged 5 months agoMITView on GitHub
Canonical instructions for coding agents (Claude Code, Codex, Cursor, Copilot) working on work-plan-toolkit. CLAUDE.md is a thin pointer to this file and carries no policy of its own — everything below applies to every agent. This file covers: how to verify your work and what "green" means, the architecture and hard constraints, commit/PR/docs conventions, and the maintainer release runbook. work-plan-toolkit is a Claude Code / Codex skill (/work-plan): a pure-Python-stdlib CLI for track-aware daily planning over GitHub issues, plus the…
- Installs packages
- Commits and pushes
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,774 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository5 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- site/llms-full.txtllms.txt
- site/llms.txtllms.txt
- repo-activity-summarySkill
- work-planSkill
The file
We split this AGENTS.md into the rules it gives an agent
5 rules. About 0 are common, 2 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 15
Run these, read the output, fix, repeat.
- Very specific: line 89
Pure Python 3.9+ stdlib: No third-party deps, no match.
- Distinctive: line 139
When a change warrants it, update the docs in the same PR as the code — don't defer:
- Very specific: line 165
Wait for PR checks (Tests matrix 3.9–3.12 × ubuntu/macos/windows, lint, vscode build): gh pr checks <n> --watch.
- Very specific: line 190
Do NOT use gh release create for a CLI-only deploy — a Release would needlessly republish the (unchanged) VS Code extension.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AGENTS.md
Canonical instructions for coding agents (Claude Code, Codex, Cursor, Copilot) working on work-plan-toolkit. CLAUDE.md is a thin pointer to this file and carries no policy of its own — everything below applies to every agent.
This file covers: how to verify your work and what "green" means, the architecture and hard constraints, commit/PR/docs conventions, and the maintainer release runbook.
work-plan-toolkit is a Claude Code / Codex skill (/work-plan): a pure-Python-stdlib CLI for track-aware daily planning over GitHub issues, plus the plan-status doc-liveness command. The repo contains the skill source; an installer copies it into ~/.claude/skills/ (or ~/.agents/skills/ for Codex) so the slash command works. Editing files here does not affect the running /work-plan slash command — re-run ./install.sh to refresh the installed copy (the installer drops a .installed-from marker and safely overwrites prior copies of the same toolkit).
For Codex specifically: in this repo, read-only review and analysis (e.g.
/spec-review, code review, plan critique) are in scope and welcome — this repo'sAGENTS.mdgoverns here. Do not fall back to plan-only refusal / handoff for read-only work. Anything that writes files or runs mutating commands still follows the normal branch/PR rules below.
The verify loop
Run these, read the output, fix, repeat. Do not claim success without running them.
| Step | Command | What "pass" means |
| Unit tests | cd skills/work-plan && python3 -m unittest discover tests | All green. Offline — every gh/git call is mocked; tests never hit the network. |
| Single test | cd skills/work-plan && python3 -m unittest tests.<module>[.<Class>.<test>] | The one you're iterating on passes. |
| CLI smoke | python3 skills/work-plan/work_plan.py --help | Runs without traceback. |
| Refresh live skill | ./install.sh (.\install.ps1 on Windows) | Re-copies source into ~/.claude/skills/work-plan/. Required after every source change — editing source does NOT update the running skill. |
There is no build step, no lint config, no CI lint gate beyond a py3.9 union check + the unittest matrix (3.9–3.12 × ubuntu/macos/windows).
Python / Node boundary. Everything under skills/work-plan/ (the CLI) is pure-stdlib Python with no build step — that property is load-bearing. The vscode/ subdir is a separate TS/Node project (the viewer extension) with its own package.json, npm build, and CI job (.github/workflows/vscode.yml: typecheck · node --test · esbuild · vsce package). It does not touch the CLI's no-dependency property. The Python matrix (test.yml) only runs unittest discover inside skills/work-plan/, so it never exercises vscode/; the extension's gate is its own Node job. When editing vscode/, use Node conventions (the local gate is npm run typecheck && npm test && npm run build); everywhere else, stdlib Python.
Handy commands
# Install / refresh into ~/.claude/skills/ (run after every code change)
./install.sh # macOS / Linux / WSL
./install.sh --target=$HOME/.agents # Codex variant
.\install.ps1 # Windows
# Run tests (no pytest, no pip — stdlib unittest)
cd skills/work-plan && python3 -m unittest discover tests
# Run a single test module / case
cd skills/work-plan && python3 -m unittest tests.test_handoff_set_next
cd skills/work-plan && python3 -m unittest tests.test_handoff_set_next.TestSetNext.test_persists_to_frontmatter
# Run the CLI directly (bypasses the install + slash command)
python3 skills/work-plan/work_plan.py --help
python3 skills/work-plan/work_plan.py briefArchitecture
The CLI is the substrate; SKILL.md is the prompt-engineering on top. work_plan.py is dispatcher-only — it maps subcommand names to modules in commands/ (each exports run(args: list[str]) -> int). Adding a subcommand means: write commands/<name>.py, register it in BOTH the SUBCOMMANDS dict AND the DESCRIPTIONS list in work_plan.py (the help text is hand-written, not auto-generated).
Layered design:
commands/<name>.py— one file per subcommand. Thin orchestration overlib/.lib/— shared helpers. Notable modules:config.py— loads~/.claude/work-plan/config.ymlby shelling out toyq(so YAML parsing stays stdlib-only).frontmatter.py—parse_file/write_filefor YAML-frontmattered markdown. Sameyqshell-out trick.tracks.py—discover_tracks(cfg)walksnotes_root/and buildsTrackdataclasses.find_track_by_nameis the canonical resolver.github_state.py/git_state.py— wrappers overgh/gitsubprocess calls.status_table.py— parses + edits the canonical issue table inside a track's markdown body.prompts.py—prompt_input,prompt_lines,prompt_yes_no,parse_flags(use these; don't reinvent).
Data model: GitHub is canonical for issue state. Track markdown files are lightweight references — they list issue numbers in YAML frontmatter, and the CLI re-derives state live from gh/git/the markdown body on every invocation. The toolkit deliberately does NOT mirror or cache GitHub state.
Two unusual patterns to know:
- Verbatim relay (
brief,handoff,orient,hygiene): the Python output IS the deliverable. SKILL.md instructs the model to reproduce the full Python output verbatim in chat — users copy-paste from chat into other terminals. - Two-step AI subcommands (
group,suggest-priorities,auto-triage): CLI fetches issues + prints a prompt → the LLM produces JSON and writes it via the Write tool to a per-user cache file under~/.claude/work-plan/cache/(mode0700; e.g.auto_triage.answers.json) → user re-runs with--apply. The CLI never calls an LLM directly.
Traps that bite agents here
- Editing source ≠ updating the live skill. Files under
skills/work-plan/are source; the running/work-planreads~/.claude/skills/work-plan/. Re-run./install.shor your change has no effect on the slash command. yqmeans mikefarah/yq (Go), not kislyuk/yq (the Python jq wrapper). Incompatible flags. Config + frontmatter parsing shell out to it. The installer verifies this.- Pure stdlib only. Python 3.9+ stdlib — no third-party packages (the "no
pip install" property is load-bearing for redistribution). PEP 585 generics (list[dict]) are fine; no 3.10+ features (nomatchstatements). - New subcommand → register in BOTH places in
work_plan.py: theSUBCOMMANDSdict AND theDESCRIPTIONSlist (help text is hand-written, not generated).
Non-negotiables (guardrails on OUTPUT, not user input)
- Pure Python 3.9+ stdlib. No third-party deps, no
match. - All GitHub state via
gh(reuses the user'sgh auth; never read or store tokens). All git viagitsubprocess (list-form args). - GitHub is canonical for issue state. The toolkit does NOT mirror or cache it — state is re-derived live from
gh/git/the markdown body on every invocation. Don't add a cache. - Tests are offline. Mock every
gh/gitsubprocess call. Don't add tests that hit the network. install.sh↔install.ps1anduninstall.sh↔uninstall.ps1stay in lockstep. Change one, change the other (seed logic, auto-detection, config seeding).
Where things live
- Dispatcher:
skills/work-plan/work_plan.py(maps subcommand → module; help is hand-written). - Subcommands:
skills/work-plan/commands/<name>.py(each exportsrun(args) -> int). Thin orchestration overlib/. - Shared helpers:
skills/work-plan/lib/(config.py,frontmatter.py,tracks.py,github_state.py,git_state.py,status_table.py,prompts.py). - Tests:
skills/work-plan/tests/(stdlibunittest, offline). - Slash-command alias:
installer/work-plan.md. Skill prompt:skills/work-plan/SKILL.md. - Specs/plans:
docs/superpowers/specs/,docs/superpowers/plans/. - Source → runtime:
skills/work-plan/→~/.claude/skills/work-plan/(viainstall.sh).
Source → runtime locations
skills/work-plan/(source) →~/.claude/skills/work-plan/(installed copy used by/work-plan)skills/repo-activity-summary/→~/.claude/skills/repo-activity-summary/installer/work-plan.md→~/.claude/commands/work-plan.md(the slash-command alias)notes/(defaultnotes_rootin seeded config) — empty untilinit-repopopulates it
The active config the skill reads is ~/.claude/work-plan/config.yml. There is no template file in the repo for it; install.sh writes the right two lines directly.
Commit / PR conventions
Conventional Commits. PR titles become squash-merge commit messages. Types: feat, fix, docs, refactor, test, chore, perf, ci. Scope is encouraged when localized (feat(orient): ..., fix(install.sh): ...). See CONTRIBUTING.md and .github/pull_request_template.md.
Before you commit
- Conventional Commit title:
type(scope): description(feat|fix|chore|docs|test|refactor|perf|ci). - Code → feature branch
feat/<issue#>-name+ PR todev(protected; squash-merge). Never commit code todev/maindirectly. - Docs/specs → may go straight to
dev. - Full test suite green:
cd skills/work-plan && python3 -m unittest discover tests. - Re-ran
./install.shif you changed skill source and want to exercise the live command. - New subcommand registered in BOTH
SUBCOMMANDSandDESCRIPTIONS. - Still pure stdlib (no new imports of third-party packages; no
match). - Docs in lockstep if user-facing: a new/changed flag or subcommand → update
README.md(both command tables); an extension change →vscode/README.md, and a new top entry invscode/CHANGELOG.mdwhenever the extension version is bumped (hand-maintained;vscode/src/release.test.tsenforces it). Don't hand-edit the rootCHANGELOG.md(release-generated). See Keep docs in lockstep with changes below.
Keep docs in lockstep with changes
When a change warrants it, update the docs in the same PR as the code — don't defer:
- vscode/CHANGELOG.md — a new top entry whenever
vscode/package.json's version is bumped (the Marketplace Changelog tab). Hand-maintained; don't confuse it with the rootCHANGELOG.md, which the bot writes. - README.md (root) — when you add/rename/remove a subcommand or flag, or change user-visible behavior. The command tables (the
## Commandsreference and the quick-start table near the top) are hand-maintained; update both rows if the change touches a command listed in each. - vscode/README.md — when the VS Code extension's surface changes (a new lens/sort/command, a new tree affordance, a confirm flow).
- site/ (the GitHub Pages site) — mirrors README facts; update it (pages,
llms.txt,llms-full.txt) when commands, flags, settings, install steps or requirements change, and runpython3 scripts/check_site.py. It deploys frommainvia.github/workflows/pages.yml. - agent-plugins (stylusnexus/agent-plugins, cross-repo) — that README is a catalog entry pinned to a release tag, written at the "VS Code viewer + skills" altitude. Update it only when the plugin's advertised surface changes (a new/renamed
/work-plan:*skill command, install/upgrade instructions, the one-line capability summary) — not for flag-level details, which live in this repo's README. Day-to-dayfeat/fixwork does not touch it; a new top-level skill command or a release that changes the pitch does. - CHANGELOG.md — don't hand-edit below the
<!-- new entries inserted below -->marker. It's written by.github/workflows/version-bump.ymlon the deploy PR merge tomain, from that PR's title/body (see "Releasing (maintainers)" below). dev merges don't touch it; the production deploy does.
Rule of thumb: a feat that adds/changes a flag or command → README here (both tables). A new top-level skill command or a release that changes the plugin's pitch → also agent-plugins. Pure internal refactor/test/chore → usually no doc change.
Releasing (maintainers)
Contributors can skip this section — releasing is a maintainer task and needs push access to main. This repo has no deploy automation of its own and no database / release-please steps; a release is just the manual dev → main merge below, after which version-bump.yml stamps the version and CHANGELOG. (Don't reach for any general-purpose deploy automation you may have from other projects — the flow here is self-contained and documented in full below.)
The release is a dev → main merge. Merging a deploy PR into main fires .github/workflows/version-bump.yml, which (on pull_request: closed + merged):
- writes
VERSION=<UTC-date>+<short-sha>(CalVer, e.g.2026.06.10+a6052bf), - syncs that CalVer into
.claude-plugin/plugin.jsonand.codex-plugin/plugin.json, - prepends a CHANGELOG.md entry from the deploy PR's title + body, and
- commits
chore(version): bump to <ver> [skip ci]tomain.
So the deploy PR title/body IS the changelog entry — write it as one (conventional-commit title like feat: …, body with the shipped changes). The title must be a real conventional type or version-bump still runs but the entry reads poorly.
Release steps (maintainer-only, run manually)
- Confirm
devCI is green andgit diff origin/main..devis non-empty. gh pr create --base main --head dev --title "<conventional summary>" --body "<changelog-worthy body>".- Wait for PR checks (Tests matrix 3.9–3.12 × ubuntu/macos/windows, lint, vscode build):
gh pr checks <n> --watch. gh pr merge <n> --merge --admin(merge commit, matching theMerge dev → mainhistory — keepsmain/devaligned, no squash phantom-diff). version-bump fires automatically.- Back-merge
main → devto pick up the bot's[skip ci]VERSION/CHANGELOG/manifest commit:git checkout dev && git merge origin/main && git push origin dev. Skipping this makes the next deploy drift on CHANGELOG.md. After it,git diff origin/main..devis empty. (Direct push todevworks — the branch-protection "must be a PR" line is advisory here.) - Re-run
./install.shif you want the local~/.claude/skills/work-plan/copy current.
Publishing the npm CLI and the VS Code extension
Two independent, version-source-distinct publishes, both gated on the deploy landing on main first:
- npm (
@stylusnexus/work-plan) — version is derived fromVERSION(CalVer→semver, e.g.2026.06.10→2026.6.10) and stamped at publish time; the committedpackage.jsonversion is irrelevant. Trigger manually:gh workflow run npm-publish.yaml --ref main -f dry_run=false(defaultdry_run=truejust packs+validates). Same-day republish of an already-taken version needs theversion_suffixinput (e.g.-1). - VS Code (
stylusnexus.work-plan-viewer) — version comes fromvscode/package.jsonand must be hand-bumped (semver; the convention has been a patch bump per deploy —0.3.1/0.3.2/0.3.3/0.3.4). Marketplace--skip-duplicatemeans republishing the same version silently no-ops, so bump it in the deploy. Also update the## Statusline invscode/README.md(NOT the root README) to the new extension version in the same deploy — it's the Marketplace listing's first paragraph and the convention is to name the version + what's new in that release. And add the matching## [x.y.z] - YYYY-MM-DDentry tovscode/CHANGELOG.md(the Marketplace Changelog tab; hand-maintained, unlike the rootCHANGELOG.md).vscode/src/release.test.tsfails CI ifpackage.json, the changelog and the Status list disagree — the changelog once silently missed six releases because no step named it. It has drifted before (stuck at an old version whilepackage.jsonmoved on); bump both together. Publish by creating a GitHub Release (gh release create v<VERSION-with-dash> --target main …, tag formv2026.06.10-a6052bf) which triggersvscode-publish.yml→ Marketplace + Open VSX as two independent jobs (either can be re-run alone). Orgh workflow run vscode-publish.yml -f dry_run=false.
The npm workflow publishes with trusted publishing (OIDC) — no NPM_TOKEN. It only works while the workflow is registered on npmjs.com (package → Settings → Trusted publisher → GitHub Actions: owner stylusnexus, repo work-plan-toolkit, workflow npm-publish.yaml — spelled exactly like the file, .yaml not .yml, which is the one workflow in this repo that does not use .yml because that is how it was registered, no environment); if a publish fails with E404/E401, check that registration first. The VS Code workflows need the org Actions secrets VSCE_PAT + OVSX_TOKEN. The Marketplace publisher (stylusnexus) must already exist.
Tag every deploy + repin the agent-plugins catalog
The stylusnexus/agent-plugins marketplace installs work-plan by pinning a git tag (ref), so a deploy isn't fully shipped until a tag exists for it AND the catalog points at it. Skip this and Codex/Claude marketplace users stay frozen on an old (possibly broken) build even though npm/Marketplace are current.
1. Every deploy must leave a tag named v<VERSION-with-dash> (e.g. v2026.06.14-6579bf7):
- A VS Code deploy already creates one via
gh release create v<VERSION-with-dash> --target main(that Release is also what firesvscode-publish.yml). - A CLI-only / npm-only deploy creates NO tag (the
npm-publish.yamlworkflow doesn't tag). Create a lightweight tag so you don't re-trigger the extension publish (vscode-publish.ymlfires onrelease: published, but a bare tag push does not):
Do NOT usegh api repos/stylusnexus/work-plan-toolkit/git/refs \ -f ref="refs/tags/v$(cat VERSION | tr '+' '-')" \ -f sha="$(gh api repos/stylusnexus/work-plan-toolkit/commits/main --jq .sha)"gh release createfor a CLI-only deploy — a Release would needlessly republish the (unchanged) VS Code extension.
2. Repin the catalog to the new tag, in both marketplace indexes (they drift independently — grep the prior tag to find every occurrence):
.agents/plugins/marketplace.json— Codex index,source: urlform (Codex can't parse Claude's{source: github})..claude-plugin/marketplace.json— Claude index,source: githubform.- The README row carries no version pin → leave it unless the advertised skill surface changed (a new
/work-plan:*command), per "Keep docs in lockstep." - Pin to a CLEAN tag, not merely the newest. If an earlier same-day tag shipped a build a later deploy fixed, point at the fixed tag. (2026-06-14: three
2026.06.14tags existed; only-6579bf7lacked the hot-branch perf regression — pinning "newest existing" would have shipped the 16-min-reload build.) - agent-plugins has no
devbranch — branch → PR → merge tomain. Then verify against the published index on GitHub, not your local clone (a local relative-source test resolves even when the publishedsource:url/refis wrong).
Same-day re-deploys (version collisions)
Two deploys on the same UTC day collide on version, because each registry derives its version differently — handle both before re-publishing:
- npm drops the sha:
VERSION2026.06.10+<sha>→ semver2026.6.10. The sha differs per deploy, but the published npm version does not, so a second same-day publish of2026.6.10is rejected ("cannot publish over existing version"). Use the workflow'sversion_suffixinput:gh workflow run npm-publish.yaml --ref main -f dry_run=false -f version_suffix=-1(then-2, …) for the 2nd+ same-day publish. - VS Code version is independent and hand-set in
vscode/package.json; it is not date-derived, so it never auto-collides — but you must bump it for every publish, including a second same-day one (e.g.0.3.4→0.3.5). Marketplace publishes with--skip-duplicate, so forgetting the bump means the workflow silently no-ops and the new build never ships. The GitHub Release tag embeds the sha (v2026.06.10-<sha2>), so the tag itself won't collide — only the extension version inside the VSIX matters.
In short: same-day npm needs version_suffix; same-day VS Code needs another package.json patch bump. Neither is automatic.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

