@aperant/framework 0.7.0 → 0.7.3

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 (151) hide show
  1. package/CHANGELOG.md +180 -0
  2. package/agents/apt-planner.md +12 -0
  3. package/agents/apt-pr-review-fixer.md +13 -9
  4. package/bin/apt-tools.mjs +7 -0
  5. package/dist/cli/ci-watch/stop-matrix.d.mts.map +1 -1
  6. package/dist/cli/ci-watch/stop-matrix.mjs +16 -0
  7. package/dist/cli/ci-watch/stop-matrix.mjs.map +1 -1
  8. package/dist/cli/commands/ci-watch.d.mts +11 -0
  9. package/dist/cli/commands/ci-watch.d.mts.map +1 -1
  10. package/dist/cli/commands/ci-watch.mjs +108 -2
  11. package/dist/cli/commands/ci-watch.mjs.map +1 -1
  12. package/dist/cli/commands/features-audit.d.mts +24 -0
  13. package/dist/cli/commands/features-audit.d.mts.map +1 -1
  14. package/dist/cli/commands/features-audit.mjs +159 -5
  15. package/dist/cli/commands/features-audit.mjs.map +1 -1
  16. package/dist/cli/commands/health-check.d.mts +16 -0
  17. package/dist/cli/commands/health-check.d.mts.map +1 -1
  18. package/dist/cli/commands/health-check.mjs +118 -2
  19. package/dist/cli/commands/health-check.mjs.map +1 -1
  20. package/dist/cli/commands/init.d.mts +9 -0
  21. package/dist/cli/commands/init.d.mts.map +1 -1
  22. package/dist/cli/commands/init.mjs +49 -4
  23. package/dist/cli/commands/init.mjs.map +1 -1
  24. package/dist/cli/commands/modes.d.mts.map +1 -1
  25. package/dist/cli/commands/modes.mjs +11 -0
  26. package/dist/cli/commands/modes.mjs.map +1 -1
  27. package/dist/cli/commands/pr-review-audit-fixer.d.mts +13 -0
  28. package/dist/cli/commands/pr-review-audit-fixer.d.mts.map +1 -1
  29. package/dist/cli/commands/pr-review-audit-fixer.mjs +18 -5
  30. package/dist/cli/commands/pr-review-audit-fixer.mjs.map +1 -1
  31. package/dist/cli/commands/task.d.mts.map +1 -1
  32. package/dist/cli/commands/task.mjs +84 -5
  33. package/dist/cli/commands/task.mjs.map +1 -1
  34. package/dist/cli/commands/validate-evidence.d.mts +24 -2
  35. package/dist/cli/commands/validate-evidence.d.mts.map +1 -1
  36. package/dist/cli/commands/validate-evidence.mjs +154 -17
  37. package/dist/cli/commands/validate-evidence.mjs.map +1 -1
  38. package/dist/cli/commands/vitest-doctor.d.mts +2 -0
  39. package/dist/cli/commands/vitest-doctor.d.mts.map +1 -0
  40. package/dist/cli/commands/vitest-doctor.mjs +168 -0
  41. package/dist/cli/commands/vitest-doctor.mjs.map +1 -0
  42. package/dist/cli/config/gitignore-drift.d.mts +23 -1
  43. package/dist/cli/config/gitignore-drift.d.mts.map +1 -1
  44. package/dist/cli/config/gitignore-drift.mjs +81 -3
  45. package/dist/cli/config/gitignore-drift.mjs.map +1 -1
  46. package/dist/cli/config/load.d.mts +56 -2
  47. package/dist/cli/config/load.d.mts.map +1 -1
  48. package/dist/cli/config/load.mjs +192 -2
  49. package/dist/cli/config/load.mjs.map +1 -1
  50. package/dist/cli/consistency/parse-review.mjs +7 -0
  51. package/dist/cli/consistency/parse-review.mjs.map +1 -1
  52. package/dist/cli/dispatch.d.mts.map +1 -1
  53. package/dist/cli/dispatch.mjs +24 -2
  54. package/dist/cli/dispatch.mjs.map +1 -1
  55. package/dist/cli/gate/gates/gitignore-in-sync.d.mts +1 -1
  56. package/dist/cli/gate/gates/gitignore-in-sync.d.mts.map +1 -1
  57. package/dist/cli/gate/gates/gitignore-in-sync.mjs +5 -2
  58. package/dist/cli/gate/gates/gitignore-in-sync.mjs.map +1 -1
  59. package/dist/cli/gate/gates/review-clean.d.mts +5 -1
  60. package/dist/cli/gate/gates/review-clean.d.mts.map +1 -1
  61. package/dist/cli/gate/gates/review-clean.mjs +23 -18
  62. package/dist/cli/gate/gates/review-clean.mjs.map +1 -1
  63. package/dist/cli/gate/gates/verify-approved.d.mts +49 -1
  64. package/dist/cli/gate/gates/verify-approved.d.mts.map +1 -1
  65. package/dist/cli/gate/gates/verify-approved.mjs +93 -14
  66. package/dist/cli/gate/gates/verify-approved.mjs.map +1 -1
  67. package/dist/cli/help.d.mts.map +1 -1
  68. package/dist/cli/help.mjs +7 -2
  69. package/dist/cli/help.mjs.map +1 -1
  70. package/dist/cli/install/runtime-detect.d.mts +13 -0
  71. package/dist/cli/install/runtime-detect.d.mts.map +1 -1
  72. package/dist/cli/install/runtime-detect.mjs +9 -0
  73. package/dist/cli/install/runtime-detect.mjs.map +1 -1
  74. package/dist/cli/task/index-md.d.mts.map +1 -1
  75. package/dist/cli/task/index-md.mjs +14 -2
  76. package/dist/cli/task/index-md.mjs.map +1 -1
  77. package/dist/plugin/.claude-plugin/plugin.json +11 -2
  78. package/dist/plugin/agents/apt-improver.md +99 -0
  79. package/dist/plugin/agents/apt-planner.md +127 -10
  80. package/dist/plugin/agents/apt-pr-review-fixer.md +13 -9
  81. package/dist/plugin/skills/apt/SKILL.md +1 -0
  82. package/dist/plugin/skills/apt-close-task/SKILL.md +63 -1
  83. package/dist/plugin/skills/apt-debug/SKILL.md +39 -6
  84. package/dist/plugin/skills/apt-debug/appendices/diagnose-discipline.md +119 -0
  85. package/dist/plugin/skills/apt-diagram/SKILL.md +378 -0
  86. package/dist/plugin/skills/apt-diagram/appendices/design-discipline.md +97 -0
  87. package/dist/plugin/skills/apt-discuss/SKILL.md +72 -5
  88. package/dist/plugin/skills/apt-discuss/appendices/grill-discipline.md +104 -0
  89. package/dist/plugin/skills/apt-discuss/appendices/zoom-out-helper.md +79 -0
  90. package/dist/plugin/skills/apt-execute/SKILL.md +57 -5
  91. package/dist/plugin/skills/apt-execute/appendices/tdd-mode.md +107 -0
  92. package/dist/plugin/skills/apt-improve/DEEPENING.md +84 -0
  93. package/dist/plugin/skills/apt-improve/INTERFACE-DESIGN.md +97 -0
  94. package/dist/plugin/skills/apt-improve/LANGUAGE.md +104 -0
  95. package/dist/plugin/skills/apt-improve/SKILL.md +141 -0
  96. package/dist/plugin/skills/apt-plan/SKILL.md +171 -4
  97. package/dist/plugin/skills/apt-plan/adapters/conductor.md +98 -0
  98. package/dist/plugin/skills/apt-pr-review/SKILL.md +57 -18
  99. package/dist/plugin/skills/apt-prototype/LOGIC.md +109 -0
  100. package/dist/plugin/skills/apt-prototype/SKILL.md +143 -0
  101. package/dist/plugin/skills/apt-prototype/UI.md +90 -0
  102. package/dist/plugin/skills/apt-quick/SKILL.md +49 -8
  103. package/dist/plugin/skills/apt-release-notes/SKILL.md +193 -0
  104. package/dist/plugin/skills/apt-release-notes/appendices/persona-voice.md +59 -0
  105. package/dist/plugin/skills/apt-review/SKILL.md +2 -0
  106. package/dist/plugin/skills/apt-run/SKILL.md +32 -4
  107. package/dist/plugin/skills/apt-setup/SKILL.md +308 -6
  108. package/dist/plugin/skills/apt-ship/SKILL.md +122 -1
  109. package/dist/plugin/skills/apt-spar/SKILL.md +315 -0
  110. package/dist/plugin/skills/apt-triage/AGENT-BRIEF.md +84 -0
  111. package/dist/plugin/skills/apt-triage/OUT-OF-SCOPE.md +75 -0
  112. package/dist/plugin/skills/apt-triage/SKILL.md +169 -0
  113. package/dist/plugin/skills/apt-update/SKILL.md +77 -10
  114. package/dist/plugin/skills/apt-verify/SKILL.md +3 -0
  115. package/dist/plugin/skills/apt-verify-proof/SKILL.md +10 -5
  116. package/dist/plugin/skills/apt-watch-ci/SKILL.md +166 -0
  117. package/dist/plugin/skills/apt-zoom-out/SKILL.md +130 -0
  118. package/package.json +133 -133
  119. package/prompts/conductor-framework-context.md +63 -0
  120. package/prompts/conductor-system.md +11 -0
  121. package/skills/apt-close-task/SKILL.md +1 -0
  122. package/skills/apt-discuss/SKILL.md +47 -5
  123. package/skills/apt-execute/SKILL.md +9 -0
  124. package/skills/apt-plan/SKILL.md +12 -0
  125. package/skills/apt-pr-review/SKILL.md +11 -2
  126. package/skills/apt-quick/SKILL.md +19 -8
  127. package/skills/apt-researcher.md +1 -0
  128. package/skills/apt-setup/SKILL.md +33 -2
  129. package/skills/apt-verify-proof/SKILL.md +7 -5
  130. package/src/cli/ci-watch/stop-matrix.mjs +17 -0
  131. package/src/cli/commands/ci-watch.mjs +113 -2
  132. package/src/cli/commands/features-audit.mjs +164 -5
  133. package/src/cli/commands/health-check.mjs +115 -2
  134. package/src/cli/commands/init.mjs +52 -4
  135. package/src/cli/commands/modes.mjs +11 -0
  136. package/src/cli/commands/pr-review-audit-fixer.mjs +18 -5
  137. package/src/cli/commands/task.mjs +83 -5
  138. package/src/cli/commands/validate-evidence.mjs +158 -17
  139. package/src/cli/commands/vitest-doctor.mjs +173 -0
  140. package/src/cli/config/gitignore-drift.mjs +74 -3
  141. package/src/cli/config/load.mjs +188 -2
  142. package/src/cli/consistency/parse-review.mjs +6 -0
  143. package/src/cli/dispatch.mjs +23 -2
  144. package/src/cli/gate/gates/gitignore-in-sync.mjs +5 -2
  145. package/src/cli/gate/gates/review-clean.mjs +24 -19
  146. package/src/cli/gate/gates/verify-approved.mjs +97 -14
  147. package/src/cli/help.mjs +7 -2
  148. package/src/cli/install/runtime-detect.mjs +9 -0
  149. package/src/cli/task/index-md.mjs +15 -2
  150. package/templates/config.json +2 -7
  151. package/workflows/verify-proof.md +8 -3
