@aperant/framework 0.8.1 → 0.8.4

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 (248) hide show
  1. package/CHANGELOG.md +287 -1
  2. package/agents/apt-planner.md +5 -4
  3. package/dist/cli/commands/adr.mjs +1 -1
  4. package/dist/cli/commands/audit-branch-current.d.mts +25 -0
  5. package/dist/cli/commands/audit-branch-current.d.mts.map +1 -0
  6. package/dist/cli/commands/audit-branch-current.mjs +252 -0
  7. package/dist/cli/commands/audit-branch-current.mjs.map +1 -0
  8. package/dist/cli/commands/audit.d.mts.map +1 -1
  9. package/dist/cli/commands/audit.mjs +13 -2
  10. package/dist/cli/commands/audit.mjs.map +1 -1
  11. package/dist/cli/commands/check-version.d.mts.map +1 -1
  12. package/dist/cli/commands/check-version.mjs +19 -1
  13. package/dist/cli/commands/check-version.mjs.map +1 -1
  14. package/dist/cli/commands/context.mjs +3 -3
  15. package/dist/cli/commands/context.mjs.map +1 -1
  16. package/dist/cli/commands/detect-runtime.d.mts +6 -0
  17. package/dist/cli/commands/detect-runtime.d.mts.map +1 -0
  18. package/dist/cli/commands/detect-runtime.mjs +136 -0
  19. package/dist/cli/commands/detect-runtime.mjs.map +1 -0
  20. package/dist/cli/commands/driver-doctor.d.mts +29 -0
  21. package/dist/cli/commands/driver-doctor.d.mts.map +1 -0
  22. package/dist/cli/commands/driver-doctor.mjs +291 -0
  23. package/dist/cli/commands/driver-doctor.mjs.map +1 -0
  24. package/dist/cli/commands/gate.mjs +14 -0
  25. package/dist/cli/commands/gate.mjs.map +1 -1
  26. package/dist/cli/commands/init.d.mts.map +1 -1
  27. package/dist/cli/commands/init.mjs +9 -6
  28. package/dist/cli/commands/init.mjs.map +1 -1
  29. package/dist/cli/commands/install-from-source.d.mts +2 -0
  30. package/dist/cli/commands/install-from-source.d.mts.map +1 -0
  31. package/dist/cli/commands/install-from-source.mjs +2 -0
  32. package/dist/cli/commands/install-from-source.mjs.map +1 -0
  33. package/dist/cli/commands/modes.mjs +1 -1
  34. package/dist/cli/commands/route.d.mts.map +1 -1
  35. package/dist/cli/commands/route.mjs +38 -1
  36. package/dist/cli/commands/route.mjs.map +1 -1
  37. package/dist/cli/commands/triage.mjs +1 -1
  38. package/dist/cli/config/load.d.mts.map +1 -1
  39. package/dist/cli/config/load.mjs +9 -3
  40. package/dist/cli/config/load.mjs.map +1 -1
  41. package/dist/cli/coordination/auto-emit-artifact-ready.mjs +1 -1
  42. package/dist/cli/coordination/event-schema.d.mts.map +1 -1
  43. package/dist/cli/coordination/event-schema.mjs +18 -0
  44. package/dist/cli/coordination/event-schema.mjs.map +1 -1
  45. package/dist/cli/dispatch.d.mts.map +1 -1
  46. package/dist/cli/dispatch.mjs +18 -1
  47. package/dist/cli/dispatch.mjs.map +1 -1
  48. package/dist/cli/gate/context.d.mts +1 -0
  49. package/dist/cli/gate/context.d.mts.map +1 -1
  50. package/dist/cli/gate/context.mjs +14 -1
  51. package/dist/cli/gate/context.mjs.map +1 -1
  52. package/dist/cli/gate/gates/consistency-check.d.mts +1 -0
  53. package/dist/cli/gate/gates/consistency-check.d.mts.map +1 -1
  54. package/dist/cli/gate/gates/consistency-check.mjs +1 -0
  55. package/dist/cli/gate/gates/consistency-check.mjs.map +1 -1
  56. package/dist/cli/gate/gates/review-clean.d.mts +1 -0
  57. package/dist/cli/gate/gates/review-clean.d.mts.map +1 -1
  58. package/dist/cli/gate/gates/review-clean.mjs +1 -0
  59. package/dist/cli/gate/gates/review-clean.mjs.map +1 -1
  60. package/dist/cli/gate/gates/verify-approved.d.mts +1 -0
  61. package/dist/cli/gate/gates/verify-approved.d.mts.map +1 -1
  62. package/dist/cli/gate/gates/verify-approved.mjs +1 -0
  63. package/dist/cli/gate/gates/verify-approved.mjs.map +1 -1
  64. package/dist/cli/gate/registry.d.mts.map +1 -1
  65. package/dist/cli/gate/registry.mjs +9 -1
  66. package/dist/cli/gate/registry.mjs.map +1 -1
  67. package/dist/cli/install/find-workspace-framework-version.d.mts +16 -0
  68. package/dist/cli/install/find-workspace-framework-version.d.mts.map +1 -0
  69. package/dist/cli/install/find-workspace-framework-version.mjs +85 -0
  70. package/dist/cli/install/find-workspace-framework-version.mjs.map +1 -0
  71. package/dist/cli/install/install-from-source.d.mts +10 -0
  72. package/dist/cli/install/install-from-source.d.mts.map +1 -0
  73. package/dist/cli/install/install-from-source.mjs +271 -0
  74. package/dist/cli/install/install-from-source.mjs.map +1 -0
  75. package/dist/cli/install/install-kernel.d.mts.map +1 -1
  76. package/dist/cli/install/install-kernel.mjs +24 -0
  77. package/dist/cli/install/install-kernel.mjs.map +1 -1
  78. package/dist/cli/install/legacy-paths.d.mts +33 -11
  79. package/dist/cli/install/legacy-paths.d.mts.map +1 -1
  80. package/dist/cli/install/legacy-paths.mjs +161 -39
  81. package/dist/cli/install/legacy-paths.mjs.map +1 -1
  82. package/dist/cli/install/runtime-detect.mjs +1 -1
  83. package/dist/cli/install/runtime-detect.mjs.map +1 -1
  84. package/dist/cli/install/runtime-migrate.d.mts +34 -14
  85. package/dist/cli/install/runtime-migrate.d.mts.map +1 -1
  86. package/dist/cli/install/runtime-migrate.mjs +63 -30
  87. package/dist/cli/install/runtime-migrate.mjs.map +1 -1
  88. package/dist/cli/install/transforms/codex.d.mts.map +1 -1
  89. package/dist/cli/install/transforms/codex.mjs +28 -17
  90. package/dist/cli/install/transforms/codex.mjs.map +1 -1
  91. package/dist/cli/skill-author/contract.mjs +2 -2
  92. package/dist/cli/skill-author/contract.mjs.map +1 -1
  93. package/dist/cli/verify-proof/audit.d.mts +34 -0
  94. package/dist/cli/verify-proof/audit.d.mts.map +1 -0
  95. package/dist/cli/verify-proof/audit.mjs +53 -0
  96. package/dist/cli/verify-proof/audit.mjs.map +1 -0
  97. package/dist/cli/verify-proof/exec.d.mts +20 -0
  98. package/dist/cli/verify-proof/exec.d.mts.map +1 -0
  99. package/dist/cli/verify-proof/exec.mjs +74 -0
  100. package/dist/cli/verify-proof/exec.mjs.map +1 -0
  101. package/dist/cli/verify-proof/idl/index.d.mts +2 -0
  102. package/dist/cli/verify-proof/idl/index.d.mts.map +1 -0
  103. package/dist/cli/verify-proof/idl/index.mjs +14 -0
  104. package/dist/cli/verify-proof/idl/index.mjs.map +1 -0
  105. package/dist/cli/verify-proof/idl/types.d.ts +9 -0
  106. package/dist/cli/verify-proof/idl/types.d.ts.map +1 -0
  107. package/dist/cli/verify-proof/idl/types.js +9 -0
  108. package/dist/cli/verify-proof/idl/types.js.map +1 -0
  109. package/dist/cli/verify-proof/manifest-validator.d.mts +19 -0
  110. package/dist/cli/verify-proof/manifest-validator.d.mts.map +1 -0
  111. package/dist/cli/verify-proof/manifest-validator.mjs +182 -0
  112. package/dist/cli/verify-proof/manifest-validator.mjs.map +1 -0
  113. package/dist/cli/verify-proof/resolver.d.mts +43 -0
  114. package/dist/cli/verify-proof/resolver.d.mts.map +1 -0
  115. package/dist/cli/verify-proof/resolver.mjs +160 -0
  116. package/dist/cli/verify-proof/resolver.mjs.map +1 -0
  117. package/dist/cli/verify-proof/runtime-detect.d.mts +27 -0
  118. package/dist/cli/verify-proof/runtime-detect.d.mts.map +1 -0
  119. package/dist/cli/verify-proof/runtime-detect.mjs +116 -0
  120. package/dist/cli/verify-proof/runtime-detect.mjs.map +1 -0
  121. package/dist/cli/verify-proof/trust.d.mts +70 -0
  122. package/dist/cli/verify-proof/trust.d.mts.map +1 -0
  123. package/dist/cli/verify-proof/trust.mjs +174 -0
  124. package/dist/cli/verify-proof/trust.mjs.map +1 -0
  125. package/dist/plugin/.claude-plugin/plugin.json +3 -1
  126. package/dist/plugin/agents/apt-planner.md +5 -4
  127. package/dist/plugin/skills/apt/SKILL.md +75 -6
  128. package/dist/plugin/skills/apt-caveman/SKILL.md +64 -0
  129. package/dist/plugin/skills/apt-debug/SKILL.md +36 -4
  130. package/dist/plugin/skills/apt-debug/appendices/diagnose-discipline.md +2 -11
  131. package/dist/plugin/skills/apt-discuss/SKILL.md +4 -4
  132. package/dist/plugin/skills/apt-discuss/appendices/grill-discipline.md +2 -11
  133. package/dist/plugin/skills/apt-discuss/appendices/zoom-out-helper.md +0 -8
  134. package/dist/plugin/skills/apt-execute/SKILL.md +27 -4
  135. package/dist/plugin/skills/apt-execute/appendices/tdd-mode.md +2 -10
  136. package/dist/plugin/skills/apt-fan-out/SKILL.md +36 -1
  137. package/dist/plugin/skills/apt-handoff/SKILL.md +228 -0
  138. package/dist/plugin/skills/apt-improve/DEEPENING.md +0 -8
  139. package/dist/plugin/skills/apt-improve/INTERFACE-DESIGN.md +0 -8
  140. package/dist/plugin/skills/apt-improve/LANGUAGE.md +0 -8
  141. package/dist/plugin/skills/apt-improve/SKILL.md +4 -4
  142. package/dist/plugin/skills/apt-plan/SKILL.md +23 -5
  143. package/dist/plugin/skills/apt-plan/adapters/conductor.md +1 -1
  144. package/dist/plugin/skills/apt-prototype/LOGIC.md +0 -8
  145. package/dist/plugin/skills/apt-prototype/SKILL.md +4 -4
  146. package/dist/plugin/skills/apt-prototype/UI.md +0 -8
  147. package/dist/plugin/skills/apt-quick/SKILL.md +31 -1
  148. package/dist/plugin/skills/apt-resume/SKILL.md +54 -31
  149. package/dist/plugin/skills/apt-run/SKILL.md +114 -16
  150. package/dist/plugin/skills/apt-setup/SKILL.md +97 -8
  151. package/dist/plugin/skills/apt-ship/SKILL.md +165 -9
  152. package/dist/plugin/skills/apt-spar/SKILL.md +65 -16
  153. package/dist/plugin/skills/apt-triage/AGENT-BRIEF.md +0 -8
  154. package/dist/plugin/skills/apt-triage/OUT-OF-SCOPE.md +0 -7
  155. package/dist/plugin/skills/apt-triage/SKILL.md +2 -2
  156. package/dist/plugin/skills/apt-update/SKILL.md +74 -17
  157. package/dist/plugin/skills/apt-verify-proof/SKILL.md +48 -1
  158. package/dist/plugin/skills/apt-zoom-out/SKILL.md +3 -3
  159. package/dist/schemas/quick-task.d.ts.map +1 -1
  160. package/dist/schemas/quick-task.js +2 -2
  161. package/dist/schemas/quick-task.js.map +1 -1
  162. package/dist/types/config.d.ts +33 -0
  163. package/dist/types/config.d.ts.map +1 -1
  164. package/dist/types/state.d.ts +1 -1
  165. package/dist/types/state.d.ts.map +1 -1
  166. package/dist/types/task-record.d.ts +1 -1
  167. package/dist/types/task-record.d.ts.map +1 -1
  168. package/package.json +134 -133
  169. package/prompts/planner.md +1 -1
  170. package/prompts/spec_writer.md +1 -1
  171. package/skills/apt/SKILL.md +75 -6
  172. package/skills/apt-caveman/SKILL.md +64 -0
  173. package/skills/apt-debug/SKILL.md +36 -4
  174. package/skills/apt-debug/appendices/diagnose-discipline.md +2 -11
  175. package/skills/apt-discuss/SKILL.md +4 -4
  176. package/skills/apt-discuss/appendices/grill-discipline.md +2 -11
  177. package/skills/apt-discuss/appendices/zoom-out-helper.md +0 -8
  178. package/skills/apt-execute/SKILL.md +27 -4
  179. package/skills/apt-execute/appendices/tdd-mode.md +2 -10
  180. package/skills/apt-fan-out/SKILL.md +36 -1
  181. package/skills/apt-handoff/SKILL.md +228 -0
  182. package/skills/apt-improve/DEEPENING.md +0 -8
  183. package/skills/apt-improve/INTERFACE-DESIGN.md +0 -8
  184. package/skills/apt-improve/LANGUAGE.md +0 -8
  185. package/skills/apt-improve/SKILL.md +4 -4
  186. package/skills/apt-plan/SKILL.md +23 -5
  187. package/skills/apt-plan/adapters/conductor.md +1 -1
  188. package/skills/apt-planner.md +1 -1
  189. package/skills/apt-prototype/LOGIC.md +0 -8
  190. package/skills/apt-prototype/SKILL.md +4 -4
  191. package/skills/apt-prototype/UI.md +0 -8
  192. package/skills/apt-quick/SKILL.md +31 -1
  193. package/skills/apt-resume/SKILL.md +54 -31
  194. package/skills/apt-run/SKILL.md +114 -16
  195. package/skills/apt-setup/SKILL.md +97 -8
  196. package/skills/apt-ship/SKILL.md +165 -9
  197. package/skills/apt-spar/SKILL.md +65 -16
  198. package/skills/apt-triage/AGENT-BRIEF.md +0 -8
  199. package/skills/apt-triage/OUT-OF-SCOPE.md +0 -7
  200. package/skills/apt-triage/SKILL.md +2 -2
  201. package/skills/apt-update/SKILL.md +74 -17
  202. package/skills/apt-verify-proof/SKILL.md +48 -1
  203. package/skills/apt-zoom-out/SKILL.md +3 -3
  204. package/src/cli/commands/adr.mjs +1 -1
  205. package/src/cli/commands/audit-branch-current.mjs +250 -0
  206. package/src/cli/commands/audit.mjs +13 -2
  207. package/src/cli/commands/check-version.mjs +20 -1
  208. package/src/cli/commands/context.mjs +3 -3
  209. package/src/cli/commands/detect-runtime.mjs +134 -0
  210. package/src/cli/commands/driver-doctor.mjs +294 -0
  211. package/src/cli/commands/gate.mjs +15 -0
  212. package/src/cli/commands/init.mjs +9 -6
  213. package/src/cli/commands/install-from-source.mjs +1 -0
  214. package/src/cli/commands/modes.mjs +1 -1
  215. package/src/cli/commands/route.mjs +42 -1
  216. package/src/cli/commands/triage.mjs +1 -1
  217. package/src/cli/config/load.mjs +9 -3
  218. package/src/cli/coordination/auto-emit-artifact-ready.mjs +1 -1
  219. package/src/cli/coordination/event-schema.mjs +19 -0
  220. package/src/cli/dispatch.mjs +17 -1
  221. package/src/cli/gate/context.mjs +20 -1
  222. package/src/cli/gate/gates/consistency-check.mjs +1 -0
  223. package/src/cli/gate/gates/review-clean.mjs +1 -0
  224. package/src/cli/gate/gates/verify-approved.mjs +1 -0
  225. package/src/cli/gate/registry.mjs +11 -1
  226. package/src/cli/install/find-workspace-framework-version.mjs +88 -0
  227. package/src/cli/install/install-from-source.mjs +276 -0
  228. package/src/cli/install/install-kernel.mjs +24 -0
  229. package/src/cli/install/legacy-paths.mjs +162 -39
  230. package/src/cli/install/runtime-detect.mjs +1 -1
  231. package/src/cli/install/runtime-migrate.mjs +63 -30
  232. package/src/cli/install/transforms/codex.mjs +26 -17
  233. package/src/cli/skill-author/contract.mjs +2 -2
  234. package/src/cli/verify-proof/.gitkeep +0 -0
  235. package/src/cli/verify-proof/audit.mjs +55 -0
  236. package/src/cli/verify-proof/exec.mjs +74 -0
  237. package/src/cli/verify-proof/idl/index.mjs +24 -0
  238. package/src/cli/verify-proof/idl/types.ts +41 -0
  239. package/src/cli/verify-proof/manifest-schema.json +211 -0
  240. package/src/cli/verify-proof/manifest-validator.mjs +184 -0
  241. package/src/cli/verify-proof/resolver.mjs +163 -0
  242. package/src/cli/verify-proof/runtime-detect.mjs +122 -0
  243. package/src/cli/verify-proof/trust.mjs +187 -0
  244. package/templates/adr-format.md +0 -8
  245. package/templates/aperant-claude-md-appendix.md +1 -1
  246. package/templates/context-format.md +1 -9
  247. package/templates/proof-verification.md +19 -5
  248. package/workflows/verify-proof.md +56 -14
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Compute a stable manifest hash for TOFU + audit lines.
3
+ * @param {DriverManifest} manifest
4
+ * @returns {string}
5
+ */
6
+ export function manifestSha256(manifest: DriverManifest): string;
7
+ /**
8
+ * Read the TOFU lock file. Returns an empty object if missing or malformed.
9
+ * @param {string} projectDir
10
+ * @returns {Record<string, {manifest_sha256: string, artifact_digest?: string, approved_at: string, trust_tier: string}>}
11
+ */
12
+ export function readTofuLock(projectDir: string): Record<string, {
13
+ manifest_sha256: string;
14
+ artifact_digest?: string;
15
+ approved_at: string;
16
+ trust_tier: string;
17
+ }>;
18
+ /**
19
+ * Persist a TOFU lock file (atomic-ish: write + rename not used since we
20
+ * append-only to a tiny JSON; conflicting writes from parallel agents
21
+ * would clobber an entry but `.aperant/driver-tofu.json` is per-project,
22
+ * not per-agent).
23
+ *
24
+ * @param {string} projectDir
25
+ * @param {Record<string, unknown>} tofu
26
+ */
27
+ export function writeTofuLock(projectDir: string, tofu: Record<string, unknown>): void;
28
+ /**
29
+ * Build the canonical TOFU key for a (driver, version) pair. The hash is
30
+ * NOT part of the key — the value's manifest_sha256 + artifact_digest
31
+ * detect drift.
32
+ * @param {string} driverId
33
+ * @param {string} version
34
+ * @returns {string}
35
+ */
36
+ export function tofuKey(driverId: string, version: string): string;
37
+ /**
38
+ * Read the project's policy file. Returns the default policy if missing.
39
+ * @param {string} projectDir
40
+ * @returns {{mode: 'first_party_only' | 'allowlist', allowed: string[], denied: string[]}}
41
+ */
42
+ export function readPolicy(projectDir: string): {
43
+ mode: "first_party_only" | "allowlist";
44
+ allowed: string[];
45
+ denied: string[];
46
+ };
47
+ /**
48
+ * Decide whether a driver invocation is allowed.
49
+ *
50
+ * @param {DriverManifest} manifest
51
+ * @param {ReturnType<typeof readTofuLock>} tofu
52
+ * @param {ReturnType<typeof readPolicy>} policy
53
+ * @returns {{decision: 'allow' | 'deny' | 'requires_approval', reason: string, expected_manifest_sha256?: string}}
54
+ */
55
+ export function decide(manifest: DriverManifest, tofu: ReturnType<typeof readTofuLock>, policy: ReturnType<typeof readPolicy>): {
56
+ decision: "allow" | "deny" | "requires_approval";
57
+ reason: string;
58
+ expected_manifest_sha256?: string;
59
+ };
60
+ /**
61
+ * Persist a one-time approval for a (driver, version) pair into the TOFU
62
+ * lock. The caller is responsible for actually prompting the user; this
63
+ * function just writes the entry.
64
+ *
65
+ * @param {string} projectDir
66
+ * @param {DriverManifest} manifest
67
+ */
68
+ export function recordApproval(projectDir: string, manifest: DriverManifest): void;
69
+ export type DriverManifest = import("@aperant/driver-sdk").DriverManifest;
70
+ //# sourceMappingURL=trust.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust.d.mts","sourceRoot":"","sources":["../../../src/cli/verify-proof/trust.mjs"],"names":[],"mappings":"AA+BA;;;;GAIG;AACH,yCAHW,cAAc,GACZ,MAAM,CAKlB;AAED;;;;GAIG;AACH,yCAHW,MAAM,GACJ,MAAM,CAAC,MAAM,EAAE;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAC,CAAC,CAUxH;AAED;;;;;;;;GAQG;AACH,0CAHW,MAAM,QACN,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,QAMjC;AAED;;;;;;;GAOG;AACH,kCAJW,MAAM,WACN,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,uCAHW,MAAM,GACJ;IAAC,IAAI,EAAE,kBAAkB,GAAG,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAC,CAgBzF;AAED;;;;;;;GAOG;AACH,iCALW,cAAc,QACd,UAAU,CAAC,OAAO,YAAY,CAAC,UAC/B,UAAU,CAAC,OAAO,UAAU,CAAC,GAC3B;IAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,mBAAmB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,wBAAwB,CAAC,EAAE,MAAM,CAAA;CAAC,CAwDjH;AAED;;;;;;;GAOG;AACH,2CAHW,MAAM,YACN,cAAc,QAYxB;6BAjKY,OAAO,qBAAqB,EAAE,cAAc"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * trust.mjs — driver trust enforcement (TOFU lock + policy file + decision).
3
+ *
4
+ * Implements ID-03:
5
+ * - 4 trust tiers: first_party_signed (default-allow), community_verified,
6
+ * community_unverified, local_unverified.
7
+ * - Default policy: only first_party_signed auto-runs.
8
+ * - Non-first-party drivers require one-time user approval; approval is
9
+ * bound to a TOFU lock at .aperant/driver-tofu.json keyed by
10
+ * {driver_id, version, manifest_sha256, artifact_digest}. Any drift
11
+ * re-prompts.
12
+ *
13
+ * The audit log (audit.mjs) writes one line per decision (allow/deny).
14
+ * The execution layer (exec.mjs) enforces structured-only local_command.
15
+ *
16
+ * This module is decision-only: it does NOT prompt the user. The caller
17
+ * (workflow runner / apt-tools driver doctor) decides whether to invoke
18
+ * the prompt UX, then calls recordApproval() to persist the TOFU entry.
19
+ */
20
+ import { createHash } from 'node:crypto';
21
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
22
+ import { dirname, join, resolve } from 'node:path';
23
+ /**
24
+ * @typedef {import('@aperant/driver-sdk').DriverManifest} DriverManifest
25
+ */
26
+ const TOFU_PATH = '.aperant/driver-tofu.json';
27
+ const POLICY_PATH = '.aperant/policy.json';
28
+ /**
29
+ * Compute a stable manifest hash for TOFU + audit lines.
30
+ * @param {DriverManifest} manifest
31
+ * @returns {string}
32
+ */
33
+ export function manifestSha256(manifest) {
34
+ const stable = JSON.stringify(manifest, Object.keys(manifest).sort());
35
+ return createHash('sha256').update(stable).digest('hex');
36
+ }
37
+ /**
38
+ * Read the TOFU lock file. Returns an empty object if missing or malformed.
39
+ * @param {string} projectDir
40
+ * @returns {Record<string, {manifest_sha256: string, artifact_digest?: string, approved_at: string, trust_tier: string}>}
41
+ */
42
+ export function readTofuLock(projectDir) {
43
+ const path = join(resolve(projectDir), TOFU_PATH);
44
+ if (!existsSync(path))
45
+ return {};
46
+ try {
47
+ return JSON.parse(readFileSync(path, 'utf-8'));
48
+ }
49
+ catch {
50
+ return {};
51
+ }
52
+ }
53
+ /**
54
+ * Persist a TOFU lock file (atomic-ish: write + rename not used since we
55
+ * append-only to a tiny JSON; conflicting writes from parallel agents
56
+ * would clobber an entry but `.aperant/driver-tofu.json` is per-project,
57
+ * not per-agent).
58
+ *
59
+ * @param {string} projectDir
60
+ * @param {Record<string, unknown>} tofu
61
+ */
62
+ export function writeTofuLock(projectDir, tofu) {
63
+ const path = join(resolve(projectDir), TOFU_PATH);
64
+ mkdirSync(dirname(path), { recursive: true });
65
+ writeFileSync(path, JSON.stringify(tofu, null, 2) + '\n', 'utf-8');
66
+ }
67
+ /**
68
+ * Build the canonical TOFU key for a (driver, version) pair. The hash is
69
+ * NOT part of the key — the value's manifest_sha256 + artifact_digest
70
+ * detect drift.
71
+ * @param {string} driverId
72
+ * @param {string} version
73
+ * @returns {string}
74
+ */
75
+ export function tofuKey(driverId, version) {
76
+ return `${driverId}@${version}`;
77
+ }
78
+ /**
79
+ * Read the project's policy file. Returns the default policy if missing.
80
+ * @param {string} projectDir
81
+ * @returns {{mode: 'first_party_only' | 'allowlist', allowed: string[], denied: string[]}}
82
+ */
83
+ export function readPolicy(projectDir) {
84
+ const path = join(resolve(projectDir), POLICY_PATH);
85
+ const defaults = { mode: 'first_party_only', allowed: [], denied: [] };
86
+ if (!existsSync(path))
87
+ return defaults;
88
+ try {
89
+ const parsed = JSON.parse(readFileSync(path, 'utf-8'));
90
+ return {
91
+ mode: parsed.mode === 'allowlist' ? 'allowlist' : 'first_party_only',
92
+ allowed: Array.isArray(parsed.allowed) ? parsed.allowed : [],
93
+ denied: Array.isArray(parsed.denied) ? parsed.denied : [],
94
+ };
95
+ }
96
+ catch {
97
+ return defaults;
98
+ }
99
+ }
100
+ /**
101
+ * Decide whether a driver invocation is allowed.
102
+ *
103
+ * @param {DriverManifest} manifest
104
+ * @param {ReturnType<typeof readTofuLock>} tofu
105
+ * @param {ReturnType<typeof readPolicy>} policy
106
+ * @returns {{decision: 'allow' | 'deny' | 'requires_approval', reason: string, expected_manifest_sha256?: string}}
107
+ */
108
+ export function decide(manifest, tofu, policy) {
109
+ const tier = manifest.trust?.tier;
110
+ const driverId = manifest.driverId;
111
+ const version = manifest.version;
112
+ // Policy denylist always wins.
113
+ if (policy.denied.includes(driverId)) {
114
+ return { decision: 'deny', reason: `policy denies driver ${driverId}` };
115
+ }
116
+ // first_party_signed: default-allow under either policy mode (unless
117
+ // explicitly denied above).
118
+ if (tier === 'first_party_signed') {
119
+ return { decision: 'allow', reason: 'first_party_signed driver — default allow' };
120
+ }
121
+ // first_party_only mode blocks every other tier.
122
+ if (policy.mode === 'first_party_only') {
123
+ return {
124
+ decision: 'deny',
125
+ reason: `policy.mode=first_party_only blocks ${tier} driver`,
126
+ };
127
+ }
128
+ // allowlist mode: require explicit allow entry AND a valid TOFU lock.
129
+ if (!policy.allowed.includes(driverId)) {
130
+ return {
131
+ decision: 'deny',
132
+ reason: `policy.mode=allowlist but ${driverId} not in allowed[]`,
133
+ };
134
+ }
135
+ // Check TOFU lock.
136
+ const key = tofuKey(driverId, version);
137
+ const entry = tofu[key];
138
+ const currentHash = manifestSha256(manifest);
139
+ if (!entry) {
140
+ return {
141
+ decision: 'requires_approval',
142
+ reason: `no TOFU entry for ${key} — first run requires approval`,
143
+ expected_manifest_sha256: currentHash,
144
+ };
145
+ }
146
+ if (entry.manifest_sha256 !== currentHash) {
147
+ return {
148
+ decision: 'requires_approval',
149
+ reason: `TOFU manifest_sha256 drift for ${key} — driver changed since approval, re-prompt required`,
150
+ expected_manifest_sha256: currentHash,
151
+ };
152
+ }
153
+ return { decision: 'allow', reason: `TOFU entry valid for ${key}` };
154
+ }
155
+ /**
156
+ * Persist a one-time approval for a (driver, version) pair into the TOFU
157
+ * lock. The caller is responsible for actually prompting the user; this
158
+ * function just writes the entry.
159
+ *
160
+ * @param {string} projectDir
161
+ * @param {DriverManifest} manifest
162
+ */
163
+ export function recordApproval(projectDir, manifest) {
164
+ const tofu = readTofuLock(projectDir);
165
+ const key = tofuKey(manifest.driverId, manifest.version);
166
+ tofu[key] = {
167
+ manifest_sha256: manifestSha256(manifest),
168
+ artifact_digest: manifest.trust?.integrity?.artifact_digest,
169
+ approved_at: new Date().toISOString(),
170
+ trust_tier: manifest.trust?.tier,
171
+ };
172
+ writeTofuLock(projectDir, tofu);
173
+ }
174
+ //# sourceMappingURL=trust.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust.mjs","sourceRoot":"","sources":["../../../src/cli/verify-proof/trust.mjs"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aperant",
3
- "version": "0.8.1",
3
+ "version": "0.8.4",
4
4
  "description": "AI coding framework — composable skills for planning, executing, verifying, and reviewing code with any LLM provider. Works as Claude Code commands, Codex tasks, or programmatically.",
