@hassangameryt/freeflow 0.2.0 → 0.4.0

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 (312) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.claude-plugin/marketplace.json +4 -4
  3. package/{plugins/freeflow/.claude-plugin → .claude-plugin}/plugin.json +5 -2
  4. package/{plugins/freeflow/.codex-plugin → .codex-plugin}/plugin.json +8 -9
  5. package/README.md +194 -127
  6. package/assets/feedback-loop.png +0 -0
  7. package/assets/freeflow-plugin-icon.png +0 -0
  8. package/assets/freeflow_workflow_map.png +0 -0
  9. package/assets/workflow.png +0 -0
  10. package/command-surface.json +129 -0
  11. package/hooks/freeflow-runtime-context.mjs +419 -0
  12. package/hooks/tests/check-runtime-context-hook.sh +223 -0
  13. package/package.json +41 -22
  14. package/pi-extension/dist/index.js +269 -0
  15. package/pi-extension/dist/integrations/mcp-config.js +29 -0
  16. package/pi-extension/dist/output-router/host-producer-identification.js +232 -0
  17. package/pi-extension/dist/output-router/native-safety-net.js +216 -0
  18. package/pi-extension/dist/output-router/observed-tool-routing.js +122 -0
  19. package/pi-extension/dist/output-router/renderers.js +1023 -0
  20. package/pi-extension/dist/output-router/router-tools.js +554 -0
  21. package/pi-extension/dist/output-router/schemas.js +383 -0
  22. package/pi-extension/dist/output-router/status.js +744 -0
  23. package/pi-extension/dist/output-router/utils.js +502 -0
  24. package/pi-extension/dist/runtime/runtime-context.js +798 -0
  25. package/pi-extension/dist/settings/settings-tui.js +314 -0
  26. package/pi-extension/dist/settings/settings-ui.js +1487 -0
  27. package/pi-extension/freeflow/index.js +1 -0
  28. package/pi-extension/src/index.ts +295 -0
  29. package/pi-extension/src/integrations/mcp-config.ts +32 -0
  30. package/pi-extension/src/output-router/host-producer-identification.ts +256 -0
  31. package/pi-extension/src/output-router/native-safety-net.ts +248 -0
  32. package/pi-extension/src/output-router/observed-tool-routing.ts +134 -0
  33. package/pi-extension/src/output-router/renderers.ts +1108 -0
  34. package/pi-extension/src/output-router/router-tools.ts +579 -0
  35. package/pi-extension/src/output-router/schemas.ts +387 -0
  36. package/pi-extension/src/output-router/status.ts +791 -0
  37. package/pi-extension/src/output-router/utils.ts +554 -0
  38. package/pi-extension/src/runtime/runtime-context.ts +895 -0
  39. package/pi-extension/src/settings/settings-tui.ts +408 -0
  40. package/pi-extension/src/settings/settings-ui.ts +1730 -0
  41. package/pi-extension/tests/integration/pi-extension.test.js +4018 -0
  42. package/pi-extension/tests/output-router/observed-producers.test.js +132 -0
  43. package/pi-extension/tests/output-router/search.test.js +722 -0
  44. package/pi-extension/tests/settings/settings-tui.test.js +243 -0
  45. package/pi-extension/tsconfig.json +16 -0
  46. package/{plugins/freeflow/router/dist → router/dist/benchmarks}/benchmark-harness.d.ts +16 -13
  47. package/router/dist/benchmarks/benchmark-harness.js +92 -0
  48. package/router/dist/benchmarks/benchmarks.d.ts +109 -0
  49. package/router/dist/benchmarks/benchmarks.js +979 -0
  50. package/router/dist/benchmarks/codex-qa-benchmarks.d.ts +95 -0
  51. package/router/dist/benchmarks/codex-qa-benchmarks.js +500 -0
  52. package/router/dist/benchmarks/command-benchmarks.d.ts +143 -0
  53. package/router/dist/benchmarks/command-benchmarks.js +698 -0
  54. package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +82 -0
  55. package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +773 -0
  56. package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +132 -0
  57. package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +1380 -0
  58. package/router/dist/benchmarks/context-saving-baseline.d.ts +60 -0
  59. package/router/dist/benchmarks/context-saving-baseline.js +470 -0
  60. package/router/dist/benchmarks/index-benchmarks.d.ts +103 -0
  61. package/router/dist/benchmarks/index-benchmarks.js +862 -0
  62. package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +101 -0
  63. package/router/dist/benchmarks/storage-policy-benchmarks.js +618 -0
  64. package/router/dist/benchmarks/vault-index-benchmarks.d.ts +56 -0
  65. package/router/dist/benchmarks/vault-index-benchmarks.js +322 -0
  66. package/router/dist/config/config.d.ts +103 -0
  67. package/router/dist/config/config.js +632 -0
  68. package/{plugins/freeflow/router/dist → router/dist/config}/router-contract.d.ts +2 -2
  69. package/router/dist/config/router-contract.js +54 -0
  70. package/{plugins/freeflow/router/dist → router/dist/config}/schema.d.ts +19 -10
  71. package/router/dist/config/schema.js +648 -0
  72. package/router/dist/config/types.d.ts +573 -0
  73. package/router/dist/config/types.js +41 -0
  74. package/router/dist/evidence/bounded-evidence.d.ts +40 -0
  75. package/router/dist/evidence/bounded-evidence.js +323 -0
  76. package/router/dist/evidence/evidence-range-selector.d.ts +24 -0
  77. package/router/dist/evidence/evidence-range-selector.js +232 -0
  78. package/router/dist/evidence/evidence-search.d.ts +27 -0
  79. package/router/dist/evidence/evidence-search.js +490 -0
  80. package/{plugins/freeflow/router/dist → router/dist/evidence}/evidence.d.ts +18 -18
  81. package/router/dist/evidence/evidence.js +200 -0
  82. package/router/dist/evidence/failure-contracts.d.ts +37 -0
  83. package/router/dist/evidence/failure-contracts.js +166 -0
  84. package/router/dist/evidence/line-ranges.d.ts +24 -0
  85. package/router/dist/evidence/line-ranges.js +22 -0
  86. package/router/dist/experiments/local-index.d.ts +64 -0
  87. package/router/dist/experiments/local-index.js +581 -0
  88. package/router/dist/index.d.ts +30 -0
  89. package/router/dist/index.js +32 -0
  90. package/router/dist/local/local-traversal.d.ts +18 -0
  91. package/router/dist/local/local-traversal.js +334 -0
  92. package/router/dist/processing/engine.d.ts +132 -0
  93. package/router/dist/processing/engine.js +533 -0
  94. package/router/dist/processing/reducers.d.ts +280 -0
  95. package/router/dist/processing/reducers.js +1673 -0
  96. package/router/dist/processing/renderers.d.ts +31 -0
  97. package/router/dist/processing/renderers.js +195 -0
  98. package/router/dist/processing/scripts.d.ts +91 -0
  99. package/router/dist/processing/scripts.js +386 -0
  100. package/{plugins/freeflow/router/dist → router/dist/repo}/repo-traversal.d.ts +9 -9
  101. package/router/dist/repo/repo-traversal.js +245 -0
  102. package/router/dist/routing/observed-reducers.d.ts +41 -0
  103. package/router/dist/routing/observed-reducers.js +661 -0
  104. package/router/dist/routing/observed-routing.d.ts +26 -0
  105. package/router/dist/routing/observed-routing.js +378 -0
  106. package/router/dist/routing/parsers.d.ts +16 -0
  107. package/router/dist/routing/parsers.js +521 -0
  108. package/router/dist/routing/run-filters.d.ts +60 -0
  109. package/router/dist/routing/run-filters.js +238 -0
  110. package/router/dist/routing/run-reducers.d.ts +49 -0
  111. package/router/dist/routing/run-reducers.js +122 -0
  112. package/router/dist/sandbox/adapter-roots.d.ts +46 -0
  113. package/router/dist/sandbox/adapter-roots.js +66 -0
  114. package/router/dist/sandbox/eryx-python-adapter.d.ts +13 -0
  115. package/router/dist/sandbox/eryx-python-adapter.js +868 -0
  116. package/router/dist/sandbox/jq-wasm-adapter.d.ts +9 -0
  117. package/router/dist/sandbox/jq-wasm-adapter.js +429 -0
  118. package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +13 -0
  119. package/router/dist/sandbox/quickjs-wasi-adapter.js +384 -0
  120. package/router/dist/sandbox/script-sandbox.d.ts +134 -0
  121. package/router/dist/sandbox/script-sandbox.js +337 -0
  122. package/router/dist/setup/script-transform-adapters.d.ts +32 -0
  123. package/router/dist/setup/script-transform-adapters.js +278 -0
  124. package/router/dist/tools/batch.d.ts +33 -0
  125. package/router/dist/tools/batch.js +586 -0
  126. package/router/dist/tools/run.d.ts +62 -0
  127. package/router/dist/tools/run.js +1304 -0
  128. package/router/dist/tools/search.d.ts +66 -0
  129. package/router/dist/tools/search.js +1364 -0
  130. package/router/dist/transform/engine.d.ts +168 -0
  131. package/router/dist/transform/engine.js +2072 -0
  132. package/router/dist/vault/vault-index.d.ts +125 -0
  133. package/router/dist/vault/vault-index.js +416 -0
  134. package/router/dist/vault/vault.d.ts +138 -0
  135. package/router/dist/vault/vault.js +630 -0
  136. package/runtime/interaction-contract.md +16 -0
  137. package/skills/bypass/SKILL.md +82 -0
  138. package/skills/commit-work/SKILL.md +106 -0
  139. package/skills/commit-work/references/staging-decisions.md +73 -0
  140. package/skills/decision-gate/SKILL.md +48 -0
  141. package/skills/design-for-depth/SKILL.md +106 -0
  142. package/skills/design-for-depth/references/design-pressure-signals.md +314 -0
  143. package/skills/design-for-depth/references/interface-design-loop.md +156 -0
  144. package/skills/design-for-depth/references/software-design-philosophy.md +248 -0
  145. package/skills/diagnose-failure/SKILL.md +105 -0
  146. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +36 -0
  147. package/skills/diagnose-failure/references/flaky-and-performance.md +43 -0
  148. package/skills/discuss/SKILL.md +121 -0
  149. package/skills/discuss/references/checkpoints.md +66 -0
  150. package/skills/evaluate-skill/SKILL.md +105 -0
  151. package/skills/evaluate-skill/references/definition-schema.md +345 -0
  152. package/skills/evaluate-skill/references/evaluation-design.md +86 -0
  153. package/skills/evaluate-skill/references/execution-and-evidence.md +85 -0
  154. package/skills/evaluate-skill/references/review-and-revision.md +51 -0
  155. package/skills/evaluate-skill/scripts/lib/definitions.mjs +296 -0
  156. package/skills/evaluate-skill/scripts/lib/evidence.mjs +46 -0
  157. package/skills/evaluate-skill/scripts/lib/grade-comparison.mjs +60 -0
  158. package/skills/evaluate-skill/scripts/lib/grade-interaction.mjs +148 -0
  159. package/skills/evaluate-skill/scripts/lib/grade-support.mjs +126 -0
  160. package/skills/evaluate-skill/scripts/lib/grade-workspace.mjs +192 -0
  161. package/skills/evaluate-skill/scripts/lib/grade.mjs +56 -0
  162. package/skills/evaluate-skill/scripts/lib/pi.mjs +489 -0
  163. package/skills/evaluate-skill/scripts/lib/process.mjs +79 -0
  164. package/skills/evaluate-skill/scripts/lib/rpc.mjs +444 -0
  165. package/skills/evaluate-skill/scripts/lib/runner.mjs +346 -0
  166. package/skills/evaluate-skill/scripts/lib/sandbox.mjs +409 -0
  167. package/skills/evaluate-skill/scripts/lib/view.mjs +337 -0
  168. package/skills/evaluate-skill/scripts/pi-guard.mjs +164 -0
  169. package/skills/evaluate-skill/scripts/skill-eval.mjs +101 -0
  170. package/skills/execute-work/SKILL.md +99 -0
  171. package/skills/execute-work/references/code-practices.md +78 -0
  172. package/skills/execute-work/references/execution-loop.md +77 -0
  173. package/skills/finish-branch/SKILL.md +117 -0
  174. package/skills/finish-branch/references/integration-options.md +80 -0
  175. package/skills/handoff/SKILL.md +92 -0
  176. package/skills/handoff/references/templates.md +141 -0
  177. package/skills/launch-work/SKILL.md +116 -0
  178. package/skills/launch-work/references/launch-readiness.md +85 -0
  179. package/skills/migration-work/SKILL.md +115 -0
  180. package/skills/migration-work/references/migration-lifecycle.md +82 -0
  181. package/skills/mode-contract/SKILL.md +82 -0
  182. package/skills/output-router/SKILL.md +206 -0
  183. package/skills/output-router/references/safety-policy.md +40 -0
  184. package/skills/release-work/SKILL.md +118 -0
  185. package/skills/release-work/references/release-evidence.md +78 -0
  186. package/skills/review-artifact/SKILL.md +126 -0
  187. package/skills/review-artifact/references/reviewer-prompt.md +148 -0
  188. package/skills/review-work/SKILL.md +126 -0
  189. package/skills/review-work/references/reviewer-prompt.md +134 -0
  190. package/skills/review-work/references/security-risk-lens.md +67 -0
  191. package/skills/setup-freeflow/SKILL.md +98 -0
  192. package/skills/setup-freeflow/references/activation-contract.md +120 -0
  193. package/skills/setup-freeflow/references/host-setup.md +72 -0
  194. package/skills/setup-freeflow/references/output-router-setup.md +110 -0
  195. package/skills/simplify-code/SKILL.md +80 -0
  196. package/skills/simplify-code/references/simplification-patterns.md +70 -0
  197. package/skills/tdd/SKILL.md +96 -0
  198. package/skills/tdd/references/test-design.md +96 -0
  199. package/skills/track-work/SKILL.md +84 -0
  200. package/skills/track-work/references/working-record-schema.md +378 -0
  201. package/skills/verify-work/SKILL.md +85 -0
  202. package/skills/verify-work/references/browser-runtime-evidence.md +55 -0
  203. package/skills/verify-work/references/integration-evidence.md +51 -0
  204. package/skills/verify-work/references/performance-evidence.md +57 -0
  205. package/skills/workflow/SKILL.md +91 -0
  206. package/skills/workflow/references/domain-skill-composition.md +57 -0
  207. package/skills/workflow/references/workflow-loop.md +92 -0
  208. package/skills/write-plan/SKILL.md +123 -0
  209. package/skills/write-plan/references/plan-shapes.md +156 -0
  210. package/skills/write-skill/SKILL.md +119 -0
  211. package/skills/write-skill/references/activation-boundaries.md +62 -0
  212. package/skills/write-skill/references/agent-first-instructions.md +87 -0
  213. package/skills/write-skill/references/progressive-disclosure.md +63 -0
  214. package/skills/write-skill/scripts/lib/skill-author.mjs +653 -0
  215. package/skills/write-skill/scripts/skill-author.mjs +104 -0
  216. package/skills/write-spec/SKILL.md +104 -0
  217. package/skills/write-spec/references/artifact-standards.md +86 -0
  218. package/skills/write-spec/references/decision-records.md +77 -0
  219. package/skills/write-spec/references/spec-shapes.md +128 -0
  220. package/plugins/freeflow/command-surface.json +0 -77
  221. package/plugins/freeflow/docs/README.md +0 -40
  222. package/plugins/freeflow/docs/adr/0001-three-modes.md +0 -27
  223. package/plugins/freeflow/docs/adr/0002-evals-before-hooks.md +0 -17
  224. package/plugins/freeflow/docs/adr/0003-release-boundary.md +0 -21
  225. package/plugins/freeflow/docs/adr/0004-research-replaces-shallow-discovery-skills.md +0 -26
  226. package/plugins/freeflow/docs/adr/README.md +0 -8
  227. package/plugins/freeflow/docs/architecture.md +0 -86
  228. package/plugins/freeflow/docs/output-router.md +0 -212
  229. package/plugins/freeflow/docs/release-evidence.md +0 -69
  230. package/plugins/freeflow/docs/skills.md +0 -43
  231. package/plugins/freeflow/docs/workflow.md +0 -57
  232. package/plugins/freeflow/hooks/freeflow-runtime-context.mjs +0 -257
  233. package/plugins/freeflow/pi-extension/index.js +0 -1176
  234. package/plugins/freeflow/router/dist/benchmark-harness.js +0 -92
  235. package/plugins/freeflow/router/dist/benchmarks.d.ts +0 -102
  236. package/plugins/freeflow/router/dist/benchmarks.js +0 -880
  237. package/plugins/freeflow/router/dist/bounded-evidence.d.ts +0 -40
  238. package/plugins/freeflow/router/dist/bounded-evidence.js +0 -310
  239. package/plugins/freeflow/router/dist/codex-qa-benchmarks.d.ts +0 -91
  240. package/plugins/freeflow/router/dist/codex-qa-benchmarks.js +0 -461
  241. package/plugins/freeflow/router/dist/command-benchmarks.d.ts +0 -128
  242. package/plugins/freeflow/router/dist/command-benchmarks.js +0 -652
  243. package/plugins/freeflow/router/dist/config.d.ts +0 -22
  244. package/plugins/freeflow/router/dist/config.js +0 -114
  245. package/plugins/freeflow/router/dist/evidence-range-selector.d.ts +0 -22
  246. package/plugins/freeflow/router/dist/evidence-range-selector.js +0 -180
  247. package/plugins/freeflow/router/dist/evidence-search.d.ts +0 -25
  248. package/plugins/freeflow/router/dist/evidence-search.js +0 -450
  249. package/plugins/freeflow/router/dist/evidence.js +0 -196
  250. package/plugins/freeflow/router/dist/experimental-local-index.d.ts +0 -1
  251. package/plugins/freeflow/router/dist/experimental-local-index.js +0 -1
  252. package/plugins/freeflow/router/dist/experiments/local-index.d.ts +0 -58
  253. package/plugins/freeflow/router/dist/experiments/local-index.js +0 -562
  254. package/plugins/freeflow/router/dist/index-benchmarks.d.ts +0 -84
  255. package/plugins/freeflow/router/dist/index-benchmarks.js +0 -458
  256. package/plugins/freeflow/router/dist/index.d.ts +0 -12
  257. package/plugins/freeflow/router/dist/index.js +0 -12
  258. package/plugins/freeflow/router/dist/line-ranges.d.ts +0 -22
  259. package/plugins/freeflow/router/dist/line-ranges.js +0 -22
  260. package/plugins/freeflow/router/dist/parsers.d.ts +0 -16
  261. package/plugins/freeflow/router/dist/parsers.js +0 -473
  262. package/plugins/freeflow/router/dist/repo-traversal.js +0 -242
  263. package/plugins/freeflow/router/dist/retrieve.d.ts +0 -33
  264. package/plugins/freeflow/router/dist/retrieve.js +0 -855
  265. package/plugins/freeflow/router/dist/router-contract.js +0 -54
  266. package/plugins/freeflow/router/dist/run.d.ts +0 -26
  267. package/plugins/freeflow/router/dist/run.js +0 -356
  268. package/plugins/freeflow/router/dist/schema.js +0 -354
  269. package/plugins/freeflow/router/dist/types.d.ts +0 -234
  270. package/plugins/freeflow/router/dist/types.js +0 -9
  271. package/plugins/freeflow/router/dist/vault.d.ts +0 -80
  272. package/plugins/freeflow/router/dist/vault.js +0 -484
  273. package/plugins/freeflow/skills/bypass/SKILL.md +0 -68
  274. package/plugins/freeflow/skills/commit-work/SKILL.md +0 -98
  275. package/plugins/freeflow/skills/commit-work/references/staging-decisions.md +0 -51
  276. package/plugins/freeflow/skills/diagnose-failure/SKILL.md +0 -95
  277. package/plugins/freeflow/skills/diagnose-failure/references/feedback-loop-catalog.md +0 -25
  278. package/plugins/freeflow/skills/diagnose-failure/references/flaky-and-performance.md +0 -31
  279. package/plugins/freeflow/skills/evaluate-skill/SKILL.md +0 -96
  280. package/plugins/freeflow/skills/evaluate-skill/references/eval-patterns.md +0 -41
  281. package/plugins/freeflow/skills/evaluate-skill/references/grading-priority.md +0 -33
  282. package/plugins/freeflow/skills/execute-plan/SKILL.md +0 -132
  283. package/plugins/freeflow/skills/execute-plan/references/execution-map.md +0 -122
  284. package/plugins/freeflow/skills/handoff/SKILL.md +0 -66
  285. package/plugins/freeflow/skills/handoff/references/templates.md +0 -64
  286. package/plugins/freeflow/skills/interview-gate/SKILL.md +0 -90
  287. package/plugins/freeflow/skills/mode-contract/SKILL.md +0 -79
  288. package/plugins/freeflow/skills/output-router/SKILL.md +0 -69
  289. package/plugins/freeflow/skills/output-router/references/safety-policy.md +0 -33
  290. package/plugins/freeflow/skills/research/ARTIFACT-DESTINATIONS.md +0 -58
  291. package/plugins/freeflow/skills/research/CHECKPOINTS.md +0 -74
  292. package/plugins/freeflow/skills/research/LANGUAGE.md +0 -61
  293. package/plugins/freeflow/skills/research/SKILL.md +0 -128
  294. package/plugins/freeflow/skills/review-artifact/SKILL.md +0 -115
  295. package/plugins/freeflow/skills/review-artifact/references/reviewer-prompt.md +0 -56
  296. package/plugins/freeflow/skills/review-work/SKILL.md +0 -96
  297. package/plugins/freeflow/skills/review-work/references/reviewer-prompt.md +0 -97
  298. package/plugins/freeflow/skills/setup-freeflow/SKILL.md +0 -94
  299. package/plugins/freeflow/skills/setup-freeflow/references/activation-contract.md +0 -99
  300. package/plugins/freeflow/skills/setup-freeflow/references/host-setup.md +0 -35
  301. package/plugins/freeflow/skills/setup-freeflow/references/output-router-setup.md +0 -52
  302. package/plugins/freeflow/skills/verify-work/SKILL.md +0 -62
  303. package/plugins/freeflow/skills/workflow/SKILL.md +0 -95
  304. package/plugins/freeflow/skills/workflow/references/workflow-map.md +0 -102
  305. package/plugins/freeflow/skills/write-plan/SKILL.md +0 -88
  306. package/plugins/freeflow/skills/write-plan/references/plan-shapes.md +0 -70
  307. package/plugins/freeflow/skills/write-skill/SKILL.md +0 -88
  308. package/plugins/freeflow/skills/write-spec/SKILL.md +0 -90
  309. package/plugins/freeflow/skills/write-spec/references/artifact-standards.md +0 -67
  310. package/plugins/freeflow/skills/write-spec/references/spec-shapes.md +0 -69
  311. /package/{plugins/freeflow/assets → assets}/freeflow-plugin-icon-transparent.png +0 -0
  312. /package/{plugins/freeflow/hooks → hooks}/hooks.json +0 -0