@@ -257,7 +257,7 @@ When the result is `unknown`, treat it as `external` for safety and prompt the u
257
257
  Authorship could not be auto-detected for PR #${PR_NUMBER}. Treat as [owned / external]? (default: external)
258
258
  ```
259
259
 
260
- If `autonomy_level >= 3` (yolo), skip the prompt and lock in `external`. Persist the user's answer to BOTH `pr-state.json:authorship` AND `config.json:pr_review.authorship_overrides['pr-${PR_NUMBER}']` so subsequent rounds don't re-ask.
260
+ If `autonomy_level >= 3` (yolo), skip the prompt and lock in `external`. Persist the user's answer to `pr-state.json:authorship` so subsequent rounds don't re-ask. (Per C56 A3 — authorship overrides moved from `config.json:pr_review.authorship_overrides` to per-PR `pr-state.json` so they GC with the pr-review round. Legacy `config.json` entries are still read with a deprecation warning + auto-promoted to pr-state on next `init-pr`; do NOT write to `config.json` from new code.)
261
261
 
262
262
  Store the result as `AUTHORSHIP_MODE` and use it as a gate at every later phase:
263
263
 
@@ -1195,6 +1195,12 @@ Take all confirmed, fixable findings and group them into up to 3 independent gro
1195
1195
 
1196
1196
  #### Step 3: Spawn Fix Agents
1197
1197
 
1198
+ **Capture the iteration-start SHA BEFORE spawning fixers** (used by both the Step 4b audit gate AND the per-fixer Pre-Return Self-Audit added in BUG-016 — fixers now commit atomically per finding, and the audit window is scoped by this SHA):
1199
+
1200
+ ```bash
1201
+ ITERATION_START_SHA=$(cd "${WORKTREE_PATH}" && git rev-parse HEAD)
1202
+ ```
1203
+
1198
1204
  For each fix group, spawn a fix agent. Read the agent definition from `.claude/agents/apt-pr-review-fixer.md` and fill in:
1199
1205
 
1200
1206
  | Placeholder | Value |
@@ -1207,6 +1213,7 @@ For each fix group, spawn a fix agent. Read the agent definition from `.claude/a
1207
1213
  | `[CRITICAL_APPROVAL]` | `true` or `false` for each critical finding in this group |