5
5
  "author": {
6
6
  "name": "Mikalsen AI",
@@ -25,6 +25,7 @@
25
25
  "skills/apt",
26
26
  "skills/apt-author-skill",
27
27
  "skills/apt-bootstrap",
28
+ "skills/apt-caveman",
28
29
  "skills/apt-classify",
29
30
  "skills/apt-close-task",
30
31
  "skills/apt-create-docs",
@@ -35,6 +36,7 @@
35
36
  "skills/apt-docs",
36
37
  "skills/apt-execute",
37
38
  "skills/apt-fan-out",
39
+ "skills/apt-handoff",
38
40
  "skills/apt-improve",
39
41
  "skills/apt-mockup",
40
42
  "skills/apt-pause",
@@ -32,7 +32,8 @@ Before planning, discover project context:
32
32
  <environment>
33
33
  - **Working directory:** The project root
34
34
  - **apt-tools:** Always invoke as `node packages/framework/bin/apt-tools.mjs`
35
- - **Task directory:** Provided in the spawn prompt as `task_dir`. ALL artifacts (spec.md, implementation_plan.json) are written here, NOT to project root.
35
+ - **Task directory:** Provided in the spawn prompt as `task_dir`. It MUST be an absolute path under the main repo's `.aperant/tasks/{task-id}/`. ALL artifacts (spec.md, implementation_plan.json) are written here, NOT to project root and NOT to a worktree-local `.aperant/tasks/` directory.
36
+ - **Worktree path:** If provided, use it only for code investigation/editing context. Do not derive artifact paths from it.
36
37
  - **Config:** `.aperant/config.json` — project preferences
37
38
  - **State:** `.aperant/state.json` — execution state
38
39
  </environment>
@@ -43,7 +44,7 @@ Before planning, discover project context:
43
44
 
44
45
  1. Read `CLAUDE.md` and `AGENTS.md` if they exist — extract conventions, stack, constraints
45
46
  2. Run `node packages/framework/bin/apt-tools.mjs state .` to understand current project state
46
- 3. Parse the task description and task_dir from the spawn prompt
47
+ 3. Parse the task description and task_dir from the spawn prompt. If task_dir is relative, resolve the real main repo path first instead of writing under the current worktree.
47
48
 
48
49
  ## 2. Assess Complexity
49
50
 
@@ -211,7 +212,7 @@ If unable to enumerate (network unavailable, action docs unclear), flag it expli
211
212
 
212
213
  ## 4. Write Specification
213
214
 
214
- The spec.md content format **branches on track** (Pocock adoption ID-05,
215
+ The spec.md content format **branches on track** (ID-05,
215
216
  Fast Path Guarantee). QUICK-routed tasks keep the existing 4-section
216
217
  shape; STANDARD/DEEP/COMPLEX tasks get a PRD-shaped artifact that
217
218
  survives the task as a second-consumer document.
@@ -344,7 +345,7 @@ fix it now, not later.
344
345
 
345
346
  ## 5. Create Implementation Plan
346
347
 
347
- Subtask schema branches on track (Pocock adoption ID-05 — Fast Path Guarantee).
348
+ Subtask schema branches on track.
348
349
 
349
350
  ### 5.A. QUICK track / SIMPLE complexity — legacy flat subtask schema
350
351
 
@@ -386,18 +386,27 @@ Parse `task_id`, `task_dir`, and (if present) `worktree.worktree_path` / `worktr
386
386
  Important nuances:
387
387
  - `task_dir` is an **absolute path** under the main repo's `.aperant/tasks/{task-id}/`. All spec/plan/progress artifacts live there and are shared across worktrees.
388
388
  - `apt-tools` commands still receive the **project root** as `<project-dir>` — they coordinate state through the main repo's `.aperant/`. The worktree only affects *code editing* cwd.
389
- - When spawning an agent, set its `cwd` (or prefix its Bash calls with `cd {worktree_path} &&`) to the worktree. Pass `worktree_path` in the agent's context so it knows where it is.
389
+ - When spawning an agent, set its `cwd` (or prefix its Bash calls with `cd {worktree_path} &&`) to the worktree for code reads/edits. Pass `worktree_path` in the agent's context so it knows where code work happens.
390
+ - Planner artifact safety: do **not** spawn `apt-planner` with host-level worktree isolation that gives it a separate copied repo. The planner must write `spec.md` and `implementation_plan.json` to the absolute main-repo `task_dir` from `task create`; `.aperant/tasks/**` is gitignored, so artifacts written under a disposable worktree can be invisible to git and lost when that worktree is cleaned.
390
391
  - If no `worktree` block is returned, proceed in the project root as before.
391
392
 
392
393
  ### Step 3: Spawn Planner Agent
393
394
 
394
395
  **If `spawn_agent` is true (STANDARD/DEEP):**
395
396
 
396
- Print phase marker BEFORE spawning:
397
+ Print the phase rail BEFORE spawning. Render the panel verbatim — branch glyphs `┌─ │ └─`, status glyphs `✓` (done) / `●` (active) / `○` (pending), one phase per row, inline metrics on completed rows when available:
398
+
397
399
  ```
398
400
  [APT] Phase 1/N — Planning (spawning apt-planner agent)
401
+ ┌─ Phase rail: {short task name} ───────────────────
402
+ │ Phase 1 Plan ● spawning apt-planner
403
+ │ Phase 2 Execute ○
404
+ │ Phase 3 Verify ○
405
+ │ Phase 4 Review ○
406
+ └───────────────────────────────────────────────────
399
407
  ```
400
- (N = total pipeline phases: e.g. plan+execute+verify+review = 4, discuss+plan+… = 5)
408
+
409
+ (N = total pipeline phases: e.g. plan+execute+verify+review = 4, discuss+plan+… = 5. Keep the `[APT] Phase X/N` header line — it's the backward-compat marker that external grep tooling relies on. The rail panel sits directly below it.)
401
410
 
402
411
  You **MUST** use the `Task` tool to spawn `apt-planner` — do NOT write
403
412
  `spec.md` or `implementation_plan.json` inline using the `Write` tool. The
@@ -414,8 +423,9 @@ Spawn `apt-planner` via Task tool with context:
414
423
  ```
415
424
  Task: {task_description}
416
425
  Task ID: {task_id}
417
- Task Dir: {task_dir}
426
+ Task Dir: {task_dir} # absolute path under the main repo, not under worktree_path
418
427
  Track: {track}
428
+ Worktree Path: {worktree_path or "none"}
419
429
 
420
430
  <files_to_read>
421
431
  - CLAUDE.md (if exists)
@@ -423,7 +433,7 @@ Track: {track}
423
433
  - Any brainstorm notes at .aperant/context/notes/{task_id}-brainstorm.md
424
434
  </files_to_read>
425
435
 
426
- Write spec.md and implementation_plan.json to {task_dir}/
436
+ Write spec.md and implementation_plan.json to {task_dir}/. Do not write plan artifacts to `{worktree_path}/.aperant/tasks/...` or any relative `.aperant/tasks/...` path.
427
437
  ```
428
438
 
429
439
  After the agent returns, emit a token running-total line:
@@ -445,9 +455,32 @@ The user's chosen option has a `pipeline` array (e.g. `["plan", "execute", "veri
445
455
  **execution_mode = "auto":**
446
456
  Auto-chain without waiting. STANDARD and DEEP auto pipelines both follow Plan → execute → verify → review (DEEP additionally leads with discuss).
447
457
 
448
- Each phase transition MUST emit a status marker for visibility:
458
+ Each phase transition MUST emit a status marker AND re-render the phase rail showing the updated state for ALL phases. The rail is the user's primary signal — render it verbatim, do not summarize or skip.
459
+
449
460
  ```
450
461
  [APT] Phase {current}/{total} — {name} (spawning {agent})
462
+ ┌─ Phase rail: {short task name} ───────────────────
463
+ │ Phase 1 Plan ✓ {N} subtasks
464
+ │ Phase 2 Execute ● spawning apt-executor
465
+ │ Phase 3 Verify ○
466
+ │ Phase 4 Review ○
467
+ └───────────────────────────────────────────────────
468
+ ```
469
+
470
+ Metric conventions per phase row (omit metrics on `○` pending rows):
471
+ - **Plan ✓**: `N subtasks`
472
+ - **Execute ✓**: `N commits, K tests` (or `N/M subtasks` mid-execute on `●`)
473
+ - **Verify ✓**: `APPROVED a/b/c/d` (completeness/correctness/quality/coverage)
474
+ - **Review ✓**: `APPROVE a/b/c/d/e/f, K findings fixed` (or `request-changes, K open`)
475
+ - **Ship ✓**: `PR #N` (the SHIPPED collapsed variant — see below)
476
+
477
+ When ship completes (lifecycle `shipped-pending-merge` + PR URL exists), collapse to the SHIPPED variant:
478
+
479
+ ```
480
+ ┌─ {short task name} ────────────────────── ✅ SHIPPED
481
+ │ Plan ✓ Execute ✓ Verify ✓ Review ✓ Ship ✓
482
+ │ PR #{N}: {url}
483
+ └───────────────────────────────────────────────────
451
484
  ```
452
485
 
453
486
  Full auto-chain sequence (STANDARD = 4 phases, DEEP = 5 phases):
@@ -460,6 +493,42 @@ Full auto-chain sequence (STANDARD = 4 phases, DEEP = 5 phases):
460
493
  After EACH agent returns, emit the token running-total line (same pattern
461
494
  as Step 3: `tokens tally` then print `[APT] Tokens: input+output = total`).
462
495
 
496
+ #### Consent-driven --spar-gates auto-inject (FRAMEWORK-RFC-001)
497
+
498
+ The route envelope carries the consent signal deterministically — do NOT
499
+ re-read `.aperant/config.local.json` from prompt-space. Two envelope fields
500
+ drive the decision, both emitted by `route.mjs` per spec §4.10:
501
+
502
+ 1. **`envelope.spar_inject_gates`** — present only on the flag-override path
503
+ (explicit `--quick` / `--deep` / `--debug`) when consent is on AND the
504
+ user did NOT pass an explicit `--spar-gates`. Value is `"plan"` (STANDARD)
505
+ or `"plan,execute"` (DEEP). When set, append `--spar-gates <value>` to
506
+ the chained `/apt:run` invocation. **Do NOT recompute** — the deterministic
507
+ contract lives in code, not prompt-space.
508
+
509
+ 2. **`envelope.spar_consent`** — present on the host-LLM classify path.
510
+ Shape: `{ enabled: boolean, partner: string|null, user_passed_explicit_gates: boolean }`.
511
+ After you (the host model) pick a track via Step 0c:
512
+ - **Track === QUICK or DEBUG: do NOT inject.** QUICK is Fast-Path-exempt
513
+ (CLAUDE.md Fast Path Guarantee); DEBUG produces no spec/plan to spar
514
+ against.
515
+ - **Track === STANDARD** AND `spar_consent.enabled === true` AND
516
+ `spar_consent.user_passed_explicit_gates === false`: append
517
+ `--spar-gates plan` to the `/apt:run` invocation.
518
+ - **Track === DEEP** AND `spar_consent.enabled === true` AND
519
+ `spar_consent.user_passed_explicit_gates === false`: append
520
+ `--spar-gates plan,execute` to the `/apt:run` invocation.
521
+ - `user_passed_explicit_gates === true`: the user already supplied
522
+ `--spar-gates` — do NOT double-inject. Their flag is already in the
523
+ dispatched invocation.
524
+
525
+ If `envelope.spar_consent` is absent (consent never configured) AND
526
+ `envelope.spar_inject_gates` is absent, do NOT inject. The signal is
527
+ **deterministic** — Step 4 reads ONLY the envelope fields above. Do NOT
528
+ re-read `.aperant/config.local.json` from prompt-space; the
529
+ consent-resolution helper is wired into `route.mjs` and the envelope is
530
+ the canonical contract. The structural test grep-locks this invariant.
531
+
463
532
  **execution_mode = "step" or "research":**
464
533
  After each stage in the pipeline, show result and ask before proceeding:
465
534
  ```
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: apt:caveman
3
+ description: "Ultra-compressed communication mode — toggle terse 'smart caveman' output to cut token usage ~75% while keeping full technical accuracy"
4
+ apt-skill-version: {{APT_VERSION}}
5
+ stage: ops
6
+ intent: configure
7
+ when_to_use: "The user invokes /apt:caveman, or says 'caveman mode', 'talk like caveman', 'be brief', 'less tokens'. Toggles a persistent terse output mode. Off with 'stop caveman' or 'normal mode'."
8
+ user_invocable: true
9
+ internal: false
10
+ spawns_agent: false
11
+ agent_name: null
12
+ task_context: none
13
+ default_execution_mode: auto
14
+ execution_modes:
15
+ - auto
16
+ allowed-tools: ""
17
+ argument-hint: "apt:caveman"
18
+ gates: []
19
+ ---
20
+
21
+ Respond terse like smart caveman. All technical substance stay. Only fluff die.
22
+
23
+ ## Persistence
24
+
25
+ ACTIVE EVERY RESPONSE once triggered. No revert after many turns. No filler drift. Still active if unsure. Off only when user says "stop caveman" or "normal mode".
26
+
27
+ ## Rules
28
+
29
+ Drop: articles (a/an/the), filler (just/really/basically/actually/simply), pleasantries (sure/certainly/of course/happy to), hedging. Fragments OK. Short synonyms (big not extensive, fix not "implement a solution for"). Abbreviate common terms (DB/auth/config/req/res/fn/impl). Strip conjunctions. Use arrows for causality (X -> Y). One word when one word enough.
30
+
31
+ Technical terms stay exact. Code blocks unchanged. Errors quoted exact.
32
+
33
+ Pattern: `[thing] [action] [reason]. [next step].`
34
+
35
+ Not: "Sure! I'd be happy to help you with that. The issue you're experiencing is likely caused by..."
36
+ Yes: "Bug in auth middleware. Token expiry check use `<` not `<=`. Fix:"
37
+
38
+ ### Examples
39
+
40
+ **"Why React component re-render?"**
41
+
42
+ > Inline obj prop -> new ref -> re-render. `useMemo`.
43
+
44
+ **"Explain database connection pooling."**
45
+
46
+ > Pool = reuse DB conn. Skip handshake -> fast under load.
47
+
48
+ ## Auto-Clarity Exception
49
+
50
+ Drop caveman temporarily for: security warnings, irreversible action confirmations, multi-step sequences where fragment order risks misread, user asks to clarify or repeats question. Resume caveman after clear part done.
51
+
52
+ Example — destructive op:
53
+
54
+ > **Warning:** This will permanently delete all rows in the `users` table and cannot be undone.
55
+ >
56
+ > ```sql
57
+ > DROP TABLE users;
58
+ > ```
59
+ >
60
+ > Caveman resume. Verify backup exist first.
61
+
62
+ ## Boundaries
63
+
64
+ Code, commits, PRs: write normal (full sentences in commit bodies / PR descriptions). Only conversational output is compressed. `stop caveman` / `normal mode` reverts.
@@ -22,7 +22,7 @@ gates: []
22
22
  <objective>
23
23
  Debug an issue using the scientific method: observe symptoms, form hypotheses, test them systematically, and reach a conclusion. State persists across context resets via `.aperant/debug/{session-id}/DEBUG.md`.
24
24
 
25
- **Diagnose-discipline posture loader (Pocock adoption AC10).** You MUST
25
+ **Diagnose-discipline posture loader.** You MUST
26
26
  load `appendices/diagnose-discipline.md` into reasoning context at
27
27
  session start. It carries the 6-phase loop (Reproduce → Minimise →
28
28
  Hypothesise → Instrument → Fix → Regression-test) and the **Phase-1
@@ -61,12 +61,44 @@ reproduction, so loading this appendix is non-trivial.
61
61
  ## 1. Initialize or Resume Session
62
62
 
63
63
  Parse `$ARGUMENTS`:
64
- - **New session:** Generate session ID from timestamp (`debug-YYYYMMDD-HHmm`)
65
- - **`--resume <session-id>`:** Read existing `.aperant/debug/{session-id}/DEBUG.md` and continue from last state
66
- - **`--resume` (no id):** Find the most recent session in `.aperant/debug/` and resume it
64
+ - **New session:** resolve a canonical task id (see 1a below), then use it as the `{session-id}` for the debug working directory.
65
+ - **`--resume <session-id>`:** Read existing `.aperant/debug/{session-id}/DEBUG.md` and continue from last state. Skip Section 1a — the session id is already canonical.
66
+ - **`--resume` (no id):** Find the most recent session in `.aperant/debug/` and resume it. Skip Section 1a.
67
67
 
68
68
  If resuming, read DEBUG.md and skip to the current phase (observe/hypothesize/test/conclude).
69
69
 
70
+ ### 1a. Resolve canonical task id (idempotent — new sessions only)
71
+
72
+ DEBUG now produces a canonical state.active_tasks record so `/apt:ship` can find the task via the lite ship profile once the fix is committed. The body owns idempotency because `apt-tools task create` does NOT guard against existing ids (see spec §3 R8).
73
+
74
+ Two invocation paths converge here:
75
+
76
+ - **Router path** (`/apt` → `/apt:debug`): the router has already called `task create` and injected `task_id` into your skill context.
77
+ - **Direct path** (`/apt:debug foo`): no `task_id` in context — you create one now.
78
+
79
+ Sequence:
80
+
81
+ 1. **If `task_id` is present in skill context** (router path):
82
+ ```bash
83
+ apt-tools task get . --id {task_id}
84
+ ```
85
+ - If exit 0 AND the returned record has `track === "DEBUG"` → reuse, skip the create call. Adopt `task_id` as `{session-id}`.
86
+ - Else (record missing OR wrong track) → call:
87
+ ```bash
88
+ apt-tools task create . --description "$ARGUMENTS" --track DEBUG --id {task_id}
89
+ ```
90
+ Adopt the id as `{session-id}`.
91
+
92
+ 2. **If no `task_id` in skill context** (direct path):
93
+ ```bash
94
+ apt-tools task create . --description "$ARGUMENTS" --track DEBUG
95
+ ```
96
+ Parse the generated `task_id` from the envelope and adopt it as `{session-id}`. The canonical id replaces the legacy `debug-YYYYMMDD-HHmm` form.
97
+
98
+ The debug working dir at `.aperant/debug/{session-id}/` stays — that working artifact is preserved (per spec §3 R7). The canonical task record at `.aperant/tasks/{task-id}/` is created in parallel by `task create`, and both share the same id.
99
+
100
+ ### 1b. Create debug working directory
101
+
70
102
  ```bash
71
103
  mkdir -p .aperant/debug/{session-id}
72
104
  mkdir -p .aperant/debug/{session-id}/checkpoints
@@ -1,12 +1,3 @@
1
- <!--
2
- Adapted from Matt Pocock's MIT-licensed skill suite:
3
- https://github.com/mattpocock/skills/blob/main/skills/engineering/diagnose
4
- Licensed under MIT. Modifications: ported as an apt:debug posture loader
5
- so the 6-phase loop attaches to the existing 5-phase apt:debug body
6
- without forking apt:debug's control flow. Aligned with apt:debug's
7
- DEBUG.md state file and checkpoint conventions.
8
- -->
9
-
10
1
  # Diagnose Discipline — apt:debug posture loader (6-phase loop)
11
2
 
12
3
  This appendix loads into `apt:debug`'s reasoning context as a posture
@@ -15,7 +6,7 @@ upgrade. The existing apt:debug body has 5 phases (Observe → Hypothesize
15
6
  symptom-gathering with reproduction. Open question #1 was verified — the
16
7
  gap is real, the appendix is non-trivial.
17
8
 
18
- This appendix carries the 6-phase Pocock discipline. The skill body
9
+ This appendix carries the 6-phase Aperant discipline. The skill body
19
10
  loads it and uses Phase 1 (Reproduce) as a **hard prerequisite** before
20
11
  advancing from Observe to Hypothesize.
21
12
 
@@ -82,7 +73,7 @@ run on demand to trigger the failure.
82
73
 
83
74
  These are different mental modes. Minimise asks "what's the smallest
84
75
  thing that still fails?" — a reductive activity. Hypothesise asks
85
- "WHY does it fail?" — an explanatory activity. Pocock's discipline
76
+ "WHY does it fail?" — an explanatory activity. the discipline
86
77
  separates them because skipping Phase 2 and going straight from "I can
87
78
  repro" to "here's why" tends to anchor on the first plausible cause
88
79
  and miss alternatives.
@@ -47,7 +47,7 @@ These are two postures of the same skill, not two different skills. The
47
47
  intent-detection step below decides which one to enter — same file, same
48
48
  artifact layout, different section populated.
49
49
 
50
- **Decision-lock posture loader (Pocock adoption ID-02 + ID-04 — AC11).**
50
+ **Decision-lock posture loader (ID-02 + ID-04 — AC11).**
51
51
  When entering decision-lock posture, you MUST load
52
52
  `appendices/grill-discipline.md` into reasoning context. It carries the
53
53
  validated 100-token reframe sentence ("Your job is not to emit a plan;
@@ -60,7 +60,7 @@ source for the autonomy-aware rule; downstream skills (`apt:improve`,
60
60
  `apt:triage`) reference it rather than re-stating the policy. Brainstorm
61
61
  posture does NOT load this appendix.
62
62
 
63
- **Brainstorm posture zoom-out helper (Pocock adoption AC6 + AC11).**
63
+ **Brainstorm posture zoom-out helper (AC6 + AC11).**
64
64
  When in brainstorm posture and the user's turn contains a zoom-out
65
65
  trigger phrase ("give me a broader picture", "I'm lost in this area",
66
66
  "explain how this fits", "what's the surrounding architecture", "zoom
@@ -565,9 +565,9 @@ Review-Auto is Auto Mode **plus one human checkpoint at the batch end**. It does
565
565
 
566
566
  Do NOT introduce per-decision staging ("show me D-01, wait, show me D-02, wait...") — that collapses review-auto into spaced interactive mode and defeats the point of joint reasoning up front. Do NOT skip the pause ("autonomy is high, let's just write it") — that collapses review-auto into auto. The one pause at the end is the whole identity of this mode.
567
567
 
568
- ## 6.5. Grill Mode (`--grill` flag — Pocock `grill-with-docs` overlay)
568
+ ## 6.5. Grill Mode (`--grill` flag — Aperant `grill-with-docs` overlay)
569
569
 
570
- **Activate when:** the user invoked the skill with `--grill`. This is an **overlay**, not a mode — it stacks on top of whichever Section 6 mode is active (Interactive by default; combine with `--auto` etc. as desired). The overlay does two things: (1) it applies Pocock's 4 grill moves during decision resolution; (2) it fires inline writes to CONTEXT.md and ADRs as terms resolve and decisions pass the Nygard 3-gate.
570
+ **Activate when:** the user invoked the skill with `--grill`. This is an **overlay**, not a mode — it stacks on top of whichever Section 6 mode is active (Interactive by default; combine with `--auto` etc. as desired). The overlay does two things: (1) it applies the 4 grill moves during decision resolution; (2) it fires inline writes to CONTEXT.md and ADRs as terms resolve and decisions pass the Nygard 3-gate.
571
571
 
572
572
  The discipline this overlay loads is already in [`appendices/grill-discipline.md`](./appendices/grill-discipline.md) — re-read the reframe sentence and the autonomy degradation table before each grill turn. **Do NOT duplicate that content here.** What follows is only the moves + writer-call instructions specific to the overlay.
573
573