@@ -1,484 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { mkdir, open, readFile, rename, unlink, writeFile } from "node:fs/promises";
3
- import { homedir } from "node:os";
4
- import { dirname, join, resolve } from "node:path";
5
- import { DEFAULT_VAULT_RETENTION, DEFAULT_VAULT_ROOT } from "./config.js";
6
- const sessionIndexWriteLocks = new Map();
7
- const SESSION_INDEX_LOCK_RETRY_MS = 5;
8
- const SESSION_INDEX_LOCK_TIMEOUT_MS = 5_000;
9
- export function createVault(options = {}) {
10
- return {
11
- root: resolveVaultRoot(options.root ?? DEFAULT_VAULT_ROOT),
12
- retention: options.retention ?? DEFAULT_VAULT_RETENTION,
13
- };
14
- }
15
- export function resolveVaultRoot(root) {
16
- if (root === "~") {
17
- return homedir();
18
- }
19
- if (root.startsWith("~/")) {
20
- return join(homedir(), root.slice(2));
21
- }
22
- return resolve(root);
23
- }
24
- export function commandOutputFingerprints(options) {
25
- const combined = options.combined ?? combineOutputSections(options.stdout, options.stderr);
26
- return {
27
- exactSha256: sha256Json({ stdout: options.stdout, stderr: options.stderr, combined }),
28
- normalizedSha256: sha256Json({
29
- stdout: normalizeOutputText(options.stdout),
30
- stderr: normalizeOutputText(options.stderr),
31
- combined: normalizeOutputText(combined),
32
- }),
33
- commandFingerprintSha256: sha256Json({
34
- command: options.command,
35
- cwd: options.cwd ?? null,
36
- executionStatus: options.executionStatus,
37
- exitCode: options.exitCode,
38
- }),
39
- };
40
- }
41
- export function textOutputFingerprints(options) {
42
- return {
43
- exactSha256: sha256Text(options.raw),
44
- normalizedSha256: sha256Text(normalizeOutputText(options.raw)),
45
- };
46
- }
47
- export async function findExactDuplicateCommandOutput(vault, options) {
48
- const index = await readSessionIndex(vault, options.sessionId);
49
- for (const outputId of index.outputs) {
50
- if (outputId === options.excludeOutputId) {
51
- continue;
52
- }
53
- const entry = index.records[outputId];
54
- if (!entry || entry.kind !== "command") {
55
- continue;
56
- }
57
- const fingerprints = entry.fingerprints;
58
- if (fingerprints?.exactSha256 === options.fingerprints.exactSha256 &&
59
- fingerprints.commandFingerprintSha256 === options.fingerprints.commandFingerprintSha256) {
60
- return entry;
61
- }
62
- }
63
- return undefined;
64
- }
65
- export async function findExactDuplicateTextOutput(vault, options) {
66
- const index = await readSessionIndex(vault, options.sessionId);
67
- for (const outputId of index.outputs) {
68
- if (outputId === options.excludeOutputId) {
69
- continue;
70
- }
71
- const entry = index.records[outputId];
72
- if (!entry || entry.kind !== "text") {
73
- continue;
74
- }
75
- if (entry.fingerprints?.exactSha256 === options.fingerprints.exactSha256) {
76
- return entry;
77
- }
78
- }
79
- return undefined;
80
- }
81
- export async function storeCommandOutput(vault, options) {
82
- const createdAt = options.createdAt ?? new Date().toISOString();
83
- const combined = options.combined ?? combineOutputSections(options.stdout, options.stderr);
84
- const decisionIds = options.decisionIds ?? [];
85
- const fingerprints = commandOutputFingerprints({
86
- command: options.command,
87
- stdout: options.stdout,
88
- stderr: options.stderr,
89
- combined,
90
- executionStatus: options.executionStatus,
91
- exitCode: options.exitCode,
92
- ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),
93
- });
94
- const payloadHash = sha256Json({
95
- kind: "command",
96
- createdAt,
97
- command: options.command,
98
- cwd: options.cwd,
99
- executionStatus: options.executionStatus,
100
- exitCode: options.exitCode,
101
- durationMs: options.durationMs,
102
- stdout: options.stdout,
103
- stderr: options.stderr,
104
- combined,
105
- decisionIds,
106
- });
107
- const objectId = objectIdFromHash(payloadHash);
108
- const outputId = outputIdFromHash(payloadHash);
109
- const objectDir = objectDirectory(vault, objectId);
110
- const paths = {
111
- meta: join(objectDir, "meta.json"),
112
- stdout: join(objectDir, "stdout.txt"),
113
- stderr: join(objectDir, "stderr.txt"),
114
- combined: join(objectDir, "combined.txt"),
115
- };
116
- const record = {
117
- kind: "command",
118
- outputId,
119
- objectId,
120
- command: options.command,
121
- createdAt,
122
- executionStatus: options.executionStatus,
123
- exitCode: options.exitCode,
124
- paths,
125
- lineCounts: {
126
- stdout: countLines(options.stdout),
127
- stderr: countLines(options.stderr),
128
- combined: countLines(combined),
129
- },
130
- byteCounts: {
131
- stdout: byteLength(options.stdout),
132
- stderr: byteLength(options.stderr),
133
- combined: byteLength(combined),
134
- },
135
- hashes: {
136
- stdoutSha256: sha256Text(options.stdout),
137
- stderrSha256: sha256Text(options.stderr),
138
- combinedSha256: sha256Text(combined),
139
- },
140
- fingerprints,
141
- decisionIds,
142
- contentHashSha256: payloadHash,
143
- retention: vault.retention,
144
- };
145
- const commandExpiresAt = expiresAt(createdAt, vault.retention);
146
- if (commandExpiresAt !== undefined) {
147
- record.expiresAt = commandExpiresAt;
148
- }
149
- if (options.cwd !== undefined) {
150
- record.cwd = options.cwd;
151
- }
152
- if (options.durationMs !== undefined) {
153
- record.durationMs = options.durationMs;
154
- }
155
- await mkdir(objectDir, { recursive: true });
156
- await writeFile(paths.stdout, options.stdout, "utf8");
157
- await writeFile(paths.stderr, options.stderr, "utf8");
158
- await writeFile(paths.combined, combined, "utf8");
159
- await writeJson(paths.meta, record);
160
- await addRecordToSessionIndex(vault, options.sessionId, record);
161
- return record;
162
- }
163
- export async function storeTextOutput(vault, options) {
164
- const createdAt = options.createdAt ?? new Date().toISOString();
165
- const decisionIds = options.decisionIds ?? [];
166
- const fingerprints = textOutputFingerprints({ raw: options.raw });
167
- const payloadHash = sha256Json({
168
- kind: "text",
169
- createdAt,
170
- sourceKind: options.sourceKind,
171
- raw: options.raw,
172
- decisionIds,
173
- });
174
- const objectId = objectIdFromHash(payloadHash);
175
- const outputId = outputIdFromHash(payloadHash);
176
- const objectDir = objectDirectory(vault, objectId);
177
- const paths = {
178
- meta: join(objectDir, "meta.json"),
179
- raw: join(objectDir, "raw.txt"),
180
- };
181
- const record = {
182
- kind: "text",
183
- outputId,
184
- objectId,
185
- sourceKind: options.sourceKind,
186
- createdAt,
187
- paths,
188
- lineCounts: { raw: countLines(options.raw) },
189
- byteCounts: { raw: byteLength(options.raw) },
190
- hashes: { rawSha256: sha256Text(options.raw) },
191
- fingerprints,
192
- decisionIds,
193
- contentHashSha256: payloadHash,
194
- retention: vault.retention,
195
- };
196
- const textExpiresAt = expiresAt(createdAt, vault.retention);
197
- if (textExpiresAt !== undefined) {
198
- record.expiresAt = textExpiresAt;
199
- }
200
- await mkdir(objectDir, { recursive: true });
201
- await writeFile(paths.raw, options.raw, "utf8");
202
- await writeJson(paths.meta, record);
203
- await addRecordToSessionIndex(vault, options.sessionId, record);
204
- return record;
205
- }
206
- export async function storeRepoFileReference(vault, options) {
207
- const createdAt = options.createdAt ?? new Date().toISOString();
208
- const decisionIds = options.decisionIds ?? [];
209
- const payloadHash = sha256Json({
210
- kind: "repo-file",
211
- createdAt,
212
- path: options.path,
213
- hashSha256: options.hashSha256,
214
- decisionIds,
215
- });
216
- const objectId = objectIdFromHash(payloadHash);
217
- const outputId = outputIdFromHash(payloadHash);
218
- const objectDir = objectDirectory(vault, objectId);
219
- const paths = {
220
- meta: join(objectDir, "meta.json"),
221
- };
222
- const record = {
223
- kind: "repo-file",
224
- outputId,
225
- objectId,
226
- path: options.path,
227
- paths,
228
- decisionIds,
229
- createdAt,
230
- contentHashSha256: payloadHash,
231
- retention: vault.retention,
232
- };
233
- const repoExpiresAt = expiresAt(createdAt, vault.retention);
234
- if (repoExpiresAt !== undefined) {
235
- record.expiresAt = repoExpiresAt;
236
- }
237
- if (options.hashSha256 !== undefined) {
238
- record.hashSha256 = options.hashSha256;
239
- }
240
- await mkdir(objectDir, { recursive: true });
241
- await writeJson(paths.meta, record);
242
- await addRecordToSessionIndex(vault, options.sessionId, record);
243
- return record;
244
- }
245
- export async function readVaultRecord(vault, sessionId, outputId) {
246
- const index = await readSessionIndex(vault, sessionId);
247
- const entry = index.records[outputId];
248
- if (!entry) {
249
- throw new Error(`No vault output found for ${outputId} in session ${sessionId}.`);
250
- }
251
- return readJson(join(objectDirectory(vault, entry.objectId), "meta.json"));
252
- }
253
- export async function readOutputText(vault, sessionId, outputId, stream) {
254
- const record = await readVaultRecord(vault, sessionId, outputId);
255
- const path = streamPath(record, stream);
256
- return readFile(path, "utf8");
257
- }
258
- export async function readOutputLines(vault, options) {
259
- if (!Number.isInteger(options.startLine) || !Number.isInteger(options.endLine)) {
260
- throw new Error("Line ranges must use integer line numbers.");
261
- }
262
- if (options.startLine < 1 || options.endLine < options.startLine) {
263
- throw new Error("Line ranges must be 1-based and endLine must be greater than or equal to startLine.");
264
- }
265
- const text = await readOutputText(vault, options.sessionId, options.outputId, options.stream);
266
- return splitLines(text).slice(options.startLine - 1, options.endLine).join("\n");
267
- }
268
- export async function readSessionIndex(vault, sessionId) {
269
- const path = sessionIndexPath(vault, sessionId);
270
- try {
271
- return (await readJson(path));
272
- }
273
- catch (error) {
274
- const code = typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
275
- if (code !== "ENOENT") {
276
- throw error;
277
- }
278
- const now = new Date().toISOString();
279
- return emptySessionIndex(sessionId, now);
280
- }
281
- }
282
- async function addRecordToSessionIndex(vault, sessionId, record) {
283
- await withSessionIndexWriteLock(vault, sessionId, async () => {
284
- const index = await readSessionIndex(vault, sessionId);
285
- const updatedAt = new Date().toISOString();
286
- const entry = {
287
- outputId: record.outputId,
288
- objectId: record.objectId,
289
- kind: record.kind,
290
- createdAt: record.createdAt,
291
- };
292
- if (record.kind === "command") {
293
- entry.executionStatus = record.executionStatus;
294
- }
295
- if (record.fingerprints !== undefined) {
296
- entry.fingerprints = record.fingerprints;
297
- }
298
- index.updatedAt = updatedAt;
299
- index.records[record.outputId] = entry;
300
- addUnique(index.outputs, record.outputId);
301
- if (record.kind === "command") {
302
- addToExecutionGroup(index, record.executionStatus, record.outputId);
303
- }
304
- await writeJsonAtomic(sessionIndexPath(vault, sessionId), index);
305
- });
306
- }
307
- async function withSessionIndexWriteLock(vault, sessionId, operation) {
308
- const key = `${vault.root}:${safeSegment(sessionId)}`;
309
- const previous = sessionIndexWriteLocks.get(key) ?? Promise.resolve();
310
- let releaseCurrent;
311
- const current = new Promise((resolve) => {
312
- releaseCurrent = resolve;
313
- });
314
- const chained = previous.catch(() => undefined).then(() => current);
315
- sessionIndexWriteLocks.set(key, chained);
316
- await previous.catch(() => undefined);
317
- try {
318
- return await withSessionIndexFileLock(vault, sessionId, operation);
319
- }
320
- finally {
321
- releaseCurrent();
322
- if (sessionIndexWriteLocks.get(key) === chained) {
323
- sessionIndexWriteLocks.delete(key);
324
- }
325
- }
326
- }
327
- async function withSessionIndexFileLock(vault, sessionId, operation) {
328
- const path = sessionIndexLockPath(vault, sessionId);
329
- await mkdir(dirname(path), { recursive: true });
330
- const startedAt = Date.now();
331
- let handle;
332
- while (handle === undefined) {
333
- try {
334
- handle = await open(path, "wx");
335
- await handle.writeFile(`${process.pid}\n${new Date().toISOString()}\n`, "utf8");
336
- }
337
- catch (error) {
338
- const code = typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
339
- if (code !== "EEXIST") {
340
- throw error;
341
- }
342
- if (Date.now() - startedAt > SESSION_INDEX_LOCK_TIMEOUT_MS) {
343
- throw new Error(`Timed out waiting for vault session index lock for ${safeSegment(sessionId)}.`);
344
- }
345
- await sleep(SESSION_INDEX_LOCK_RETRY_MS);
346
- }
347
- }
348
- try {
349
- return await operation();
350
- }
351
- finally {
352
- await handle.close().catch(() => undefined);
353
- await unlink(path).catch(() => undefined);
354
- }
355
- }
356
- function addToExecutionGroup(index, status, outputId) {
357
- if (status === "success") {
358
- addUnique(index.successful, outputId);
359
- }
360
- else if (status === "failed") {
361
- addUnique(index.failed, outputId);
362
- }
363
- else if (status === "timed_out") {
364
- addUnique(index.timedOut, outputId);
365
- }
366
- else if (status === "cancelled") {
367
- addUnique(index.cancelled, outputId);
368
- }
369
- }
370
- function emptySessionIndex(sessionId, now) {
371
- return {
372
- version: 1,
373
- sessionId: safeSegment(sessionId),
374
- createdAt: now,
375
- updatedAt: now,
376
- outputs: [],
377
- records: {},
378
- successful: [],
379
- failed: [],
380
- timedOut: [],
381
- cancelled: [],
382
- };
383
- }
384
- function streamPath(record, stream) {
385
- if (record.kind === "command") {
386
- if (stream === "raw") {
387
- throw new Error("Command records do not have a raw stream. Use stdout, stderr, or combined.");
388
- }
389
- return record.paths[stream];
390
- }
391
- if (record.kind === "text") {
392
- if (stream !== "raw") {
393
- throw new Error("Text records only have a raw stream.");
394
- }
395
- return record.paths.raw;
396
- }
397
- throw new Error("Repo file reference records store metadata only and have no raw stream.");
398
- }
399
- function sessionIndexPath(vault, sessionId) {
400
- return join(vault.root, "sessions", safeSegment(sessionId), "index.json");
401
- }
402
- function sessionIndexLockPath(vault, sessionId) {
403
- return `${sessionIndexPath(vault, sessionId)}.lock`;
404
- }
405
- function objectDirectory(vault, objectId) {
406
- return join(vault.root, "objects", objectId);
407
- }
408
- function objectIdFromHash(hash) {
409
- return `sha256_${hash}`;
410
- }
411
- function outputIdFromHash(hash) {
412
- return `ffout_${hash.slice(0, 24)}`;
413
- }
414
- function combineOutputSections(stdout, stderr) {
415
- if (stdout.length === 0) {
416
- return stderr;
417
- }
418
- if (stderr.length === 0) {
419
- return stdout;
420
- }
421
- return `[stdout]\n${stdout}\n[stderr]\n${stderr}`;
422
- }
423
- function countLines(text) {
424
- if (text.length === 0) {
425
- return 0;
426
- }
427
- return splitLines(text).length;
428
- }
429
- function splitLines(text) {
430
- return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
431
- }
432
- function byteLength(text) {
433
- return Buffer.byteLength(text, "utf8");
434
- }
435
- function sha256Text(text) {
436
- return createHash("sha256").update(text).digest("hex");
437
- }
438
- function normalizeOutputText(text) {
439
- return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trimEnd();
440
- }
441
- function sha256Json(value) {
442
- return sha256Text(JSON.stringify(value));
443
- }
444
- function expiresAt(createdAt, retention) {
445
- if (retention.strategy !== "ttl") {
446
- return undefined;
447
- }
448
- const createdTime = new Date(createdAt).getTime();
449
- if (!Number.isFinite(createdTime)) {
450
- return undefined;
451
- }
452
- return new Date(createdTime + retention.ttlDays * 24 * 60 * 60 * 1_000).toISOString();
453
- }
454
- function addUnique(items, item) {
455
- if (!items.includes(item)) {
456
- items.push(item);
457
- }
458
- }
459
- function safeSegment(value) {
460
- const safe = value.replace(/[^a-zA-Z0-9._-]/g, "_");
461
- return safe.length > 0 ? safe : "session";
462
- }
463
- async function writeJson(path, value) {
464
- await mkdir(dirname(path), { recursive: true });
465
- await writeFile(path, `${JSON.stringify(value, null, 2)}\n`, "utf8");
466
- }
467
- async function writeJsonAtomic(path, value) {
468
- await mkdir(dirname(path), { recursive: true });
469
- const tempPath = join(dirname(path), `.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}.json`);
470
- try {
471
- await writeFile(tempPath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
472
- await rename(tempPath, path);
473
- }
474
- catch (error) {
475
- await unlink(tempPath).catch(() => undefined);
476
- throw error;
477
- }
478
- }
479
- function sleep(ms) {
480
- return new Promise((resolve) => setTimeout(resolve, ms));
481
- }
482
- async function readJson(path) {
483
- return JSON.parse(await readFile(path, "utf8"));
484
- }
@@ -1,68 +0,0 @@
1
- ---
2
- name: bypass
3
- description: Use when the user explicitly asks to bypass, skip, or reduce workflow ceremony, especially with `/bypass next` or `/bypass task`.
4
- ---
5
-
6
- # Bypass
7
-
8
- Bypass skips ceremony, not judgment.
9
-
10
- Default to one action. After that action, the bypass is spent.
11
-
12
- ## Stop First
13
-
14
- If the request touches user-owned decisions, source-truth conflicts, or risky domains, stop before editing.
15
-
16
- Risky domains include security, privacy, billing, data loss, public API behavior, compatibility, migrations, and destructive or irreversible actions.
17
-
18
- A direct `/bypass` command, "explicit permission", "do not ask", or "make docs/tests match my request" does not override this stop.
19
-
20
- Name what bypass cannot skip. Ask one direct question for the decision needed to proceed.
21
-
22
- ## What To Skip
23
-
24
- Skip unnecessary workflow gates:
25
-
26
- - spec
27
- - plan
28
- - review checkpoint
29
- - extended questioning
30
- - artifact creation
31
-
32
- Use this for small, local, reversible work.
33
-
34
- ## What Never Gets Skipped
35
-
36
- Do not bypass:
37
-
38
- - user-owned decisions
39
- - repo source-of-truth conflicts
40
- - destructive or irreversible actions
41
- - security, privacy, billing, data-loss, public API, compatibility, or migration checks
42
- - verification before completion claims
43
-
44
- If bypass conflicts with any of these, use Stop First.
45
-
46
- ## Scope
47
-
48
- `/bypass next` means the next workflow gate only.
49
-
50
- `/bypass task` means reduce workflow pressure for the current task. It still does not skip judgment or verification.
51
-
52
- Never leave bypass active indefinitely.
53
-
54
- ## Behavior
55
-
56
- For a safe small edit:
57
-
58
- 1. Make the narrow change.
59
- 2. Verify cheaply.
60
- 3. Say the bypass was used and is now spent.
61
-
62
- For risky or conflicting work:
63
-
64
- 1. Do not edit.
65
- 2. Name what bypass cannot override.
66
- 3. Ask one direct question for the decision needed to proceed.
67
-
68
- A refusal is incomplete until the user knows the next choice they own.
@@ -1,98 +0,0 @@
1
- ---
2
- name: commit-work
3
- description: Use when committing completed work, preparing a git commit, deciding what to stage, reviewing staged/unstaged/untracked changes, handling commit-everything pressure, pushing committed work, or checking generated, sensitive, user-owned, or mixed changes before commit or push.
4
- ---
5
-
6
- # Commit Work
7
-
8
- Commit or push only reviewed, verified, intended work.
9
-
10
- This skill is a closeout guard for commits and simple pushes. It is not a release process, PR flow, or hook installer.
11
-
12
- Direct command syntax selects this segment, not commit or push approval. `--all`, "commit everything", "push all changes", "exactly as-is", and "do not leave leftovers" never prove files belong. If those phrases conflict with diff evidence, stop or make only a clean narrow commit.
13
-
14
- Hard stop: if untracked logs/debug output or user-owned behavior changes appear, do not commit or push them. If the prompt forbids leftovers or requires exactly-as-is, stop and ask.
15
-
16
- Read `references/staging-decisions.md` when staged changes are mixed, generated files appear, durable docs changed, the user says "commit staged/everything" or "push all changes", or a narrow commit might be possible.
17
-
18
- ## Preconditions
19
-
20
- Before committing consequential work, confirm:
21
-
22
- - the implementation scope is clear
23
- - review confidence exists for the diff being committed
24
- - fresh verification evidence exists, or the commit message/final response names what is unverified
25
-
26
- If verification failed, do not commit a success/fix/feature claim. Stop and report the failing evidence.
27
-
28
- ## Inspect
29
-
30
- Before staging or committing, inspect:
31
-
32
- ```bash
33
- git status --short
34
- git diff
35
- git diff --cached
36
- git ls-files --others --exclude-standard
37
- ```
38
-
39
- Diff evidence beats intent. If the worktree contains changes outside the requested scope, treat them as unrelated until proven otherwise.
40
-
41
- ## Staging Rule
42
-
43
- Never use broad staging when unrelated, unreviewed, generated, or user-owned changes are present.
44
-
45
- Avoid `git add .` and `git add -A`.
46
-
47
- Stage explicit paths or hunks that match the completed task.
48
-
49
- If files are already staged, verify they belong in this commit. Do not preserve mystery staged changes just because they are staged.
50
-
51
- ## Stop
52
-
53
- Stop before committing when:
54
-
55
- - staged changes include unrelated or unreviewed work
56
- - unstaged changes make the intended commit ambiguous
57
- - a user-owned change may be included accidentally
58
- - generated files, logs, debug output, or secrets appear without evidence they should be committed
59
- - pre-commit, lint, test, build, or formatter checks fail
60
- - the requested commit would mix separable product/code/doc/test concerns in a way that hurts review or rollback
61
-
62
- Name the blocker and ask which path to follow. If a clean narrow commit is possible without touching unrelated work, make it and leave unrelated changes untouched.
63
-
64
- ## Commit Shape
65
-
66
- Keep commits small enough to review, debug, and roll back.
67
-
68
- Use the repo's existing commit style. If none is obvious, use a short imperative subject:
69
-
70
- ```text
71
- Fix settings title typo
72
- ```
73
-
74
- Add a body only when it helps future readers understand why.
75
-
76
- Reference specs, plans, ADRs, issues, or decisions when they materially explain the commit. Do not invent mandatory `Refs:` lines for repos that do not require them.
77
-
78
- ## Push Rule
79
-
80
- Push only commits you inspected. Before pushing, inspect branch, upstream, remote, and ahead/behind state.
81
- Do not push to protected/shared branches, set upstream, use `--force`, or rewrite remote history unless explicitly requested and branch evidence supports it. Use `--force-with-lease` only for an intended rewrite of the user's own branch.
82
- If branch state is stale, diverged, missing upstream, or likely needs PR/CI/release judgment, stop and ask.
83
-
84
- ## After Commit Or Push
85
-
86
- Verify what landed:
87
-
88
- ```bash
89
- git show --stat --oneline --name-only HEAD
90
- git status --branch --short
91
- ```
92
-
93
- Final response should state:
94
-
95
- - commit SHA, subject, and push result if pushed
96
- - what was committed
97
- - what verification supports it
98
- - any remaining uncommitted, unpushed, or unverified changes
@@ -1,51 +0,0 @@
1
- # Staging Decisions
2
-
3
- Use this for mixed staged sets, generated files, durable docs, or broad commit/push pressure.
4
-
5
- ## Evidence First
6
-
7
- Read staged, unstaged, and untracked state before deciding what to commit or push:
8
-
9
- - `git status --short`
10
- - `git diff --cached`
11
- - `git diff`
12
- - `git ls-files --others --exclude-standard`
13
-
14
- Diff evidence beats "staged means ready", "commit everything", "push all changes", and "include all leftovers".
15
-
16
- ## Mixed Staged Sets
17
-
18
- Staged changes can still be wrong.
19
-
20
- Stop or make a narrow commit when the staged set mixes separable concerns, such as:
21
-
22
- - release note or copy edits plus product behavior
23
- - source code plus local debug output
24
- - generated files plus hand edits
25
- - source-truth docs plus implementation changes that have not been confirmed
26
- - security, billing, permissions, privacy, migration, or public API behavior with unrelated work
27
-
28
- If a sensitive staged change conflicts with docs, tests, policy, or contracts, do not commit it just because it is staged.
29
-
30
- ## Narrow Commit Rule
31
-
32
- Make a narrow commit only when:
33
-
34
- - the intended scope is clear
35
- - the included files are all part of that scope
36
- - excluded changes can remain staged or dirty without being lost
37
- - the final response reports remaining staged/dirty/untracked work
38
-
39
- If excluding files would require unstaging or rearranging user-owned work, ask first unless the repo clearly supports a safe path.
40
-
41
- ## Generated Files
42
-
43
- Do not commit generated files, logs, snapshots, lockfiles, build outputs, or formatter churn unless the task or repo convention makes them part of the intended change.
44
-
45
- If generated output is required, name the generator or verification that produced it.
46
-
47
- ## Durable Docs
48
-
49
- Durable specs, ADRs, policies, handoffs, and runbooks are source truth. Commit them with code only when they describe the same confirmed change.
50
-
51
- If a durable doc changes policy, status, ownership, public API behavior, billing, privacy, security, data loss, migration, or compatibility, treat that as a user-owned decision unless already confirmed.