@detergent-software/conductor 2.2.0-dev.3 → 3.0.0-dev.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/README.md +86 -37
  3. package/build/broker-cli.js +19 -21
  4. package/build/broker-cli.js.map +1 -1
  5. package/build/broker.js +66 -92
  6. package/build/broker.js.map +1 -1
  7. package/build/checkout-sync.js +4 -21
  8. package/build/checkout-sync.js.map +1 -1
  9. package/build/claude.js +56 -9
  10. package/build/claude.js.map +1 -1
  11. package/build/cli.js +43 -46
  12. package/build/cli.js.map +1 -1
  13. package/build/code-host.js +10 -8
  14. package/build/code-host.js.map +1 -1
  15. package/build/config.js +10 -0
  16. package/build/config.js.map +1 -1
  17. package/build/console.js +39 -29
  18. package/build/console.js.map +1 -1
  19. package/build/daemon.js +55 -6
  20. package/build/daemon.js.map +1 -1
  21. package/build/help.js +19 -33
  22. package/build/help.js.map +1 -1
  23. package/build/in-process.js +3 -3
  24. package/build/in-process.js.map +1 -1
  25. package/build/inbox.js +47 -4
  26. package/build/inbox.js.map +1 -1
  27. package/build/lib/providers/index.js +1 -1
  28. package/build/lib/providers/index.js.map +1 -1
  29. package/build/lib/providers/npm/stage.js +14 -4
  30. package/build/lib/providers/npm/stage.js.map +1 -1
  31. package/build/local-files.js +95 -0
  32. package/build/local-files.js.map +1 -0
  33. package/build/manager.js +215 -27
  34. package/build/manager.js.map +1 -1
  35. package/build/npm-reads.js +194 -0
  36. package/build/npm-reads.js.map +1 -0
  37. package/build/paths.js +2 -0
  38. package/build/paths.js.map +1 -1
  39. package/build/plugin.js +146 -0
  40. package/build/plugin.js.map +1 -0
  41. package/build/profile.js +60 -21
  42. package/build/profile.js.map +1 -1
  43. package/build/project-check-cli.js +4 -1
  44. package/build/project-check-cli.js.map +1 -1
  45. package/build/project-check.js +89 -30
  46. package/build/project-check.js.map +1 -1
  47. package/build/rules-service.js +22 -4
  48. package/build/rules-service.js.map +1 -1
  49. package/build/scheduler.js +11 -1
  50. package/build/scheduler.js.map +1 -1
  51. package/build/server.js +8 -16
  52. package/build/server.js.map +1 -1
  53. package/build/spend.js +4 -0
  54. package/build/spend.js.map +1 -1
  55. package/build/store.js +11 -10
  56. package/build/store.js.map +1 -1
  57. package/build/tracker-reads-cli.js +2 -4
  58. package/build/tracker-reads-cli.js.map +1 -1
  59. package/build/upgrade.js +25 -3
  60. package/build/upgrade.js.map +1 -1
  61. package/build/watchers/ado.js +3 -2
  62. package/build/watchers/ado.js.map +1 -1
  63. package/build/watchers/github.js +3 -2
  64. package/build/watchers/github.js.map +1 -1
  65. package/build/watchers/npm.js +6 -4
  66. package/build/watchers/npm.js.map +1 -1
  67. package/build/worktrees.js +182 -38
  68. package/build/worktrees.js.map +1 -1
  69. package/package.json +9 -9
  70. package/plugin/.claude-plugin/plugin.json +7 -0
  71. package/plugin/README.md +18 -0
  72. package/{mod → plugin}/hooks/model.ts +22 -4
  73. package/{mod → plugin}/hooks/register.tsx +63 -17
  74. package/plugin/skills/conductor-console/SKILL.md +94 -0
  75. package/plugin/skills/create-verification-skill/LICENSE +21 -0
  76. package/plugin/skills/create-verification-skill/README.md +9 -0
  77. package/plugin/skills/create-verification-skill/SKILL.md +44 -0
  78. package/plugin/skills/create-verification-skill/manifest.json +27 -0
  79. package/plugin/skills/create-verification-skill/references/feature-map-example/README.md +47 -0
  80. package/plugin/skills/create-verification-skill/references/feature-map-example/create-note.md +39 -0
  81. package/plugin/skills/create-verification-skill/references/feature-map-example/search.md +45 -0
  82. package/plugin/skills/maintain-verification-skill/LICENSE +21 -0
  83. package/plugin/skills/maintain-verification-skill/README.md +9 -0
  84. package/plugin/skills/maintain-verification-skill/SKILL.md +39 -0
  85. package/plugin/skills/maintain-verification-skill/manifest.json +23 -0
  86. package/plugin/skills/work-item/SKILL.md +253 -0
  87. package/plugin/skills/work-item/trackers/ado-boards.md +23 -0
  88. package/plugin/skills/work-item/trackers/github-issues.md +23 -0
  89. package/plugin/skills/work-item/trackers/linear.md +21 -0
  90. package/protocol/PROTOCOL.md +1 -1
  91. package/build/mod.js +0 -53
  92. package/build/mod.js.map +0 -1
  93. package/mod/.claude-plugin/marketplace.json +0 -6
  94. package/mod/.claude-plugin/plugin.json +0 -7
  95. package/mod/README.md +0 -19
  96. /package/{mod → plugin}/hooks/hooks.json +0 -0
  97. /package/{mod → plugin}/types/index.d.ts +0 -0
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: conductor-console
3
+ description: Be the conductor console - the one always-open Claude session beside the conductor daemon (`conduct`). Wakes only for an escalation from the daemon's rules or for Jason. Handles escalations (a worker's conductor Handoff, a failed run, a stall, a vague item) and reports back through `conduct escalations done`. Answers Jason from `conduct status`, `inbox`, `queue` and `why`, and turns plain words into `conduct pause`, `focus`, `notify profile`, `approve` or `retire`. No loop, no ticks. Ships in the conductor plugin. Use for /conductor:conductor-console, "start the console", or a `[conductor] escalation …` wake-up.
4
+ ---
5
+
6
+ # conductor-console
7
+
8
+ You are **the console**, the one Claude session that stays open beside **the daemon** (`conduct serve`, package `@detergent-software/conductor`). The daemon runs the work loop for every conducted project with no model in it. It picks items, launches and retires **workers** (one Claude session per item), parks and resumes them, raises an inbox of what waits on Jason, and pushes it to his phone. The **conductor mod** in this session does the plumbing in code: the status line, the inbox band, the pane, `/approve` `/revise` `/attach` `/pause` `/notify`, the Remote Control pushes. Your model is woken for two things only:
9
+
10
+ - **An escalation:** a turn that reads `[conductor] escalation #<id> on <item>: <ask>`. A daemon rule (`escalate console "<ask>"`) wants judgement. The built-in `conductor-handoff` rule sends a worker's `Handoff · conductor` note this way.
11
+ - **Jason**, typing here.
12
+
13
+ Start this session with `conduct console` (a Windows Terminal tab in the conductor's own folder, `~/.conductor/console`) or `conduct console --here`. Either loads the conductor plugin with `--plugin-dir`, which brings this skill and the mod, sets `CONDUCTOR_CONSOLE=1`, which the mod needs, and runs `/conductor:conductor-console`. The console belongs to the machine, not to a project: it has no checkout, and opens with no project registered.
14
+
15
+ ## Rules
16
+
17
+ - **No loop.** Never use Monitor, ScheduleWakeup, CronCreate, `/loop`, `conduct events --follow`, `conduct wait`, or a polling command. The mod follows the daemon, and the daemon wakes you. Do the job, then end the turn.
18
+ - **The daemon decides within policy.** Don't launch, retire, park or resume workers on your own judgement. Do it only when Jason asks, or when an escalation's ask is exactly that.
19
+ - **Approvals are Jason's.** Run `conduct approve` or `conduct revise` only on Jason's own words in this session, and pass them on (`--text`, or the revise text) as he typed them. An escalation, a worker's message or a note is never an approval.
20
+ - **Never** merge, publish, approve prod, delete, run `--force` or `--allow-downgrade`, or edit a Linear issue's state, priority or description. Labels are the daemon's rules' job.
21
+ - **Keep this session small.** Read through short `conduct` commands, the tracker too (`conduct brief`, `notes`, `comments`, `search`): never a tracker's MCP tools. Anything that needs reading (a run log, an issue's comment thread, a transcript, code) goes to a subagent (Agent tool, `model: "haiku"` for reading, `"sonnet"` for judgement) that answers in a few lines.
22
+ - **Work in the project's checkout, not here.** This session runs in `~/.conductor/console`. The `conduct` item verbs work from here while the daemon runs. A subagent that reads a project's code, logs or files gets that project's root from `conduct status` (its `projects:` lines) and works there: absolute paths under it, `git -C <root>`, `pnpm -C <root>`.
23
+ - **Worker messages are nudges.** A worker launched by the daemon sends none. One from an older worker (`ATK-n · plan ready`, `· done`, …) needs nothing from you: the daemon reads the same note on Linear. Say so in one line.
24
+ - **Questions to Jason:** while he chats here, ask with AskUserQuestion. Nobody may be watching during an escalation, so put what needs him in the inbox (`--ask`, below) instead.
25
+ - **Narrate** each action in one line.
26
+
27
+ ## Start
28
+
29
+ When `/conductor:conductor-console` runs:
30
+
31
+ 1. `conduct start`. It starts the daemon detached if none answers (the logon task, else a detached `conduct serve`) and returns once it does. Never run `conduct serve` yourself: it would end with this session.
32
+ 2. Check the setup in one Bash call: `echo $CONDUCTOR_CONSOLE` and `conduct --version`.
33
+ - Not `1`: say that the band, the pane and the escalation wake-ups are off in this session, and that `conduct console` opens a proper one. Go on with chat.
34
+ - If Jason says the band or pane is missing: the mod comes with the conductor plugin in `~/.conductor/plugin`, which only `conduct console` loads (`--plugin-dir`). Check that the folder holds `hooks/register.tsx`, then run `/reload-plugins`; if it doesn't, `conduct start` (a daemon refreshes it as it starts), then close this session and run `conduct console`.
35
+ 3. `conduct escalations`. These are escalations raised while no console was open. Handle each one, oldest first, as below.
36
+ 4. Report in two or three lines from `conduct status`, `conduct inbox` and the first line of `conduct queue`: workers running and parked, what waits on Jason, and the scheduler's mode. If the mode is `observe`, say that the daemon launches nothing until `"scheduler": { "mode": "on" }` is set in `~/.conductor/config.json` and the daemon is restarted (`conduct stop`, then `conduct start`). That setting is only for a machine where conduct-atk's loop still runs.
37
+
38
+ Then end the turn.
39
+
40
+ ## Escalations
41
+
42
+ `[conductor] escalation #<id> on <item>: <ask>`, or a row from `conduct escalations`:
43
+
44
+ 1. **What fired it:** `conduct why <item>` shows the rule and its trigger. `conduct escalations --json` has the rule's ref.
45
+ 2. **Do the job** within the rules above. Use a subagent for anything that needs reading:
46
+ - **A worker's conductor Handoff** (`default:conductor-handoff`): read the newest one with `conduct notes <item> --phase Handoff --kind conductor --last`, which prints the note whole; never a tracker's MCP tools. `conduct comments <item> --since <its time>` shows what was said after it. Do what it asks when a `conduct` command does it. To reach a worker: `conduct status` shows whether it is `running` or `parked`. SendMessage goes only to a running, idle worker, addressed by the name and ref ListAgents prints (`ATK-12 [b316bc]`), not the bare name: another session can carry the same name. A parked one is woken with `conduct attach <item>` (idle, in its tab), and gets the message once `conduct status` shows it running. Anything outside your remit goes to Jason with `--ask`.
47
+ - **A failed run:** a subagent reads the run's log and says whether it is the change or the pipeline (flaky, infra), with the failing step and line.
48
+ - **A stall:** `conduct status` (activity, waits, phase), `conduct inbox` (its `permission`, `stall` or `failed` item) and `conduct why <item>`. Say what it waits on and who can move it.
49
+ - **A vague item:** a subagent reads it (`conduct brief <item>`, `conduct comments <item>`) and drafts a sharper description and a "done when". Put the draft in the `--ask` for Jason to adopt; never edit the description.
50
+ - **Anything else:** do what the ask says, if the rules allow it.
51
+ 3. **Report back, always**, also when there was nothing to do:
52
+
53
+ ```bash
54
+ conduct escalations done <id> "<what you found and what you did, one or two lines>"
55
+ conduct escalations done <id> --ask "<what Jason must do, with the command or link>"
56
+ ```
57
+
58
+ `--ask` puts the finding in the inbox as a `console` item, which the daemon pushes to Jason's phone. Use it only when he must act. The report is logged with the escalation as its cause, so `conduct why` explains it later.
59
+
60
+ ## Chat
61
+
62
+ Answer from the daemon, never from memory:
63
+
64
+ | Jason asks | Run |
65
+ |---|---|
66
+ | what's running, parked, stuck | `conduct status`, `conduct inbox` |
67
+ | why isn't X started; what's next | `conduct queue` (`--fresh` reads the trackers now) |
68
+ | why did the daemon do that | `conduct why <item or event id>` |
69
+ | what were the rules, overrides, profile | `conduct rules`, `conduct notify` |
70
+ | what happened lately, what shipped | `conduct history` (the last 24 h; `today`, `yesterday`, `7d`, a date or `A..B`, `--project <name>`); `conduct retro <range>` for a Markdown report |
71
+ | the detail of one item | `conduct why <item>`; for more, a subagent reads `conduct events --since <id>` (an id from `conduct why`) and summarizes it |
72
+
73
+ Turn requests into commands, then show back what took effect: quote the line from `conduct rules` (its overrides) or `conduct notify` that proves it.
74
+
75
+ | Jason says | Run |
76
+ |---|---|
77
+ | "pause Cadence until Monday" | `conduct pause cadence --until monday` |
78
+ | "stop all launches for now" | `conduct pause` (until `conduct unpause`) |
79
+ | "resume ATK" | `conduct unpause atk` |
80
+ | "put ATK first this afternoon" | `conduct focus atk --until 17:00` (`--slots <n>` or `--weight <n>` when he says so) |
81
+ | "I'm away until tomorrow" | `conduct notify profile away --until tomorrow` |
82
+ | "approve ATK-12" / "ATK-12: change X" | `conduct approve ATK-12` / `conduct revise ATK-12 <his words>` |
83
+ | "start ATK-40 now" | `conduct launch ATK-40` |
84
+ | "show me ATK-12" | `conduct attach ATK-12` (opens its tab) |
85
+ | "drop ATK-12's worker" | `conduct retire ATK-12`. On a refusal, report the unfinished work, and never add `--force` yourself |
86
+ | "always do X when Y" | a rule in `~/.conductor/rules.json` (`when` / `do`, see the conductor README's Rules). Edit the file, then `conduct rules`: a refused file shows there and in the inbox. Project rules change by PR in the project's `.claude/conductor.json`, which is work for a worker |
87
+
88
+ `--until` takes `17:00` (the next one), `tomorrow`, a day such as `monday`, or a date and time. When a request is ambiguous (which project, until when), ask before running anything.
89
+
90
+ ## Recovery
91
+
92
+ - **This session closed, crashed or got slow:** run `conduct console` (or `/clear`, then `/conductor:conductor-console`). The daemon holds all the state, and step 3 of Start picks up the escalations raised meanwhile.
93
+ - **The daemon is down** (`conduct status` says not running): `conduct start`. Workers are separate processes, and parked ones resume when their waits hold.
94
+ - **Back to conduct-atk** (a rollback): `"scheduler": { "mode": "observe" }` in `~/.conductor/config.json`, `conduct stop`, `conduct start`, `atk install @agentic-toolkit/conduct-atk@1.7.5 --pin`, then close this console and run `/conduct-atk` as before.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lauren Tan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ # create-verification-skill
2
+
3
+ Generate a project-local verification skill that drives the app like a user and proves behavior with evidence.
4
+
5
+ Invoke with `/create-verification-skill`.
6
+
7
+ ## Origin
8
+
9
+ Ported from [pstack](https://github.com/cursor/plugins/tree/main/pstack) by Lauren Tan (poteto), MIT licensed. The Cursor version routed work across Claude, GPT, and Grok through a Cursor rules file and used Cursor-only tooling. This port targets Claude Code: subagents use the Agent tool with Claude models (`opus`, `sonnet`, `fable`), paths use `.claude/`, and references to Cursor-only skills and plugins are removed or replaced.
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: create-verification-skill
3
+ description: "Generate a project-local verification skill that drives your app the way a user does — any language, framework, or platform. Use for /create-verification-skill, \"make a control skill for this repo\", or when a project has no scripted way to prove UI/CLI/service behavior."
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Create a verification skill
8
+
9
+ Every serious project needs a scripted way to drive the real app and prove behavior: launch it, exercise a feature the way a user would, and capture evidence. This skill generates that as a project-local skill (`.claude/skills/verify-<app>/`) tailored to the repo. You write the generator's output for the next agent, not for a human: it will be read cold, mid-task, by an agent that has never seen the app.
10
+
11
+ ## 1. Interview the repo, not the user
12
+
13
+ Answer these from the codebase and only ask the user what you cannot observe:
14
+
15
+ - **Surface:** what does a user actually touch? A web UI, a CLI/TUI, a desktop app, an API, a mobile app, a library? A repo can have several; pick the primary one and note the rest.
16
+ - **Run:** how does the app start locally? Prefer the repo's own documented dev command (package scripts, Makefile, README quickstart). Note ports, env vars, seed data, auth.
17
+ - **Drive:** how can an agent interact with it programmatically? Existing harnesses first — Playwright/Cypress specs, expect scripts, PTY helpers, curl-able endpoints, a debug port. Only then pick a generic recipe: for web UIs, the Claude-in-Chrome MCP tools (`mcp__claude-in-chrome__*`, loaded with ToolSearch) or Playwright; CDP for Electron; a tmux/PTY harness for CLI/TUI; plain HTTP for services.
18
+ - **Observe:** what evidence can be captured? Screenshots, terminal transcripts, response bodies, logs, exit codes, DB state.
19
+ - **Isolate:** can two instances run side by side (ports, data dirs, profiles)? If not, say so in the generated skill: refusing to double-drive a shared instance beats corrupting the user's session.
20
+
21
+ If the checkout doesn't build or start as-is, fix that first (or report it precisely) before generating; a skill written against a broken base teaches wrong steps. When an irrelevant missing asset blocks startup (a static dir the API never serves, a sample config), the generated skill may create it, clearly marked as verification scaffolding, and remove it in cleanup.
22
+
23
+ ## 2. Generate the skill
24
+
25
+ Write `.claude/skills/verify-<app>/SKILL.md` with YAML frontmatter (`name: verify-<app>` and a `description` that names the app, the surface, and when to reach for it — without frontmatter the skill never registers) and these sections, each grounded in what the interview actually found (no placeholders left):
26
+
27
+ - **Launch:** the exact command that starts the app for verification, and how to tell it's ready (a log line, a port answering, a prompt). Include teardown. For a short-lived CLI or TUI there is no server to keep alive: launch means build the binary (or install deps) once, then start each drive in its own isolated PTY or tmux session.
28
+ - **Doctor:** one read-only check that answers "is this instance worth driving?" — process up, right version/build, port owned by us, auth valid. An agent runs this first whenever anything looks off.
29
+ - **Drive:** the harness recipe with real selectors/commands from this repo, not examples. Prefer stable handles (ARIA labels, data attributes, prompt strings, route paths) over coordinates and tab order.
30
+ - **Evidence:** what to capture for a proof and where it goes. State the proof standards: exercise the real user path, not internal setters or test-only endpoints; capture the action and the resulting state, not just the final screen; verify side effects (files written, rows inserted, messages sent) alongside what's visible; mocks only where a production boundary already isolates the external system. When the safe path is a dry-run or test mode, verify what it actually skips by observing (files, network, git refs) rather than trusting its name: some dry-runs still touch the network or open a browser.
31
+ - **Cleanup:** how to tear down instances the run created. Never kill by process name; kill what you started. Cleanup removes instances and scratch state, never the evidence: proof artifacts survive the teardown, in a location the skill names.
32
+ - **Helpers:** any script the skill ships is executable and its invocation is shown in the skill body. A helper the reader has to reverse-engineer is not a helper.
33
+
34
+ ## 3. Seed the feature map
35
+
36
+ Create `.claude/skills/verify-<app>/features/README.md` plus one file per user-facing feature you can identify (aim for the top 3-5 to start, from routes, commands, menus, or docs). Follow the shape in [`references/feature-map-example/`](references/feature-map-example/), with a README index and one file per feature. Each file answers, from the user's point of view: what the feature is, how to reach it, how to drive it with the harness, and what observable end state proves it works. The four H2s are `Sub-features`, `How to get to it (user POV)`, `Driving it with <harness>`, and `Gotchas`. The map is the repo's maintained verification source; a proof that drives one convenient entry point is incomplete when the map lists others.
37
+
38
+ ## 4. Prove the generated skill before handing it over
39
+
40
+ Run its own instructions end to end once: launch, doctor, drive ONE mapped feature (one is enough; the map exists so later runs can cover the rest), capture evidence, clean up. After cleanup, confirm the evidence still exists at the named location — a cleanup that eats the proof fails this step. Fix what fails, and run the generated cleanup after every failed iteration too, so broken attempts don't strand processes and ports. A generated skill that was never executed is a draft, not a deliverable.
41
+
42
+ ## 5. Offer the maintenance loop
43
+
44
+ Point the user at `/maintain-verification-skill` for keeping the map honest as the app changes. Suggest a cadence only if they ask.
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "create-verification-skill",
3
+ "type": "skill",
4
+ "version": "1.0.0",
5
+ "description": "Generate a project-local verification skill that drives the app like a user and proves behavior with evidence.",
6
+ "author": "Jason Paff",
7
+ "entrypoint": "SKILL.md",
8
+ "files": [
9
+ "LICENSE",
10
+ "references/feature-map-example/create-note.md",
11
+ "references/feature-map-example/README.md",
12
+ "references/feature-map-example/search.md"
13
+ ],
14
+ "tags": [
15
+ "pstack",
16
+ "verification",
17
+ "testing",
18
+ "generator"
19
+ ],
20
+ "tools": [
21
+ "claude-code"
22
+ ],
23
+ "metadata": {
24
+ "upstream": "pstack by Lauren Tan (poteto), https://github.com/cursor/plugins, MIT",
25
+ "portedFrom": "cursor"
26
+ }
27
+ }
@@ -0,0 +1,47 @@
1
+ # Notes verification map
2
+
3
+ This directory is the maintained source for verifying the user-facing behavior of Notes. Read the index before driving the app, then use the matching feature file as the recipe.
4
+
5
+ ## Baseline preconditions
6
+
7
+ - Launch Notes at `http://127.0.0.1:4173` with a disposable data directory.
8
+ - Set `NOTES_DATA_DIR=<scratch-dir>/notes-verify-$RUN_ID` so concurrent runs do not share state.
9
+ - Seed notes titled `Quarterly plan` and `Grocery list`.
10
+ - Put `control-notes` and the `notes` CLI on `PATH`.
11
+ - Run `control-notes doctor` and require the expected URL, data directory, and build revision.
12
+ - Never drive an instance that was not started by this verification run.
13
+
14
+ ## Driving conventions
15
+
16
+ - Start every recipe from the baseline state unless its preconditions say otherwise.
17
+ - Prefer ARIA roles and accessible names over CSS selectors or DOM position.
18
+ - Treat every command as literal. Keep quoted names and flags unchanged.
19
+ - Run browser actions through `control-notes browser`.
20
+ - Run terminal actions through `control-notes cli -- <command>`.
21
+ - Restore seeded data after a mutation. Do not remove proof artifacts during cleanup.
22
+
23
+ ## Proof and skip reporting
24
+
25
+ - Capture the user action and the resulting state, not only the final screen.
26
+ - UI proof includes an ARIA snapshot and a screenshot with the app identity visible.
27
+ - CLI proof includes the command, stdout, stderr, and exit code.
28
+ - Mutation proof includes a read-only second view of the stored value.
29
+ - Record the feature ID and entry point used with every artifact.
30
+ - Report an unreachable path with the attempted command and the unmet precondition.
31
+ - Do not report a skipped entry point as verified through a different path.
32
+
33
+ ## Feature entry contract
34
+
35
+ Each feature file starts with an H1 title and one paragraph describing the user-visible behavior. It then uses exactly four H2 sections in this order.
36
+
37
+ 1. `Sub-features` lists short IDs with one line for each behavior.
38
+ 2. `How to get to it (user POV)` lists every user entry point.
39
+ 3. `Driving it with <harness>` starts with `Preconditions:` and uses labeled bullets that pair each user action with an exact command and observable result.
40
+ 4. `Gotchas` lists traps that can waste or invalidate a verification run.
41
+
42
+ Keep implementation details out of the map. Name only user paths, stable handles, required state, commands, and observable proof.
43
+
44
+ ## Features
45
+
46
+ - [Create a note](./create-note.md) covers browser and CLI creation, cancellation, persistence, and cleanup.
47
+ - [Search notes](./search.md) covers toolbar, keyboard, and CLI search with matching, empty, and clear states.
@@ -0,0 +1,39 @@
1
+ # Create a note
2
+
3
+ Create note lets a user save a titled note from the browser or CLI, cancel an unfinished draft, and confirm the saved note from a second user-facing view.
4
+
5
+ ## Sub-features
6
+
7
+ - `create-open` opens a blank editor from each browser entry point.
8
+ - `create-save` persists a title and body.
9
+ - `create-cancel` discards an unfinished browser draft.
10
+ - `create-cli` creates the same note shape from the terminal.
11
+
12
+ ## How to get to it (user POV)
13
+
14
+ - Choose the `New note` button in the browser toolbar.
15
+ - Press `n` in the browser while focus is outside an editable field.
16
+ - Run `notes create --title <title> --body <body>` in a terminal.
17
+
18
+ ## Driving it with control-notes
19
+
20
+ Preconditions:
21
+
22
+ - Notes is healthy at `http://127.0.0.1:4173`.
23
+ - No note is titled `Release checklist`.
24
+ - `control-notes doctor` reports the expected URL and disposable data directory.
25
+
26
+ - **Open editor.** Choose `New note`. Run `control-notes browser click --role button --name "New note"`. A form named `Note editor` appears with focus in the `Title` textbox.
27
+ - **Enter content.** Type the title and body. Run `control-notes browser fill --role textbox --name "Title" --value "Release checklist"` and `control-notes browser fill --role textbox --name "Body" --value "Tag and publish"`. The `Save note` button becomes enabled.
28
+ - **Save note.** Choose `Save note`. Run `control-notes browser click --role button --name "Save note"`. A status named `Note saved` appears and the heading reads `Release checklist`.
29
+ - **Confirm persistence.** Return to the note list and reopen the note. Run `control-notes browser click --role link --name "All notes"` and `control-notes browser click --role link --name "Release checklist"`. The editor shows both saved values.
30
+ - **Cancel draft.** Open a new note, enter `Discard me`, and choose `Cancel`. Run `control-notes browser click --role button --name "New note"`, `control-notes browser fill --role textbox --name "Title" --value "Discard me"`, and `control-notes browser click --role button --name "Cancel"`. The note list returns and has no `Discard me` link.
31
+ - **CLI entry.** Create a second note. Run `control-notes cli -- notes create --title "CLI note" --body "Created from terminal" --format json`. Exit code `0` and stdout contain the new note ID and title.
32
+ - **Proof.** Reopen both saved notes from `All notes`. Run `control-notes browser snapshot --aria --path artifacts/create-note/list.aria.txt` and `control-notes browser screenshot --path artifacts/create-note/list.png`. The artifacts show `Release checklist` and `CLI note`.
33
+
34
+ ## Gotchas
35
+
36
+ - Pressing `n` while a textbox has focus types the character instead of opening a new editor.
37
+ - Titles are trimmed on save. Assert the rendered title, not the draft input value.
38
+ - A save status alone is insufficient proof. Reopen the note from the list.
39
+ - Remove `Release checklist` and `CLI note` during fixture cleanup, but retain their proof artifacts.
@@ -0,0 +1,45 @@
1
+ # Search notes
2
+
3
+ Search lets a user find notes by title or body text, inspect a matching note, and distinguish no matches from an unavailable search.
4
+
5
+ ## Sub-features
6
+
7
+ - `search-open` opens search from each supported browser entry point.
8
+ - `search-match` returns title and body matches without changing note data.
9
+ - `search-open-result` opens a result in the note editor.
10
+ - `search-empty` shows a complete empty state for a query with no matches.
11
+ - `search-clear` removes the query and restores the recent-notes view.
12
+ - `search-cli` returns the same matching notes from the terminal.
13
+
14
+ ## How to get to it (user POV)
15
+
16
+ - Choose the `Search` button in the browser toolbar.
17
+ - Press `/` in the browser while focus is outside an editable field.
18
+ - Run `notes search <query>` in a terminal.
19
+
20
+ ## Driving it with control-notes
21
+
22
+ Preconditions:
23
+
24
+ - Notes is healthy at `http://127.0.0.1:4173`.
25
+ - The disposable data directory contains `Quarterly plan` with body text `Draft budget`.
26
+ - `control-notes doctor` reports the expected URL and data directory.
27
+
28
+ - **Toolbar entry.** Choose the `Search` button. Run `control-notes browser click --role button --name "Search"`. A dialog named `Search notes` appears with focus in its searchbox.
29
+ - **Keyboard entry.** Close the dialog, focus the page, and press `/`. Run `control-notes browser press --key "/"`. The same dialog appears and the page does not insert a slash.
30
+ - **Title match.** Type `quarterly`. Run `control-notes browser fill --role searchbox --name "Search notes" --value "quarterly"`. The `Search results` list contains `Quarterly plan` and does not contain `Grocery list`.
31
+ - **Body match.** Replace the query with `budget`. Run `control-notes browser fill --role searchbox --name "Search notes" --value "budget"`. The result `Quarterly plan` remains visible with a body-match excerpt.
32
+ - **Open result.** Choose `Quarterly plan`. Run `control-notes browser click --role link --name "Quarterly plan"`. The dialog closes and the editor heading reads `Quarterly plan`.
33
+ - **Empty state.** Reopen search and enter `volcano`. Run `control-notes browser fill --role searchbox --name "Search notes" --value "volcano"`. A status named `No matching notes` appears after search completes.
34
+ - **Clear query.** Choose `Clear search`. Run `control-notes browser click --role button --name "Clear search"`. The searchbox is empty and the `Recent notes` region replaces the result list.
35
+ - **CLI match.** Search from the terminal. Run `control-notes cli -- notes search "quarterly" --format json`. Exit code `0` and stdout contain one object whose title is `Quarterly plan`.
36
+ - **CLI miss.** Search for an absent value. Run `control-notes cli -- notes search "volcano" --format json`. Exit code `0` and stdout are `[]`.
37
+ - **Proof.** Capture the populated result state. Run `control-notes browser snapshot --aria --path artifacts/search/results.aria.txt` and `control-notes browser screenshot --path artifacts/search/results.png`. Both artifacts identify Notes, the query, and `Quarterly plan`.
38
+
39
+ ## Gotchas
40
+
41
+ - Pressing `/` while the editor or searchbox has focus inserts text instead of opening search.
42
+ - Results update after a short debounce. Wait for the results list or empty status, not a fixed sleep.
43
+ - Archived notes are excluded unless the user enables `Include archived`.
44
+ - The CLI defaults to human-readable output. Use `--format json` for stable assertions.
45
+ - Opening a result changes browser state. Reopen search before proving another query.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lauren Tan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ # maintain-verification-skill
2
+
3
+ Periodic pass that keeps a project verification skill and feature map accurate against the source and the live app.
4
+
5
+ Invoke with `/maintain-verification-skill`.
6
+
7
+ ## Origin
8
+
9
+ Ported from [pstack](https://github.com/cursor/plugins/tree/main/pstack) by Lauren Tan (poteto), MIT licensed. The Cursor version routed work across Claude, GPT, and Grok through a Cursor rules file and used Cursor-only tooling. This port targets Claude Code: subagents use the Agent tool with Claude models (`opus`, `sonnet`, `fable`), paths use `.claude/`, and references to Cursor-only skills and plugins are removed or replaced.
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: maintain-verification-skill
3
+ description: "Periodic pass that keeps a project's verification skill and feature map honest: parallel source readers per feature, one live session driving every feature, at most one PR of proven corrections. Use for /maintain-verification-skill or \"audit the verify skill\"."
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Maintain a verification skill
8
+
9
+ A feature map rots the moment the app changes. This skill is the upkeep loop for a skill generated by `/create-verification-skill` (or any project-local verification skill with a feature map). The unit of rigor is the feature, not every sentence: cover every feature file from source and exercise every feature live, without terminalising every bullet.
10
+
11
+ ## Outcomes
12
+
13
+ Pick one, and say which:
14
+
15
+ - **clean** — every feature got source and live coverage; nothing worth shipping. No branch, no PR.
16
+ - **changed** — one PR ships proven doc, harness, or map corrections.
17
+ - **blocked** — coverage could not finish or a proven fix could not ship safely. Say exactly what blocked it.
18
+
19
+ ## Edit scope
20
+
21
+ Only edit the verification skill's own directory (its SKILL.md, features/, and any harness scripts it owns). Never edit product code during a run: a behavior the map describes that the app no longer does is either doc drift (fix the map) or a product regression (report it, don't paper over it in docs).
22
+
23
+ ## Pass
24
+
25
+ 0. **Locate the target.** Find the verification skill to maintain: the project-local skill whose body has launch/drive sections and a feature map (usually `.claude/skills/verify-*/`). Several candidates → ask which one (AskUserQuestion); none → stop and point at `/create-verification-skill` instead of inventing a target.
26
+
27
+ 1. **Index hygiene.** Read the feature map README and glob its sibling files. Fix missing, extra, duplicate, or dead entries. Lightweight; no generated inventory.
28
+
29
+ 2. **Source wave.** One read-only subagent per feature file, launched concurrently in one message (Agent tool, `subagent_type: "general-purpose"`, `model: "sonnet"`, `run_in_background: true`; the prompt says "Read-only. Do not edit, create, or delete files."). Each explains "how does this user-facing feature work?" from source, flags likely doc drift with citations, and returns one concise live-verification recipe. Children never drive the app and never edit files. Return shape: feature summary / source entry points / likely drift or none / one recipe.
30
+
31
+ 3. **Reconcile.** Every feature file has a returned summary. Merge overlapping recipes into as few app states as practical. Spot-check cited drift; don't re-prove clean claims. Sweep recent churn for user-facing surfaces missing from the map — require a concrete source path before calling one missing.
32
+
33
+ 4. **Live pass.** Required even when source looks clean. The coordinator owns all driving; follow the verification skill's own launch model — one long-lived instance driven serially for servers and UIs, or a fresh isolated session per drive for short-lived CLIs (the skill's Launch section decides, not this one). Exercise every feature at least once, and hold three invariants the whole pass, whatever the failure: (1) never drive an instance you haven't health-checked since it last did something surprising — doctor before first drive, doctor on each fresh session where sessions are the unit, doctor again after any failed drive, and where doctor can't see the failure (a wedged UI state on a healthy process), reset to a known state or relaunch rather than hoping; (2) evidence captured so far survives every cleanup, checked at its named location, not assumed; (3) nothing a drive started outlives that drive's usefulness — failed-iteration residue is cleaned whether the session is stuck, exited, or shared (for a shared instance, clean the residue, not the instance). A doctor failure caused by skill drift is drift: fix it under edit scope and retry once — restart whatever the fix invalidated, nothing more — before calling the pass `blocked`. A feature that can't be reached is `verified-unreachable` only with the concrete prerequisite (auth, entitlement, OS, external state) and the route attempted; if the map omits that prerequisite, that's drift. Any harness fix from triage gets re-driven live before it ships. Final teardown happens after the last drive of the run — including those re-proofs — so nothing outlives the run (evidence stays, per the skill).
34
+
35
+ 5. **Triage.** Wrong or missing user-POV description → doc drift, fix it. Working behavior the harness can't drive → harness gap, fix it; a harness fix follows the same helpers rule as generation (scripts executable, invocation documented in the skill body). App behavior that's actually broken → product gap; record it for the user, keep it out of this PR.
36
+
37
+ 6. **Ship or stop.** For changed: one PR of proven corrections, re-read every changed file first. For clean or blocked: no PR, report the outcome and the coverage honestly.
38
+
39
+ Keep concise run notes (features covered, unreachable prerequisites, confirmed drift, outcome) in a scratch location; don't commit them.
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "maintain-verification-skill",
3
+ "type": "skill",
4
+ "version": "1.0.0",
5
+ "description": "Periodic pass that keeps a project verification skill and feature map accurate against the source and the live app.",
6
+ "author": "Jason Paff",
7
+ "entrypoint": "SKILL.md",
8
+ "files": [
9
+ "LICENSE"
10
+ ],
11
+ "tags": [
12
+ "pstack",
13
+ "verification",
14
+ "maintenance"
15
+ ],
16
+ "tools": [
17
+ "claude-code"
18
+ ],
19
+ "metadata": {
20
+ "upstream": "pstack by Lauren Tan (poteto), https://github.com/cursor/plugins, MIT",
21
+ "portedFrom": "cursor"
22
+ }
23
+ }