1208
1214
  | `[PARALLEL_FIXERS]` | `true` if more than 1 fixer is spawned this iteration |
1209
1215
  | `[WORKTREE_PATH]` | The worktree path — fix agents edit files HERE, not in the user's working directory |
1216
+ | `[ITERATION_START_SHA]` | The SHA captured BEFORE spawning fixers (see Step 4b's `ITERATION_START_SHA=$(...)` capture). Required for BUG-016 commit-discipline Pre-Return Self-Audit. |
1210
1217
 
1211
1218
  ```
1212
1219
  Agent(
@@ -1260,7 +1267,9 @@ If `--since-sha` is **omitted**, the CLI falls back to `git merge-base HEAD orig
1260
1267
 
1261
1268
  Rule of thumb: pass `--since-sha "${ITERATION_START_SHA}"` on every audit invocation. The merge-base fallback exists only so a missing flag doesn't flip every standard-branch-workflow repo into a false-positive hallucination — it is NOT a replacement for the explicit flag.
1262
1269
 
1263
- The CLI returns a JSON envelope with `verdict` ∈ `verified | hallucinated | skipped`, writes `iterations/${ITERATION}/audit.json` (append-only), and bumps `metadata.json.fixer_hallucinations_total` on every `hallucinated` outcome. The envelope's `observed.since_sha` + `observed.since_sha_source` fields record which SHA was used and where it came from (`flag` | `merge-base` | `null`). The same envelope is used for the fixer and the self-reviewer (Phase 7) — `--fixer self-reviewer` reads from `self-review.md` instead of `fixes-applied-group{N}.md`.
1270
+ The CLI returns a JSON envelope with `verdict` ∈ `verified | hallucinated | skipped`, writes `iterations/${ITERATION}/audit.json` (append-only), and bumps `metadata.json.fixer_hallucinations_total` on every `hallucinated` outcome. The envelope's `observed.since_sha` + `observed.since_sha_source` fields record which SHA was used and where it came from (`flag` | `merge-base` | `null`). The same envelope is used for the fixer and the self-reviewer (Phase 7) — `--fixer self-reviewer` reads from `self-review.md`.
1271
+
1272
+ **Canonical fix-report filename per fixer (BUG-030):** each fixer agent writes to `fixes-applied-${FIXER_NAME}.md` (e.g. `fixes-applied-fixer-1.md`). The audit CLI resolves candidates in strict order: `fixes-applied-group{N}.md` (legacy group-named, pre-BUG-030 reviews) → `fixes-applied-fixer-{N}.md` (NEW fixer-named) → `fixes-applied-${FIXER_NAME}.md` (exact match, preferred for non-numeric fixer names) → `fixes-applied.md` (legacy unscoped, single-fixer reviews only). Writing the canonical name eliminates the cross-fixer false-positive `hallucinated` verdict that fired when two parallel fixers shared `fixes-applied.md`.
1264
1273
 
1265
1274
  | Verdict | Orchestrator Action |
1266
1275
  |---------|---------------------|
@@ -1454,33 +1463,63 @@ node packages/framework/bin/apt-tools.mjs workflow advance . --id ${REVIEW_ID} -
1454
1463
 
1455
1464
  If `WORKTREE_PATH != .` AND fixes were applied in Phase 6/7:
1456
1465
 
1466
+ Get the PR head ref (for branch reviews, use the branch name directly):
1457
1467
  ```bash
1458
- cd ${WORKTREE_PATH}
1468
+ PR_HEAD_REF=$(gh pr view ${PR_NUMBER} --json headRefName -q .headRefName)
1469
+ ```
1459
1470
 
1460
- # Commit all staged fixes
1461
- git add -A
1462
- git commit -m "fix: auto-fix review findings from /apt:pr-review (review ${REVIEW_ID})"
1471
+ #### Confirmation gate (BUG-009 fix)
1463
1472
 
1464
- # Push fixes back to the PR branch
1465
- # For PRs: push to the PR's head ref
1466
- git push origin HEAD:${PR_HEAD_REF}
1473
+ Whether the push prompts for confirmation is controlled by `pr_review.confirm_before_push` in `.aperant/config.json` (tri-state: `ask` | `auto` | `never`; default when absent: `auto` at autonomy ≥ 2, `ask` at autonomy < 2). Mirrors the `pr_review.suggest_after_ship` precedent in `/apt:ship` Section 7.1 — `ask` is honest about the irreversible-ish nature of the push (re-triggers CI on origin, visible to teammates); `auto` honors yolo pipelines.
1467
1474
 
1468
- cd -
1475
+ ```bash
1476
+ confirm_mode=$(jq -r '.pr_review.confirm_before_push // empty' .aperant/config.json)
1477
+ autonomy=$(jq -r '.autonomy.default // 2' .aperant/config.json)
1478
+ if [ -z "$confirm_mode" ]; then
1479
+ if [ "${autonomy}" -ge 2 ]; then confirm_mode="auto"; else confirm_mode="ask"; fi
1480
+ fi
1469
1481
  ```
1470
1482
 
1471
- Where `PR_HEAD_REF` is the PR's head branch name (e.g., `feat/auth`). Get it from:
1483
+ Branch on `confirm_mode`:
1484
+
1485
+ - **`never`** — Skip push entirely. Print "fixes left in worktree; push manually with `git -C ${WORKTREE_PATH} push origin HEAD:${PR_HEAD_REF}`". Proceed to Step 0b cleanup.
1486
+ - **`auto`** — Proceed silently to the catch-all + push below. No prompt.
1487
+ - **`ask`** — Emit the structured question: `Fixes are ready in the worktree. Push to ${PR_HEAD_REF}? (y/n)`. On `n` or any non-`y`: same skip behavior as `never`. On `y` (or empty enter): proceed.
1488
+
1489
+ `confirm_before_push` is purely additive — it does not affect `authorship_override`, `authorship_overrides`, `max_rounds`, or `suggest_after_ship` in the same `pr_review` block.
1490
+
1491
+ #### Catch-all + push (BUG-010 fix)
1492
+
1493
+ The fixer pipeline normally produces atomic per-finding commits, so the worktree is clean by the time Step 0 runs. The catch-all commit below exists ONLY to capture uncommitted residue (rare — e.g. a fixer's pre-return self-audit failed to detect a stray edit). Guard it before committing:
1494
+
1472
1495
  ```bash
1473
- gh pr view ${PR_NUMBER} --json headRefName -q .headRefName
1474
- ```
1496
+ cd ${WORKTREE_PATH}
1475
1497
 
1476
- For branch reviews: push to the branch name directly.
1498
+ # Guard 1: skip the catch-all entirely if the tree is clean.
1499
+ # Per-finding commits with proper messages are strictly better history than a single catch-all.
1500
+ if ! git diff --quiet || ! git diff --cached --quiet || [ -n "$(git ls-files --others --exclude-standard)" ]; then
1501
+ # Guard 2: explicit allowlist instead of `git add -A`.
1502
+ # `git add -A` would sweep orchestrator-level Read/Write side-effects
1503
+ # (metadata.json, audit.json, validated.md, etc.) into the PR. Bad.
1504
+ # Stage ONLY files in the review's touched set, computed from the iteration diffs.
1505
+ REVIEW_TOUCHED=$(git diff --name-only ${ITERATION_START_SHA:-HEAD~4}..HEAD 2>/dev/null \
1506
+ | grep -v '^\.aperant/' \
1507
+ | tr '\n' ' ')
1508
+ if [ -n "$REVIEW_TOUCHED" ]; then
1509
+ # shellcheck disable=SC2086
1510
+ git add -- $REVIEW_TOUCHED
1511
+ fi
1512
+ # Only commit if `git add --` actually staged something.
1513
+ if ! git diff --cached --quiet; then
1514
+ git commit -m "fix: auto-fix review findings from /apt:pr-review (review ${REVIEW_ID})"
1515
+ fi
1516
+ fi
1477
1517
 
1478
- **IMPORTANT:** Ask the user for confirmation before pushing:
1479
- ```
1480
- Fixes are ready in the worktree. Push to ${PR_HEAD_REF}? (y/n)
1518
+ git push origin HEAD:${PR_HEAD_REF}
1519
+ cd -
1481
1520
  ```
1482
1521
 
1483
- If the user declines, skip the push but still write the report. The fixes remain in the worktree for manual review.
1522
+ Two guards. The outer `if` skips the whole catch-all path when the tree is clean. The inner allowlist (filter to files in the iteration-diff scope, minus anything under `.aperant/`) prevents `git add` from sweeping arbitrary orchestrator side-effects into the PR. Both guards default to the safe no-op shape on the happy path (fixers committed atomically, clean tree).
1484
1523
 
1485
1524
  ### Step 0b: Cleanup Worktree
1486
1525
 
@@ -0,0 +1,109 @@
1
+ <!--
2
+ Adapted from Matt Pocock's MIT-licensed skill suite:
3
+ https://github.com/mattpocock/skills/blob/main/skills/engineering/prototype/LOGIC.md
4
+ Licensed under MIT. Modifications: scoped to terminal-app prototypes
5
+ that validate state machines, protocols, and control flow. Aligned with
6
+ the 5 universal rules in apt-prototype/SKILL.md.
7
+ -->
8
+
9
+ # LOGIC branch — Terminal app for state-machine validation
10
+
11
+ When the user's question is about **behavior**, the prototype is a
12
+ single terminal app that the user runs and watches. The output prints
13
+ every state transition so the user can FEEL whether the logic works,
14
+ not just reason about it.
15
+
16
+ ## When this branch fires
17
+
18
+ Question types that route here:
19
+
20
+ - "Does this state machine work?"
21
+ - "Does this control flow handle edge case X?"
22
+ - "Can this protocol handle out-of-order messages?"
23
+ - "What does the worker pool do under back-pressure?"
24
+ - "Does this retry policy actually converge?"
25
+
26
+ Question types that DO NOT route here (use UI branch instead):
27
+
28
+ - "Does this UI shape feel right?"
29
+ - "Is this flow discoverable?"
30
+ - "Does this layout work on mobile?"
31
+
32
+ ## File shape
33
+
34
+ ONE file. Pick the project's primary runtime (TypeScript via `tsx`,
35
+ JavaScript via `node`, Python via `python3`, etc.). The shape:
36
+
37
+ ```
38
+ // THROWAWAY PROTOTYPE — do not merge, do not extend, do not test.
39
+ // Question: "{verbatim question from user}"
40
+ // Decision criterion: "{what does 'yes' look like? what does 'no' look like?}"
41
+
42
+ // --- State machine model ---
43
+ // {Declare states, transitions, and any guards.}
44
+
45
+ // --- Transition driver ---
46
+ // {A function that takes (currentState, event) and returns nextState,
47
+ // PRINTING every transition so the user can see what's happening.}
48
+
49
+ // --- Scripted run ---
50
+ // {5-10 sequential transitions that exercise the interesting paths.}
51
+ ```
52
+
53
+ ## Single-command invocation
54
+
55
+ The prototype runs with ONE command. Examples:
56
+
57
+ - `node prototype.mjs` — no transpile, no build, no install
58
+ - `pnpm dlx tsx prototype.ts` — uses dlx so no dependency added to the project
59
+ - `python3 prototype.py` — no virtualenv setup
60
+
61
+ If your prototype needs any of: webpack, vite, esbuild, a database
62
+ connection, an environment variable — you are prototyping the wrong
63
+ question. Re-scope to the BEHAVIOR question; the infrastructure is a
64
+ separate concern.
65
+
66
+ ## Surface-state-transparently — concrete examples
67
+
68
+ A terminal app prints state transitions inline:
69
+
70
+ ```
71
+ [T+0] state=IDLE
72
+ [T+1] event=user.click.submit → state=SUBMITTING
73
+ [T+2] event=network.timeout → state=RETRYING (attempt 1)
74
+ [T+3] event=network.timeout → state=RETRYING (attempt 2)
75
+ [T+4] event=network.timeout → state=FAILED (exceeded retries)
76
+ ```
77
+
78
+ The user reads this output and either says "yes that's what I wanted"
79
+ or "no, the retry policy needs jitter" — and the question is answered
80
+ in 30 seconds of looking, not 3 hours of staring at a flowchart.
81
+
82
+ If the state machine has parallel regions or hierarchical states, print
83
+ the full state vector at each transition, not just the leaf state.
84
+
85
+ ## When the scripted run isn't enough
86
+
87
+ If the user needs to drive the state machine interactively (the
88
+ question is "what happens when I hit submit twice quickly?"), add a
89
+ tiny REPL loop:
90
+
91
+ ```
92
+ > submit
93
+ [T+1] event=user.click.submit → state=SUBMITTING
94
+ > submit
95
+ [T+2] event=user.click.submit (REJECTED — already submitting)
96
+ [T+2] state=SUBMITTING
97
+ > timeout
98
+ [T+3] event=network.timeout → state=RETRYING (attempt 1)
99
+ ```
100
+
101
+ Keep the REPL parser dumb (split on space, no quoting, no escape
102
+ handling). The user isn't testing your parser; they're testing the
103
+ state machine.
104
+
105
+ ## Throwaway discipline reminder
106
+
107
+ When the question is answered, delete the prototype file. Do not let it
108
+ linger as "documentation of the design decision" — that's what
109
+ `apt-tools adr write` or `.aperant/context/notes/` are for.
@@ -0,0 +1,143 @@
1
+ ---
2
+ name: apt:prototype
3
+ description: "Question-driven throwaway prototyping with 5-rule discipline — LOGIC branch (terminal-app for state-machine validation) and UI branch (delegates to apt:mockup)"
4
+ apt-skill-version: {{APT_VERSION}}
5
+ stage: design
6
+ intent: design
7
+ when_to_use: "The user has a question that wants a runnable prototype rather than a plan — 'does this state machine work?' (LOGIC branch) or 'does this UI shape feel right?' (UI branch). Throwaway code by design; do NOT confuse this with apt:plan or apt:execute."
8
+ user_invocable: true
9
+ internal: false
10
+ spawns_agent: false
11
+ agent_name: null
12
+ task_context: create-new
13
+ default_track: STANDARD
14
+ default_execution_mode: step
15
+ execution_modes:
16
+ - auto
17
+ - step
18
+ allowed-tools: "Bash, Read, Write, Edit, Grep, Glob"
19
+ argument-hint: "apt:prototype [question]"
20
+ gates: []
21
+ config_keys:
22
+ - coding.prototype_discipline
23
+ ---
24
+
25
+ # Prototype — Question-Driven Throwaway Code
26
+
27
+ This skill ships throwaway code that answers ONE question. It is NOT a
28
+ planning artifact, NOT a feature, and NOT something to merge. The output
29
+ is a single-command-runnable prototype that lets the user feel whether
30
+ the question's answer is "yes" or "no", then gets thrown away.
31
+
32
+ **Pocock adoption attribution.** Discipline ported from Matt Pocock's
33
+ MIT-licensed `prototype` skill. Routes between two branches by
34
+ question-type; the UI branch delegates to Aperant's existing
35
+ `/apt:mockup` skill for HTML+Tailwind variants. The LOGIC branch and
36
+ the 5-rule discipline are new for Aperant.
37
+
38
+ ## When to Use
39
+
40
+ - The user asks a question (not a "build me X" request) — "does this
41
+ state machine work?", "does this UI shape feel right?", "would users
42
+ find this discoverable?"
43
+ - A throwaway prototype is the cheapest answer (cheaper than designing,
44
+ planning, building, then discovering the answer was "no")
45
+ - The answer can be felt by running the prototype, not just reasoning
46
+ about it
47
+
48
+ ## When NOT to Use
49
+
50
+ - The user has a feature request — use `/apt:plan` + `/apt:execute`
51
+ - The user wants a polished mockup to share — use `/apt:mockup` directly
52
+ (the UI branch of this skill delegates there anyway)
53
+ - The user wants production code with tests — that's TDD-mode
54
+ `/apt:execute --tdd`, not a prototype
55
+
56
+ ## Branch routing
57
+
58
+ Inspect the user's question:
59
+
60
+ - **LOGIC branch** — triggers: "does this state machine work?", "does
61
+ this control flow handle edge case X?", "can this protocol handle
62
+ out-of-order messages?". Answer: a single-file terminal app the user
63
+ can run with one command to feel the state transitions.
64
+ - **UI branch** — triggers: "does this UI shape feel right?", "is this
65
+ flow discoverable?", "does this layout work on mobile?". Answer:
66
+ delegate to `/apt:mockup --variants 3` for HTML+Tailwind parallel
67
+ variants.
68
+
69
+ If the question is genuinely ambiguous, ask ONE clarifying question
70
+ ("are you asking about behavior or appearance?") — do NOT enter a long
71
+ interview.
72
+
73
+ ## The 5 Universal Rules (Pocock discipline, applies to both branches)
74
+
75
+ These five rules apply to EVERY prototype this skill produces. They are
76
+ load-bearing — violating them collapses the prototype into ceremony
77
+ disguised as a question.
78
+
79
+ 1. **Throwaway-marked.** Every prototype file MUST carry a top-of-file
80
+ comment: `// THROWAWAY PROTOTYPE — do not merge, do not extend, do
81
+ not test.` This is not optional. Files without this marker drift into
82
+ production code and the question never gets answered cleanly.
83
+
84
+ 2. **Single-command-run.** The prototype runs with ONE command. No
85
+ build step. No dependency install. `node prototype.mjs` or `pnpm dlx
86
+ tsx prototype.ts` or `bash prototype.sh` — pick one and stop. If you
87
+ reach for webpack, you're prototyping a build, not the question.
88
+
89
+ 3. **No-persistence-default.** The prototype does NOT touch any
90
+ persistent store (libSQL, Convex, localStorage, .aperant/state.json).
91
+ Everything is in-memory. If persistence is part of the question,
92
+ explicitly opt in via a tmpfile — never the project's actual stores.
93
+
94
+ 4. **Skip-polish.** No error handling for impossible scenarios. No
95
+ accessibility audit. No mobile responsive breakpoints unless the
96
+ question is about mobile. No animation refinement. Polish is what
97
+ you do AFTER the prototype answered "yes"; doing it now obscures
98
+ whether the answer was actually "yes".
99
+
100
+ 5. **Surface-state-transparently.** The prototype prints / renders its
101
+ internal state at every step the user might want to inspect. A
102
+ terminal app prints every state transition. A UI prototype shows
103
+ the data shape next to the rendered output. The user must be able
104
+ to SEE what's happening — they can't feel an answer to "does this
105
+ work" if the state is hidden.
106
+
107
+ ## LOGIC branch — terminal app for state-machine validation
108
+
109
+ When the question is about behavior / control flow / state machines /
110
+ protocols:
111
+
112
+ 1. Read `LOGIC.md` for the discipline (ported from Pocock's
113
+ `prototype/LOGIC.md` with MIT attribution).
114
+ 2. Write ONE file (e.g., `prototype.mjs`, `prototype.ts`, or
115
+ `prototype.py`) that:
116
+ - Models the state machine in code
117
+ - Provides a command-line driver that fires transitions one at a
118
+ time, printing each state
119
+ - Includes a 5-10 turn scripted run at the bottom that exercises the
120
+ interesting paths
121
+ 3. Write a one-line invocation: `node prototype.mjs` (or whatever).
122
+ 4. Verify: run it. The user reads the output, gets their answer, and
123
+ the file is deleted.
124
+
125
+ ## UI branch — delegates to apt:mockup
126
+
127
+ When the question is about layout / aesthetics / flow / discoverability:
128
+
129
+ 1. Read `UI.md` for the discipline (ported from Pocock's
130
+ `prototype/UI.md` with MIT attribution).
131
+ 2. Invoke `/apt:mockup --variants 3` as a sub-step. apt:mockup already
132
+ enforces the UI-specific universal rules (zero-dep Tailwind CDN, no
133
+ JS, throwaway HTML iterations preserved).
134
+ 3. The 5 universal rules above still apply — verify each HTML file
135
+ carries the `<!-- THROWAWAY PROTOTYPE -->` marker.
136
+
137
+ ## Output contract
138
+
139
+ - Single prototype file (LOGIC) OR 3 HTML variants via apt:mockup (UI).
140
+ - No commits. No tests. No docs. The skill emits a final note: "Delete
141
+ this when the question is answered."
142
+ - If the user wants to convert the prototype into real code, that's a
143
+ separate `/apt:plan` invocation.
@@ -0,0 +1,90 @@
1
+ <!--
2
+ Adapted from Matt Pocock's MIT-licensed skill suite:
3
+ https://github.com/mattpocock/skills/blob/main/skills/engineering/prototype/UI.md
4
+ Licensed under MIT. Modifications: routed through Aperant's existing
5
+ apt:mockup skill rather than a freestanding HTML+Tailwind generator;
6
+ aligned with the 5 universal rules in apt-prototype/SKILL.md.
7
+ -->
8
+
9
+ # UI branch — Delegates to apt:mockup
10
+
11
+ When the user's question is about **appearance / layout / flow /
12
+ discoverability**, the prototype is one or more HTML files generated
13
+ by Aperant's existing `/apt:mockup` skill. apt:mockup already enforces
14
+ the UI-specific universal rules (zero-dep Tailwind CDN, no JS, throwaway
15
+ HTML iterations preserved).
16
+
17
+ ## When this branch fires
18
+
19
+ Question types that route here:
20
+
21
+ - "Does this UI shape feel right?"
22
+ - "Is this flow discoverable?"
23
+ - "Does this layout work on mobile?"
24
+ - "Should the primary action be a button or a card?"
25
+ - "How does X scale to N items?"
26
+
27
+ Question types that DO NOT route here (use LOGIC branch):
28
+
29
+ - "Does this state machine work?"
30
+ - "Does this control flow handle edge case X?"
31
+ - "Can this protocol handle out-of-order messages?"
32
+
33
+ ## How the delegation works
34
+
35
+ apt:prototype's UI branch is a thin wrapper that:
36
+
37
+ 1. Parses the user's question to extract the UI element / flow being
38
+ asked about (e.g., "search results card with N items").
39
+ 2. Invokes the existing skill: `/apt:mockup --variants 3 [extracted topic]`.
40
+ 3. apt:mockup produces 3 parallel HTML+Tailwind variants under
41
+ `.aperant/mockups/{topic-slug}/` so the user can compare them
42
+ side-by-side.
43
+
44
+ apt:prototype does NOT re-implement HTML+Tailwind generation — the
45
+ discipline lives in apt:mockup's body. UI.md exists so the apt:prototype
46
+ skill body can branch on question-type without conflating "logic
47
+ prototype" and "UI mockup" code paths.
48
+
49
+ ## The 5 universal rules still apply
50
+
51
+ apt:mockup already enforces:
52
+
53
+ - Throwaway-marked (each HTML file carries a comment marker)
54
+ - Single-command-run (`open mockup.html` — zero dependencies)
55
+ - No-persistence-default (static HTML, no localStorage usage by default)
56
+ - Skip-polish (CSS reset, no animation refinement, no responsive
57
+ breakpoints unless the question is about responsive)
58
+
59
+ The fifth rule — **surface-state-transparently** — is the one
60
+ apt:mockup doesn't fully cover by default. For UI prototypes where the
61
+ question is about data shape (e.g., "what does this look like with 0
62
+ items vs 100 items?"), instruct apt:mockup to render each variant with
63
+ a different data-fixture state, and put the fixture JSON in a
64
+ side-panel of each mockup so the user can see what's driving the
65
+ render.
66
+
67
+ ## What apt:prototype's UI branch adds over running apt:mockup directly
68
+
69
+ Two things:
70
+
71
+ 1. **Question framing.** apt:mockup is invocable as "build me a mockup
72
+ of X". apt:prototype's UI branch is invocable as "I have a question
73
+ about UI X — show me three answers." The framing shifts the
74
+ discipline from "deliver the mockup the user asked for" to "answer
75
+ the user's question with the cheapest possible visual artifact."
76
+
77
+ 2. **5-rule cross-discipline reminder.** When the UI branch fires, the
78
+ skill body explicitly re-states all 5 universal rules (not just the
79
+ UI-specific ones). The user gets the apt:prototype mental model on
80
+ top of apt:mockup's mechanical output — which prevents the variant
81
+ from drifting into "polish this until it's production-ready."
82
+
83
+ ## When the apt:mockup delegation is NOT enough
84
+
85
+ If the question requires interaction the user can drive (click through,
86
+ hover states, conditional rendering on input), the right call is
87
+ `/apt:prototype` LOGIC branch on top of `/apt:mockup` — a tiny
88
+ JS-driven terminal-ish runner that swaps between the 3 mockups based
89
+ on simulated state. This is rare; most UI questions are answered by
90
+ the side-by-side parallel variants apt:mockup already produces.
@@ -21,6 +21,8 @@ gates: []
21
21
  ---
22
22
  <objective>
23
23
  Execute a small task quickly without full pipeline overhead. For small fixes, doc updates, config changes, and ad-hoc tasks. Skip planning — go straight to implementation with atomic commits and lightweight state tracking.
24
+
25
+ **QUICK is sequential single-agent by contract.** Per roundtable 2026-05-14 (R1), QUICK = one agent doing intent → implementation in one context window. There are no phase sub-agents. This is a contract, not an optimization — the QUICK track exists precisely because phase isolation buys nothing on tasks small enough that the planner's mental model and the implementer's mental model would be identical.
24
26
  </objective>
25
27
 
26
28
  <your_environment>
@@ -99,6 +101,34 @@ If the task does NOT cross any obligation axes, proceed normally.
99
101
  2. Use Glob/Grep to find the files that need changes
100
102
  3. Read those files to understand current state
101
103
 
104
+ ## 3.5. Risk Check (mandatory)
105
+
106
+ Before implementing, check the risk class of files this task will modify. QUICK shares the same Critical/Destructive hard stop as `/apt:execute` step 3b — the speed of QUICK does NOT waive the risk gate. Misclassified QUICK tasks touching `**/auth/**`, `**/schema*`, `**/convex/schema.*`, or other Critical paths must NOT commit without explicit human approval.
107
+
108
+ ```bash
109
+ node .aperant/deps/node_modules/@aperant/framework/bin/apt-tools.mjs risk-check . --paths {target files}
110
+ ```
111
+
112
+ If the task description contains destructive keywords ("delete", "remove", "drop", "force-push"), pass `--operation delete` so glob matching covers the destructive intent.
113
+
114
+ Parse the JSON result and apply the gate:
115
+
116
+ **If `risk_class` is `"Critical"` or `"Destructive"`:**
117
+ Stop execution. Show the user:
118
+ ```
119
+ RISK GATE: This QUICK task touches {risk_class} files.
120
+ Files: {matched_paths list}
121
+ Pattern: {matched_pattern}
122
+
123
+ Approve this change? (yes/no)
124
+ ```
125
+ Wait for explicit approval. If denied, abort the task and record `verification.risk_gate = "denied"` in `task.json`. The gate is hardcoded at ALL autonomy levels — QUICK does not get to skip it.
126
+
127
+ **If `risk_class` is `"Elevated"` AND autonomy < 3:**
128
+ Show the affected files briefly before proceeding (5-second delay; user can interrupt). At YOLO autonomy, proceed without stopping.
129
+
130
+ **Why this exists:** roundtable 2026-05-14 R1 surfaced that `apt-quick` previously had no risk-check gate, meaning a misclassified QUICK task touching schema/auth could commit Critical-path changes with zero code-level safeguard. See `.aperant/roundtables/phase-mode-per-track-20260514/REPORT.md` (R1, Risk Assessment §1).
131
+
102
132
  ## 4. Implement
103
133
 
104
134
  Make the changes directly:
@@ -249,18 +279,29 @@ skill MUST exit silently regardless of the config value, so spawned subagents
249
279
  never block on a prompt that no human will answer.
250
280
 
251
281
  ```bash
252
- # Pseudocode the model executes inline:
282
+ # Pseudocode the model executes inline.
283
+ # AUDIT-001: `preferences.quick_task_post_verify` is per-device — read from
284
+ # the MERGED config (shared `.aperant/config.json` + local
285
+ # `.aperant/config.local.json`). Local wins on collision. Reading raw
286
+ # `config.json` only would miss per-device overrides.
253
287
  node -e '
254
288
  const fs = require("fs");
255
289
  const path = require("path");
256
- const cfgPath = path.join(process.cwd(), ".aperant/config.json");
290
+ const readJsonOrEmpty = (p) => { try { return JSON.parse(fs.readFileSync(p, "utf-8")) ?? {} } catch { return {} } };
291
+ const shared = readJsonOrEmpty(path.join(process.cwd(), ".aperant/config.json"));
292
+ const local = readJsonOrEmpty(path.join(process.cwd(), ".aperant/config.local.json"));
293
+ function merge(a, b) {
294
+ if (a === null || typeof a !== "object" || Array.isArray(a)) return b;
295
+ if (b === null || typeof b !== "object" || Array.isArray(b)) return b;
296
+ const out = { ...a };
297
+ for (const k of Object.keys(b)) out[k] = (k in a) ? merge(a[k], b[k]) : b[k];
298
+ return out;
299
+ }
300
+ const cfg = merge(shared, local);
257
301
  let mode = "ask";
258
- try {
259
- const cfg = JSON.parse(fs.readFileSync(cfgPath, "utf-8"));
260
- if (cfg && cfg.preferences && cfg.preferences.quick_task_post_verify) {
261
- mode = cfg.preferences.quick_task_post_verify;
262
- }
263
- } catch {}
302
+ if (cfg.preferences && cfg.preferences.quick_task_post_verify) {
303
+ mode = cfg.preferences.quick_task_post_verify;
304
+ }
264
305
  if (mode === "never" || !process.stdin.isTTY) process.exit(0);
265
306
  if (mode === "always") { /* invoke apt:verify {task-id} */ process.exit(0); }
266
307
  // mode === "ask": readline prompt with 30s timeout, default = skip.