@matteeh/osq 0.1.0 → 0.2.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 (619) hide show
  1. package/README.md +415 -72
  2. package/dist/cli/approve.d.ts +13 -3
  3. package/dist/cli/approve.d.ts.map +1 -1
  4. package/dist/cli/approve.js +59 -4
  5. package/dist/cli/approve.js.map +1 -1
  6. package/dist/cli/bin.js +0 -0
  7. package/dist/cli/confirm.d.ts +21 -0
  8. package/dist/cli/confirm.d.ts.map +1 -0
  9. package/dist/cli/confirm.js +28 -0
  10. package/dist/cli/confirm.js.map +1 -0
  11. package/dist/cli/doctor.d.ts +13 -0
  12. package/dist/cli/doctor.d.ts.map +1 -0
  13. package/dist/cli/doctor.js +23 -0
  14. package/dist/cli/doctor.js.map +1 -0
  15. package/dist/cli/done.d.ts +12 -0
  16. package/dist/cli/done.d.ts.map +1 -0
  17. package/dist/cli/done.js +26 -0
  18. package/dist/cli/done.js.map +1 -0
  19. package/dist/cli/inbox.d.ts +22 -0
  20. package/dist/cli/inbox.d.ts.map +1 -0
  21. package/dist/cli/inbox.js +41 -0
  22. package/dist/cli/inbox.js.map +1 -0
  23. package/dist/cli/index.d.ts.map +1 -1
  24. package/dist/cli/index.js +127 -8
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/cli/init.d.ts +1 -0
  27. package/dist/cli/init.d.ts.map +1 -1
  28. package/dist/cli/init.js +9 -3
  29. package/dist/cli/init.js.map +1 -1
  30. package/dist/cli/lint.d.ts +26 -0
  31. package/dist/cli/lint.d.ts.map +1 -0
  32. package/dist/cli/lint.js +60 -0
  33. package/dist/cli/lint.js.map +1 -0
  34. package/dist/cli/migrate.d.ts +18 -0
  35. package/dist/cli/migrate.d.ts.map +1 -0
  36. package/dist/cli/migrate.js +42 -0
  37. package/dist/cli/migrate.js.map +1 -0
  38. package/dist/cli/new.js +1 -1
  39. package/dist/cli/new.js.map +1 -1
  40. package/dist/cli/plan-queue.d.ts +50 -0
  41. package/dist/cli/plan-queue.d.ts.map +1 -0
  42. package/dist/cli/plan-queue.js +167 -0
  43. package/dist/cli/plan-queue.js.map +1 -0
  44. package/dist/cli/plan.d.ts +35 -0
  45. package/dist/cli/plan.d.ts.map +1 -0
  46. package/dist/cli/plan.js +153 -0
  47. package/dist/cli/plan.js.map +1 -0
  48. package/dist/cli/queue.d.ts +9 -0
  49. package/dist/cli/queue.d.ts.map +1 -0
  50. package/dist/cli/queue.js +24 -0
  51. package/dist/cli/queue.js.map +1 -0
  52. package/dist/cli/reject.d.ts +8 -0
  53. package/dist/cli/reject.d.ts.map +1 -0
  54. package/dist/cli/reject.js +18 -0
  55. package/dist/cli/reject.js.map +1 -0
  56. package/dist/cli/report.d.ts +1 -1
  57. package/dist/cli/report.d.ts.map +1 -1
  58. package/dist/cli/report.js +141 -14
  59. package/dist/cli/report.js.map +1 -1
  60. package/dist/cli/retry.d.ts +7 -0
  61. package/dist/cli/retry.d.ts.map +1 -0
  62. package/dist/cli/retry.js +29 -0
  63. package/dist/cli/retry.js.map +1 -0
  64. package/dist/cli/serve.d.ts +30 -0
  65. package/dist/cli/serve.d.ts.map +1 -0
  66. package/dist/cli/serve.js +136 -0
  67. package/dist/cli/serve.js.map +1 -0
  68. package/dist/cli/setup.d.ts.map +1 -1
  69. package/dist/cli/setup.js +7 -1
  70. package/dist/cli/setup.js.map +1 -1
  71. package/dist/cli/show.d.ts +2 -1
  72. package/dist/cli/show.d.ts.map +1 -1
  73. package/dist/cli/show.js +20 -3
  74. package/dist/cli/show.js.map +1 -1
  75. package/dist/cli/status.d.ts +1 -1
  76. package/dist/cli/status.d.ts.map +1 -1
  77. package/dist/cli/status.js +2 -2
  78. package/dist/cli/status.js.map +1 -1
  79. package/dist/cli/watch.d.ts +9 -6
  80. package/dist/cli/watch.d.ts.map +1 -1
  81. package/dist/cli/watch.js +15 -2
  82. package/dist/cli/watch.js.map +1 -1
  83. package/dist/core/foundation/config-codex.d.ts +22 -0
  84. package/dist/core/foundation/config-codex.d.ts.map +1 -0
  85. package/dist/core/foundation/config-codex.js +58 -0
  86. package/dist/core/foundation/config-codex.js.map +1 -0
  87. package/dist/core/foundation/config-doctor.d.ts +14 -0
  88. package/dist/core/foundation/config-doctor.d.ts.map +1 -0
  89. package/dist/core/foundation/config-doctor.js +29 -0
  90. package/dist/core/foundation/config-doctor.js.map +1 -0
  91. package/dist/core/foundation/config-env.d.ts +3 -0
  92. package/dist/core/foundation/config-env.d.ts.map +1 -0
  93. package/dist/core/foundation/config-env.js +22 -0
  94. package/dist/core/foundation/config-env.js.map +1 -0
  95. package/dist/core/foundation/config-gates.d.ts +22 -0
  96. package/dist/core/foundation/config-gates.d.ts.map +1 -0
  97. package/dist/core/foundation/config-gates.js +43 -0
  98. package/dist/core/foundation/config-gates.js.map +1 -0
  99. package/dist/core/foundation/config-pi.d.ts +64 -0
  100. package/dist/core/foundation/config-pi.d.ts.map +1 -0
  101. package/dist/core/foundation/config-pi.js +131 -0
  102. package/dist/core/foundation/config-pi.js.map +1 -0
  103. package/dist/core/foundation/config-planning.d.ts +24 -0
  104. package/dist/core/foundation/config-planning.d.ts.map +1 -0
  105. package/dist/core/foundation/config-planning.js +60 -0
  106. package/dist/core/foundation/config-planning.js.map +1 -0
  107. package/dist/core/foundation/config-queue.d.ts +15 -0
  108. package/dist/core/foundation/config-queue.d.ts.map +1 -0
  109. package/dist/core/foundation/config-queue.js +24 -0
  110. package/dist/core/foundation/config-queue.js.map +1 -0
  111. package/dist/core/foundation/config-serve.d.ts +20 -0
  112. package/dist/core/foundation/config-serve.d.ts.map +1 -0
  113. package/dist/core/foundation/config-serve.js +35 -0
  114. package/dist/core/foundation/config-serve.js.map +1 -0
  115. package/dist/core/{config.d.ts → foundation/config.d.ts} +34 -3
  116. package/dist/core/foundation/config.d.ts.map +1 -0
  117. package/dist/core/{config.js → foundation/config.js} +35 -18
  118. package/dist/core/foundation/config.js.map +1 -0
  119. package/dist/core/foundation/doctor-managed.d.ts +13 -0
  120. package/dist/core/foundation/doctor-managed.d.ts.map +1 -0
  121. package/dist/core/foundation/doctor-managed.js +77 -0
  122. package/dist/core/foundation/doctor-managed.js.map +1 -0
  123. package/dist/core/foundation/doctor.d.ts +19 -0
  124. package/dist/core/foundation/doctor.d.ts.map +1 -0
  125. package/dist/core/foundation/doctor.js +187 -0
  126. package/dist/core/foundation/doctor.js.map +1 -0
  127. package/dist/core/foundation/harness-catalog.d.ts +96 -0
  128. package/dist/core/foundation/harness-catalog.d.ts.map +1 -0
  129. package/dist/core/foundation/harness-catalog.js +182 -0
  130. package/dist/core/foundation/harness-catalog.js.map +1 -0
  131. package/dist/core/foundation/init-blocks.d.ts +33 -0
  132. package/dist/core/foundation/init-blocks.d.ts.map +1 -0
  133. package/dist/core/foundation/init-blocks.js +165 -0
  134. package/dist/core/foundation/init-blocks.js.map +1 -0
  135. package/dist/core/foundation/init-managed.d.ts +10 -0
  136. package/dist/core/foundation/init-managed.d.ts.map +1 -0
  137. package/dist/core/foundation/init-managed.js +115 -0
  138. package/dist/core/foundation/init-managed.js.map +1 -0
  139. package/dist/core/foundation/init.d.ts +18 -0
  140. package/dist/core/foundation/init.d.ts.map +1 -0
  141. package/dist/core/foundation/init.js +113 -0
  142. package/dist/core/foundation/init.js.map +1 -0
  143. package/dist/core/{logger.d.ts → foundation/logger.d.ts} +1 -0
  144. package/dist/core/foundation/logger.d.ts.map +1 -0
  145. package/dist/core/{logger.js → foundation/logger.js} +18 -2
  146. package/dist/core/foundation/logger.js.map +1 -0
  147. package/dist/core/{new.d.ts → foundation/new.d.ts} +3 -0
  148. package/dist/core/foundation/new.d.ts.map +1 -0
  149. package/dist/core/foundation/new.js +206 -0
  150. package/dist/core/foundation/new.js.map +1 -0
  151. package/dist/core/foundation/package-root.d.ts +9 -0
  152. package/dist/core/foundation/package-root.d.ts.map +1 -0
  153. package/dist/core/foundation/package-root.js +11 -0
  154. package/dist/core/foundation/package-root.js.map +1 -0
  155. package/dist/core/lifecycle/done.d.ts +17 -0
  156. package/dist/core/lifecycle/done.d.ts.map +1 -0
  157. package/dist/core/lifecycle/done.js +97 -0
  158. package/dist/core/lifecycle/done.js.map +1 -0
  159. package/dist/core/lifecycle/reject.d.ts +26 -0
  160. package/dist/core/lifecycle/reject.d.ts.map +1 -0
  161. package/dist/core/lifecycle/reject.js +83 -0
  162. package/dist/core/lifecycle/reject.js.map +1 -0
  163. package/dist/core/lifecycle/retry-transition.d.ts +23 -0
  164. package/dist/core/lifecycle/retry-transition.d.ts.map +1 -0
  165. package/dist/core/lifecycle/retry-transition.js +41 -0
  166. package/dist/core/lifecycle/retry-transition.js.map +1 -0
  167. package/dist/core/lifecycle/retry.d.ts +18 -0
  168. package/dist/core/lifecycle/retry.d.ts.map +1 -0
  169. package/dist/core/lifecycle/retry.js +179 -0
  170. package/dist/core/lifecycle/retry.js.map +1 -0
  171. package/dist/core/report/approval-flags.d.ts +29 -0
  172. package/dist/core/report/approval-flags.d.ts.map +1 -0
  173. package/dist/core/report/approval-flags.js +138 -0
  174. package/dist/core/report/approval-flags.js.map +1 -0
  175. package/dist/core/report/planning-economics.d.ts +39 -0
  176. package/dist/core/report/planning-economics.d.ts.map +1 -0
  177. package/dist/core/report/planning-economics.js +168 -0
  178. package/dist/core/report/planning-economics.js.map +1 -0
  179. package/dist/core/report/planning-observed.d.ts +59 -0
  180. package/dist/core/report/planning-observed.d.ts.map +1 -0
  181. package/dist/core/report/planning-observed.js +135 -0
  182. package/dist/core/report/planning-observed.js.map +1 -0
  183. package/dist/core/report/planning-records.d.ts +69 -0
  184. package/dist/core/report/planning-records.d.ts.map +1 -0
  185. package/dist/core/report/planning-records.js +149 -0
  186. package/dist/core/report/planning-records.js.map +1 -0
  187. package/dist/core/report/planning-slice-lookup.d.ts +13 -0
  188. package/dist/core/report/planning-slice-lookup.d.ts.map +1 -0
  189. package/dist/core/report/planning-slice-lookup.js +146 -0
  190. package/dist/core/report/planning-slice-lookup.js.map +1 -0
  191. package/dist/core/report/planning-slice-measures.d.ts +17 -0
  192. package/dist/core/report/planning-slice-measures.d.ts.map +1 -0
  193. package/dist/core/report/planning-slice-measures.js +85 -0
  194. package/dist/core/report/planning-slice-measures.js.map +1 -0
  195. package/dist/core/report/planning-slice-record.d.ts +4 -0
  196. package/dist/core/report/planning-slice-record.d.ts.map +1 -0
  197. package/dist/core/report/planning-slice-record.js +66 -0
  198. package/dist/core/report/planning-slice-record.js.map +1 -0
  199. package/dist/core/report/planning-slice-turns.d.ts +13 -0
  200. package/dist/core/report/planning-slice-turns.d.ts.map +1 -0
  201. package/dist/core/report/planning-slice-turns.js +41 -0
  202. package/dist/core/report/planning-slice-turns.js.map +1 -0
  203. package/dist/core/report/planning-slice.d.ts +70 -0
  204. package/dist/core/report/planning-slice.d.ts.map +1 -0
  205. package/dist/core/report/planning-slice.js +147 -0
  206. package/dist/core/report/planning-slice.js.map +1 -0
  207. package/dist/core/report/planning.d.ts +31 -0
  208. package/dist/core/report/planning.d.ts.map +1 -0
  209. package/dist/core/report/planning.js +75 -0
  210. package/dist/core/report/planning.js.map +1 -0
  211. package/dist/core/report/report-events.d.ts +52 -0
  212. package/dist/core/report/report-events.d.ts.map +1 -0
  213. package/dist/core/report/report-events.js +198 -0
  214. package/dist/core/report/report-events.js.map +1 -0
  215. package/dist/core/report/report-pre-spawn.d.ts +25 -0
  216. package/dist/core/report/report-pre-spawn.d.ts.map +1 -0
  217. package/dist/core/report/report-pre-spawn.js +40 -0
  218. package/dist/core/report/report-pre-spawn.js.map +1 -0
  219. package/dist/core/report/report-retries.d.ts +30 -0
  220. package/dist/core/report/report-retries.d.ts.map +1 -0
  221. package/dist/core/report/report-retries.js +100 -0
  222. package/dist/core/report/report-retries.js.map +1 -0
  223. package/dist/core/report/report.d.ts +276 -0
  224. package/dist/core/report/report.d.ts.map +1 -0
  225. package/dist/core/report/report.js +1421 -0
  226. package/dist/core/report/report.js.map +1 -0
  227. package/dist/core/{lock.d.ts → run/lock.d.ts} +6 -0
  228. package/dist/core/run/lock.d.ts.map +1 -0
  229. package/dist/core/{lock.js → run/lock.js} +7 -15
  230. package/dist/core/run/lock.js.map +1 -0
  231. package/dist/core/run/manifest.d.ts +39 -0
  232. package/dist/core/run/manifest.d.ts.map +1 -0
  233. package/dist/core/run/manifest.js +137 -0
  234. package/dist/core/run/manifest.js.map +1 -0
  235. package/dist/core/run/scope-hash.d.ts +71 -0
  236. package/dist/core/run/scope-hash.d.ts.map +1 -0
  237. package/dist/core/run/scope-hash.js +177 -0
  238. package/dist/core/run/scope-hash.js.map +1 -0
  239. package/dist/core/run/scope.d.ts +30 -0
  240. package/dist/core/run/scope.d.ts.map +1 -0
  241. package/dist/core/run/scope.js +193 -0
  242. package/dist/core/run/scope.js.map +1 -0
  243. package/dist/core/run/summary.d.ts +8 -0
  244. package/dist/core/run/summary.d.ts.map +1 -0
  245. package/dist/core/run/summary.js +25 -0
  246. package/dist/core/run/summary.js.map +1 -0
  247. package/dist/core/run/verification.d.ts +23 -0
  248. package/dist/core/run/verification.d.ts.map +1 -0
  249. package/dist/core/run/verification.js +78 -0
  250. package/dist/core/run/verification.js.map +1 -0
  251. package/dist/core/spec/approve.d.ts +31 -0
  252. package/dist/core/spec/approve.d.ts.map +1 -0
  253. package/dist/core/spec/approve.js +111 -0
  254. package/dist/core/spec/approve.js.map +1 -0
  255. package/dist/core/spec/delta.d.ts +77 -0
  256. package/dist/core/spec/delta.d.ts.map +1 -0
  257. package/dist/core/spec/delta.js +581 -0
  258. package/dist/core/spec/delta.js.map +1 -0
  259. package/dist/core/spec/digest-flags.d.ts +21 -0
  260. package/dist/core/spec/digest-flags.d.ts.map +1 -0
  261. package/dist/core/spec/digest-flags.js +194 -0
  262. package/dist/core/spec/digest-flags.js.map +1 -0
  263. package/dist/core/spec/digest-verify-starts.d.ts +5 -0
  264. package/dist/core/spec/digest-verify-starts.d.ts.map +1 -0
  265. package/dist/core/spec/digest-verify-starts.js +31 -0
  266. package/dist/core/spec/digest-verify-starts.js.map +1 -0
  267. package/dist/core/spec/digest.d.ts +42 -0
  268. package/dist/core/spec/digest.d.ts.map +1 -0
  269. package/dist/core/spec/digest.js +170 -0
  270. package/dist/core/spec/digest.js.map +1 -0
  271. package/dist/core/spec/hasher.d.ts +11 -0
  272. package/dist/core/spec/hasher.d.ts.map +1 -0
  273. package/dist/core/{hasher.js → spec/hasher.js} +27 -3
  274. package/dist/core/spec/hasher.js.map +1 -0
  275. package/dist/core/spec/linter.d.ts +79 -0
  276. package/dist/core/spec/linter.d.ts.map +1 -0
  277. package/dist/core/spec/linter.js +826 -0
  278. package/dist/core/spec/linter.js.map +1 -0
  279. package/dist/core/spec/migrate.d.ts +54 -0
  280. package/dist/core/spec/migrate.d.ts.map +1 -0
  281. package/dist/core/spec/migrate.js +297 -0
  282. package/dist/core/spec/migrate.js.map +1 -0
  283. package/dist/core/spec/openspec-version.d.ts +30 -0
  284. package/dist/core/spec/openspec-version.d.ts.map +1 -0
  285. package/dist/core/spec/openspec-version.js +118 -0
  286. package/dist/core/spec/openspec-version.js.map +1 -0
  287. package/dist/core/spec/parser.d.ts +82 -0
  288. package/dist/core/spec/parser.d.ts.map +1 -0
  289. package/dist/core/spec/parser.js +221 -0
  290. package/dist/core/spec/parser.js.map +1 -0
  291. package/dist/core/spec/verify-paths.d.ts +18 -0
  292. package/dist/core/spec/verify-paths.d.ts.map +1 -0
  293. package/dist/core/spec/verify-paths.js +139 -0
  294. package/dist/core/spec/verify-paths.js.map +1 -0
  295. package/dist/core/spec/verify-starts.d.ts +45 -0
  296. package/dist/core/spec/verify-starts.d.ts.map +1 -0
  297. package/dist/core/spec/verify-starts.js +61 -0
  298. package/dist/core/spec/verify-starts.js.map +1 -0
  299. package/dist/core/status/inbox-cursor.d.ts +10 -0
  300. package/dist/core/status/inbox-cursor.d.ts.map +1 -0
  301. package/dist/core/status/inbox-cursor.js +33 -0
  302. package/dist/core/status/inbox-cursor.js.map +1 -0
  303. package/dist/core/status/inbox-projection.d.ts +15 -0
  304. package/dist/core/status/inbox-projection.d.ts.map +1 -0
  305. package/dist/core/status/inbox-projection.js +20 -0
  306. package/dist/core/status/inbox-projection.js.map +1 -0
  307. package/dist/core/status/inbox-text.d.ts +4 -0
  308. package/dist/core/status/inbox-text.d.ts.map +1 -0
  309. package/dist/core/status/inbox-text.js +48 -0
  310. package/dist/core/status/inbox-text.js.map +1 -0
  311. package/dist/core/status/inbox.d.ts +53 -0
  312. package/dist/core/status/inbox.d.ts.map +1 -0
  313. package/dist/core/status/inbox.js +167 -0
  314. package/dist/core/status/inbox.js.map +1 -0
  315. package/dist/core/status/layout.d.ts +29 -0
  316. package/dist/core/status/layout.d.ts.map +1 -0
  317. package/dist/core/status/layout.js +77 -0
  318. package/dist/core/status/layout.js.map +1 -0
  319. package/dist/core/status/queue-parser.d.ts +13 -0
  320. package/dist/core/status/queue-parser.d.ts.map +1 -0
  321. package/dist/core/status/queue-parser.js +88 -0
  322. package/dist/core/status/queue-parser.js.map +1 -0
  323. package/dist/core/status/queue-planning.d.ts +62 -0
  324. package/dist/core/status/queue-planning.d.ts.map +1 -0
  325. package/dist/core/status/queue-planning.js +158 -0
  326. package/dist/core/status/queue-planning.js.map +1 -0
  327. package/dist/core/status/queue-report-detail.d.ts +50 -0
  328. package/dist/core/status/queue-report-detail.d.ts.map +1 -0
  329. package/dist/core/status/queue-report-detail.js +140 -0
  330. package/dist/core/status/queue-report-detail.js.map +1 -0
  331. package/dist/core/status/queue-report.d.ts +14 -0
  332. package/dist/core/status/queue-report.d.ts.map +1 -0
  333. package/dist/core/status/queue-report.js +41 -0
  334. package/dist/core/status/queue-report.js.map +1 -0
  335. package/dist/core/status/queue-state.d.ts +53 -0
  336. package/dist/core/status/queue-state.d.ts.map +1 -0
  337. package/dist/core/status/queue-state.js +167 -0
  338. package/dist/core/status/queue-state.js.map +1 -0
  339. package/dist/core/status/queue.d.ts +7 -0
  340. package/dist/core/status/queue.d.ts.map +1 -0
  341. package/dist/core/status/queue.js +4 -0
  342. package/dist/core/status/queue.js.map +1 -0
  343. package/dist/core/status/show.d.ts +102 -0
  344. package/dist/core/status/show.d.ts.map +1 -0
  345. package/dist/core/status/show.js +704 -0
  346. package/dist/core/status/show.js.map +1 -0
  347. package/dist/core/status/state.d.ts +56 -0
  348. package/dist/core/status/state.d.ts.map +1 -0
  349. package/dist/core/status/state.js +187 -0
  350. package/dist/core/status/state.js.map +1 -0
  351. package/dist/core/status/status.d.ts +23 -0
  352. package/dist/core/status/status.d.ts.map +1 -0
  353. package/dist/core/status/status.js +173 -0
  354. package/dist/core/status/status.js.map +1 -0
  355. package/dist/core/web/web-data-change.d.ts +10 -0
  356. package/dist/core/web/web-data-change.d.ts.map +1 -0
  357. package/dist/core/web/web-data-change.js +106 -0
  358. package/dist/core/web/web-data-change.js.map +1 -0
  359. package/dist/core/web/web-data-folders.d.ts +39 -0
  360. package/dist/core/web/web-data-folders.d.ts.map +1 -0
  361. package/dist/core/web/web-data-folders.js +125 -0
  362. package/dist/core/web/web-data-folders.js.map +1 -0
  363. package/dist/core/web/web-data-graph.d.ts +8 -0
  364. package/dist/core/web/web-data-graph.d.ts.map +1 -0
  365. package/dist/core/web/web-data-graph.js +113 -0
  366. package/dist/core/web/web-data-graph.js.map +1 -0
  367. package/dist/core/web/web-data-lifecycle.d.ts +43 -0
  368. package/dist/core/web/web-data-lifecycle.d.ts.map +1 -0
  369. package/dist/core/web/web-data-lifecycle.js +141 -0
  370. package/dist/core/web/web-data-lifecycle.js.map +1 -0
  371. package/dist/core/web/web-data-observations.d.ts +30 -0
  372. package/dist/core/web/web-data-observations.d.ts.map +1 -0
  373. package/dist/core/web/web-data-observations.js +181 -0
  374. package/dist/core/web/web-data-observations.js.map +1 -0
  375. package/dist/core/web/web-data-tokens.d.ts +29 -0
  376. package/dist/core/web/web-data-tokens.d.ts.map +1 -0
  377. package/dist/core/web/web-data-tokens.js +62 -0
  378. package/dist/core/web/web-data-tokens.js.map +1 -0
  379. package/dist/core/web/web-data-types.d.ts +156 -0
  380. package/dist/core/web/web-data-types.d.ts.map +1 -0
  381. package/dist/core/web/web-data-types.js +15 -0
  382. package/dist/core/web/web-data-types.js.map +1 -0
  383. package/dist/core/web/web-data.d.ts +10 -0
  384. package/dist/core/web/web-data.d.ts.map +1 -0
  385. package/dist/core/web/web-data.js +8 -0
  386. package/dist/core/web/web-data.js.map +1 -0
  387. package/dist/core/web/web-events.d.ts +54 -0
  388. package/dist/core/web/web-events.d.ts.map +1 -0
  389. package/dist/core/web/web-events.js +162 -0
  390. package/dist/core/web/web-events.js.map +1 -0
  391. package/dist/core/web/web-export.d.ts +18 -0
  392. package/dist/core/web/web-export.d.ts.map +1 -0
  393. package/dist/core/web/web-export.js +112 -0
  394. package/dist/core/web/web-export.js.map +1 -0
  395. package/dist/core/web/web-server.d.ts +34 -0
  396. package/dist/core/web/web-server.d.ts.map +1 -0
  397. package/dist/core/web/web-server.js +182 -0
  398. package/dist/core/web/web-server.js.map +1 -0
  399. package/dist/core/web/web-static.d.ts +20 -0
  400. package/dist/core/web/web-static.d.ts.map +1 -0
  401. package/dist/core/web/web-static.js +104 -0
  402. package/dist/core/web/web-static.js.map +1 -0
  403. package/dist/harness/{agy.d.ts → agy/agy.d.ts} +8 -6
  404. package/dist/harness/agy/agy.d.ts.map +1 -0
  405. package/dist/harness/{agy.js → agy/agy.js} +49 -34
  406. package/dist/harness/agy/agy.js.map +1 -0
  407. package/dist/harness/claude/claude-turns.d.ts +29 -0
  408. package/dist/harness/claude/claude-turns.d.ts.map +1 -0
  409. package/dist/harness/claude/claude-turns.js +162 -0
  410. package/dist/harness/claude/claude-turns.js.map +1 -0
  411. package/dist/harness/claude/claude-usage.d.ts +12 -0
  412. package/dist/harness/claude/claude-usage.d.ts.map +1 -0
  413. package/dist/harness/claude/claude-usage.js +144 -0
  414. package/dist/harness/claude/claude-usage.js.map +1 -0
  415. package/dist/harness/codex/codex-observe-usage.d.ts +6 -0
  416. package/dist/harness/codex/codex-observe-usage.d.ts.map +1 -0
  417. package/dist/harness/codex/codex-observe-usage.js +215 -0
  418. package/dist/harness/codex/codex-observe-usage.js.map +1 -0
  419. package/dist/harness/codex/codex-prompt.d.ts +17 -0
  420. package/dist/harness/codex/codex-prompt.d.ts.map +1 -0
  421. package/dist/harness/codex/codex-prompt.js +43 -0
  422. package/dist/harness/codex/codex-prompt.js.map +1 -0
  423. package/dist/harness/codex/codex-stream.d.ts +23 -0
  424. package/dist/harness/codex/codex-stream.d.ts.map +1 -0
  425. package/dist/harness/codex/codex-stream.js +182 -0
  426. package/dist/harness/codex/codex-stream.js.map +1 -0
  427. package/dist/harness/codex/codex-usage.d.ts +26 -0
  428. package/dist/harness/codex/codex-usage.d.ts.map +1 -0
  429. package/dist/harness/codex/codex-usage.js +122 -0
  430. package/dist/harness/codex/codex-usage.js.map +1 -0
  431. package/dist/harness/codex/codex.d.ts +16 -0
  432. package/dist/harness/codex/codex.d.ts.map +1 -0
  433. package/dist/harness/codex/codex.js +92 -0
  434. package/dist/harness/codex/codex.js.map +1 -0
  435. package/dist/harness/index.d.ts +11 -2
  436. package/dist/harness/index.d.ts.map +1 -1
  437. package/dist/harness/index.js +24 -9
  438. package/dist/harness/index.js.map +1 -1
  439. package/dist/harness/mock.d.ts +5 -2
  440. package/dist/harness/mock.d.ts.map +1 -1
  441. package/dist/harness/mock.js +10 -11
  442. package/dist/harness/mock.js.map +1 -1
  443. package/dist/harness/opencode/opencode-observe-usage.d.ts +4 -0
  444. package/dist/harness/opencode/opencode-observe-usage.d.ts.map +1 -0
  445. package/dist/harness/opencode/opencode-observe-usage.js +100 -0
  446. package/dist/harness/opencode/opencode-observe-usage.js.map +1 -0
  447. package/dist/harness/opencode/opencode-usage.d.ts +24 -0
  448. package/dist/harness/opencode/opencode-usage.d.ts.map +1 -0
  449. package/dist/harness/opencode/opencode-usage.js +181 -0
  450. package/dist/harness/opencode/opencode-usage.js.map +1 -0
  451. package/dist/harness/{opencode.d.ts → opencode/opencode.d.ts} +10 -7
  452. package/dist/harness/opencode/opencode.d.ts.map +1 -0
  453. package/dist/harness/{opencode.js → opencode/opencode.js} +159 -70
  454. package/dist/harness/opencode/opencode.js.map +1 -0
  455. package/dist/harness/pi/pi-args.d.ts +9 -0
  456. package/dist/harness/pi/pi-args.d.ts.map +1 -0
  457. package/dist/harness/pi/pi-args.js +33 -0
  458. package/dist/harness/pi/pi-args.js.map +1 -0
  459. package/dist/harness/pi/pi-stream.d.ts +27 -0
  460. package/dist/harness/pi/pi-stream.d.ts.map +1 -0
  461. package/dist/harness/pi/pi-stream.js +176 -0
  462. package/dist/harness/pi/pi-stream.js.map +1 -0
  463. package/dist/harness/pi/pi-tools.d.ts +5 -0
  464. package/dist/harness/pi/pi-tools.d.ts.map +1 -0
  465. package/dist/harness/pi/pi-tools.js +31 -0
  466. package/dist/harness/pi/pi-tools.js.map +1 -0
  467. package/dist/harness/pi/pi.d.ts +11 -0
  468. package/dist/harness/pi/pi.d.ts.map +1 -0
  469. package/dist/harness/pi/pi.js +109 -0
  470. package/dist/harness/pi/pi.js.map +1 -0
  471. package/dist/harness/prompt.d.ts +11 -0
  472. package/dist/harness/prompt.d.ts.map +1 -0
  473. package/dist/harness/prompt.js +105 -0
  474. package/dist/harness/prompt.js.map +1 -0
  475. package/dist/harness/types.d.ts +287 -8
  476. package/dist/harness/types.d.ts.map +1 -1
  477. package/dist/harness/types.js +125 -0
  478. package/dist/harness/types.js.map +1 -1
  479. package/dist/index.d.ts +13 -2
  480. package/dist/index.d.ts.map +1 -1
  481. package/dist/index.js +8 -1
  482. package/dist/index.js.map +1 -1
  483. package/dist/watcher/archive-verify.d.ts +9 -0
  484. package/dist/watcher/archive-verify.d.ts.map +1 -0
  485. package/dist/watcher/archive-verify.js +80 -0
  486. package/dist/watcher/archive-verify.js.map +1 -0
  487. package/dist/watcher/archiver.d.ts +14 -2
  488. package/dist/watcher/archiver.d.ts.map +1 -1
  489. package/dist/watcher/archiver.js +112 -33
  490. package/dist/watcher/archiver.js.map +1 -1
  491. package/dist/watcher/attempt.d.ts +19 -0
  492. package/dist/watcher/attempt.d.ts.map +1 -0
  493. package/dist/watcher/attempt.js +94 -0
  494. package/dist/watcher/attempt.js.map +1 -0
  495. package/dist/watcher/auto-retry.d.ts +11 -0
  496. package/dist/watcher/auto-retry.d.ts.map +1 -0
  497. package/dist/watcher/auto-retry.js +180 -0
  498. package/dist/watcher/auto-retry.js.map +1 -0
  499. package/dist/watcher/build.d.ts +24 -0
  500. package/dist/watcher/build.d.ts.map +1 -0
  501. package/dist/watcher/build.js +169 -0
  502. package/dist/watcher/build.js.map +1 -0
  503. package/dist/watcher/change-verify.d.ts +25 -0
  504. package/dist/watcher/change-verify.d.ts.map +1 -0
  505. package/dist/watcher/change-verify.js +57 -0
  506. package/dist/watcher/change-verify.js.map +1 -0
  507. package/dist/watcher/dev.d.ts +51 -0
  508. package/dist/watcher/dev.d.ts.map +1 -0
  509. package/dist/watcher/dev.js +124 -0
  510. package/dist/watcher/dev.js.map +1 -0
  511. package/dist/watcher/failure-reason.d.ts +7 -0
  512. package/dist/watcher/failure-reason.d.ts.map +1 -0
  513. package/dist/watcher/failure-reason.js +2 -0
  514. package/dist/watcher/failure-reason.js.map +1 -0
  515. package/dist/watcher/fingerprint.d.ts +19 -0
  516. package/dist/watcher/fingerprint.d.ts.map +1 -0
  517. package/dist/watcher/fingerprint.js +53 -0
  518. package/dist/watcher/fingerprint.js.map +1 -0
  519. package/dist/watcher/heartbeat.d.ts +33 -0
  520. package/dist/watcher/heartbeat.d.ts.map +1 -0
  521. package/dist/watcher/heartbeat.js +135 -0
  522. package/dist/watcher/heartbeat.js.map +1 -0
  523. package/dist/watcher/lock.d.ts +10 -0
  524. package/dist/watcher/lock.d.ts.map +1 -0
  525. package/dist/watcher/lock.js +14 -0
  526. package/dist/watcher/lock.js.map +1 -0
  527. package/dist/watcher/loop.d.ts +26 -6
  528. package/dist/watcher/loop.d.ts.map +1 -1
  529. package/dist/watcher/loop.js +154 -37
  530. package/dist/watcher/loop.js.map +1 -1
  531. package/dist/watcher/measures.d.ts +46 -0
  532. package/dist/watcher/measures.d.ts.map +1 -0
  533. package/dist/watcher/measures.js +203 -0
  534. package/dist/watcher/measures.js.map +1 -0
  535. package/dist/watcher/outcome.d.ts +32 -0
  536. package/dist/watcher/outcome.d.ts.map +1 -0
  537. package/dist/watcher/outcome.js +127 -0
  538. package/dist/watcher/outcome.js.map +1 -0
  539. package/dist/watcher/regression.d.ts +43 -0
  540. package/dist/watcher/regression.d.ts.map +1 -0
  541. package/dist/watcher/regression.js +175 -0
  542. package/dist/watcher/regression.js.map +1 -0
  543. package/dist/watcher/runner.d.ts +6 -68
  544. package/dist/watcher/runner.d.ts.map +1 -1
  545. package/dist/watcher/runner.js +74 -523
  546. package/dist/watcher/runner.js.map +1 -1
  547. package/dist/watcher/spawn.d.ts +48 -0
  548. package/dist/watcher/spawn.d.ts.map +1 -0
  549. package/dist/watcher/spawn.js +130 -0
  550. package/dist/watcher/spawn.js.map +1 -0
  551. package/dist/watcher/task-verify.d.ts +59 -0
  552. package/dist/watcher/task-verify.d.ts.map +1 -0
  553. package/dist/watcher/task-verify.js +108 -0
  554. package/dist/watcher/task-verify.js.map +1 -0
  555. package/dist/watcher/verify.d.ts +44 -0
  556. package/dist/watcher/verify.d.ts.map +1 -0
  557. package/dist/watcher/verify.js +156 -0
  558. package/dist/watcher/verify.js.map +1 -0
  559. package/package.json +21 -9
  560. package/templates/PLANNER.md +77 -0
  561. package/templates/openspec/config.yaml +24 -0
  562. package/templates/openspec/schemas/osq/README.md +30 -0
  563. package/templates/openspec/schemas/osq/schema.yaml +133 -0
  564. package/templates/openspec/schemas/osq/templates/proposal.md +66 -0
  565. package/templates/openspec/schemas/osq/templates/spec.md +13 -0
  566. package/templates/openspec/schemas/osq/templates/tasks.md +11 -0
  567. package/templates/proposal.md +66 -0
  568. package/templates/tasks.md +5 -0
  569. package/ui/dist/assets/index-CZYeQ8la.js +9 -0
  570. package/ui/dist/assets/index-D6zVSjO7.css +1 -0
  571. package/ui/dist/index.html +14 -0
  572. package/dist/core/approve.d.ts +0 -11
  573. package/dist/core/approve.d.ts.map +0 -1
  574. package/dist/core/approve.js +0 -52
  575. package/dist/core/approve.js.map +0 -1
  576. package/dist/core/config.d.ts.map +0 -1
  577. package/dist/core/config.js.map +0 -1
  578. package/dist/core/hasher.d.ts +0 -4
  579. package/dist/core/hasher.d.ts.map +0 -1
  580. package/dist/core/hasher.js.map +0 -1
  581. package/dist/core/init.d.ts +0 -12
  582. package/dist/core/init.d.ts.map +0 -1
  583. package/dist/core/init.js +0 -151
  584. package/dist/core/init.js.map +0 -1
  585. package/dist/core/linter.d.ts +0 -8
  586. package/dist/core/linter.d.ts.map +0 -1
  587. package/dist/core/linter.js +0 -100
  588. package/dist/core/linter.js.map +0 -1
  589. package/dist/core/lock.d.ts.map +0 -1
  590. package/dist/core/lock.js.map +0 -1
  591. package/dist/core/logger.d.ts.map +0 -1
  592. package/dist/core/logger.js.map +0 -1
  593. package/dist/core/new.d.ts.map +0 -1
  594. package/dist/core/new.js +0 -79
  595. package/dist/core/new.js.map +0 -1
  596. package/dist/core/parser.d.ts +0 -32
  597. package/dist/core/parser.d.ts.map +0 -1
  598. package/dist/core/parser.js +0 -87
  599. package/dist/core/parser.js.map +0 -1
  600. package/dist/core/report.d.ts +0 -54
  601. package/dist/core/report.d.ts.map +0 -1
  602. package/dist/core/report.js +0 -475
  603. package/dist/core/report.js.map +0 -1
  604. package/dist/core/show.d.ts +0 -50
  605. package/dist/core/show.d.ts.map +0 -1
  606. package/dist/core/show.js +0 -374
  607. package/dist/core/show.js.map +0 -1
  608. package/dist/core/state.d.ts +0 -25
  609. package/dist/core/state.d.ts.map +0 -1
  610. package/dist/core/state.js +0 -180
  611. package/dist/core/state.js.map +0 -1
  612. package/dist/core/status.d.ts +0 -10
  613. package/dist/core/status.d.ts.map +0 -1
  614. package/dist/core/status.js +0 -106
  615. package/dist/core/status.js.map +0 -1
  616. package/dist/harness/agy.d.ts.map +0 -1
  617. package/dist/harness/agy.js.map +0 -1
  618. package/dist/harness/opencode.d.ts.map +0 -1
  619. package/dist/harness/opencode.js.map +0 -1
package/README.md CHANGED
@@ -8,31 +8,49 @@ If a fresh agent could not pick up a task from the files in the repo alone, the
8
8
 
9
9
  ## Install
10
10
 
11
+ osq requires Node.js 24 LTS or newer (`engines.node: >=24.0.0`).
12
+
11
13
  ```sh
12
14
  npx @matteeh/osq init # scaffolds the folders below and configuration
13
15
  pnpm add -D @matteeh/osq # adds osq as a devDependency (or npm i -D @matteeh/osq)
14
- pnpm osq watch # start the watcher
16
+ pnpm osq watch # start the watcher
15
17
  ```
16
18
 
17
- `init` is idempotent. Run it again after upgrading to refresh the managed block in AGENTS.md; it never touches anything else you've edited.
19
+ `init` is idempotent. Run it again after upgrading to refresh the managed blocks in `AGENTS.md`, `PLANNER.md`, and `.claude/commands/osq-plan.md`; it never touches anything else you've edited and preserves foreign managed blocks. Until you do, `osq doctor` reports the drift.
20
+
21
+ Run `osq init --refresh-schema` to pick up a new OpenSpec schema. It overwrites the six scaffolded schema files — `openspec/config.yaml`, `openspec/schemas/osq/schema.yaml`, `openspec/schemas/osq/README.md`, and `openspec/schemas/osq/templates/{proposal,spec,tasks}.md` — from the installed templates, so any local edits to those files are replaced. It leaves files that already match untouched, and it does not touch `osq.config.ts` or `.env.example`. Review or commit your diff first.
22
+
23
+ ## Upgrading
24
+
25
+ Resolver 2 changes the automated done-marker hashes for active changes. On the first watcher cycle after upgrading, a completed task in an active change whose `.run/done/<n>` lacks `scope_resolver: 2` is detected even when its recorded aggregate hash still matches. This is a one-time recertification wave: the watcher runs each affected task's `verify` at detection, writes one idempotent `.run/regressed/<n>.md` scope-regression marker carrying the recorded and current resolver versions, and halts the change. Review each marker and run `osq retry <id> <task>` to recertify that task explicitly; a passing verification refreshes the marker with resolver-2 hashes. Markers inside `openspec/changes/archive/` are not rewritten or audited by this migration.
18
26
 
19
27
  ## What it puts in your repo
20
28
 
29
+ `osq init` writes the files marked `*`; the rest appear as you plan and run changes.
30
+
21
31
  ```
22
- AGENTS.md your existing file, plus a managed block with the coding agent procedure
23
- osq.config.ts limits, paths, max concurrency
24
- specs/
25
- _template/ copied by `osq new`
26
- 042-order-cancellation/
27
- spec.md goal, contract, non-goals, and the delta to apply to feature docs
28
- tasks.md one checkbox per task, ticked by the watcher
29
- tasks/1.md the unit of work: acceptance, verify, scope, entry
30
- tasks/2.md
31
- .run/ approved (hash), running/, done/, dead/, results/, events/
32
- archive/ finished change folders, moved whole
33
- features/ one doc per feature, describes current behavior, always true of main
32
+ AGENTS.md * your existing file, plus a managed block: the executor protocol and a pointer for planners
33
+ PLANNER.md * the managed planner protocol
34
+ .claude/commands/ osq-plan.md *, the Claude Code planning command (slug as $ARGUMENTS)
35
+ osq.config.ts * harness selection; every limit, timeout, and gate has a default you can override here
36
+ .env.example * OSQ_HARNESS and API keys
37
+ openspec/
38
+ config.yaml * OpenSpec project configuration
39
+ schemas/osq/ * workflow schema and templates
40
+ queue.md optional brief queue read by `osq queue` and `osq plan --next`
41
+ specs/ living capability specifications (e.g. cli-foundation/spec.md)
42
+ changes/
43
+ 042-order-cancellation/
44
+ proposal.md parent spec: goal, verify, non-goals, contract, human steps, delta
45
+ plan-prompt.md the planning prompt `osq plan` writes; removed at archive
46
+ tasks.md task checklist, ticked by the watcher
47
+ tasks/1.md unit of work: acceptance, verify, scope, entry, tests.modify, verify_starts
48
+ tasks/2.md
49
+ specs/ delta specifications, one per capability the change writes
50
+ .run/ approved (hash), manifest.json, running/, done/, dead/, regressed/, results/, events/
51
+ archive/ finished change folders, moved whole
52
+ rejected/ rejected change folders, preserved with audit reason
34
53
  decisions/ ADRs, superseded not edited
35
- .env.example OSQ_HARNESS and API keys
36
54
  ```
37
55
 
38
56
  A change folder is a feature. A task is one unit of work for one agent. After approval the folder is read-only until every task is done or one is dead. State is which marker files exist under `.run/`, never a field in a document.
@@ -40,36 +58,76 @@ A change folder is a feature. A task is one unit of work for one agent. After ap
40
58
  ## The loop
41
59
 
42
60
  ```
43
- you + smart model write change folder -> specs/042-x/ with spec.md and tasks/
44
- you approve -> .run/approved
45
- watcher spawn per task -> cheap agent, fresh context, one attempt
61
+ you + smart model plan change folder -> osq plan <name> --brief <file> -> openspec/changes/042-x/ with plan-prompt.md
62
+ you lint / approve -> osq approve <id> -> .run/approved, .run/manifest.json
63
+ watcher spawn per task -> cheap agent, fresh context, capability rules injected
46
64
  agent work, write result -> .run/results/1.md, exit
47
65
  watcher verify, tick box -> .run/done/1 or .run/dead/1.md
48
- watcher last task done -> apply delta to features/, archive folder
49
- you next time -> osq status, look at dead
66
+ watcher last task done -> re-verify the final tree, merge deltas into openspec/specs/, archive
67
+ you next time -> osq (inbox) -> needs you, running, landed since last look
68
+ you fix / triage -> osq retry <id> <task|change> or osq reject <id> --reason <text>
50
69
  ```
51
70
 
52
71
  Smart models author specs and never execute them. Cheap models execute specs and never author them.
53
72
 
73
+ ## Gates and permissions
74
+
75
+ - **Approval gate.** Nothing runs until a human runs `osq approve`. It lints the change, hashes the folder, and writes `.run/approved` plus `.run/manifest.json`.
76
+ - **Approval digest.** Before sealing, `osq approve` prints a short digest: the goal, one line per task with its resolved-scope file count, and the requirements each delta adds, modifies, or removes. It then flags six things worth a human look: `shared_file` (a path two tasks share), `sensitive_path` (a package manifest, lockfile, CI workflow, osq or OpenSpec config, managed instruction file, or env file in scope), `verify_without_test` (a verify naming no test file or runner), `removed_requirement` (a delta that removes requirements), `unknown_capability` (a delta for a capability with no living spec), and `verify_starts_conflict` (a task that declares `green` or `any` while its verify names a missing test its own scope creates). Flags never block by default: they print last, as information, and the approval line names them (`Approved <id> with N flags: ...`). Add `--confirm` to stop and ask about them instead.
77
+ - **Verification gate.** The watcher never trusts the agent's claim. It runs each task's `verify` in its own process after the agent exits and writes `.run/done/<n>` only on exit 0; a non-zero exit becomes `.run/dead/<n>.md`.
78
+ - **Change verification after every task.** When the task's `verify` passes, the watcher also runs the proposal's change-level `verify` (`gates.changeVerifyAfterTask`, on by default). A red result kills the task with `change_verify_red`, so every task must leave the whole change green.
79
+ - **Pre-spawn verify check.** Before a task's first attempt, the watcher runs that task's `verify` once and expects it to fail: a verify already green before any agent work means the work is done or the verify does not exercise the task. A task declares its expected start with `verify_starts` — `red` by default, `green` for work like a refactor that should already pass, or `any` when either is fine. A mismatch warns by default and the task continues; `gates.preSpawnVerify: fail` kills the task with `verify_precondition` before the agent spawns, and `off` disables the check. A mismatch shows in the task's `verify_ran` event, `osq show`, and `osq report`. A named path the verify refers to that does not exist yet is recorded as `missingPaths` on that event and does not count as a mismatch for a `red` task. The check adds one extra verify per task, on its first attempt only.
80
+ - **Automatic retry.** When a task dies for a reason a fresh attempt could fix — `verify_red`, `change_verify_red`, `undeclared_test_change`, `verify_path_missing`, `no_result`, `crashed`, or `timeout` — the watcher retries it without asking. Every other reason (`spec_conflict`, `verify_precondition`, `already_running`) waits for you. `gates.autoRetries` caps how many automatic retries a task gets since its approval or its last manual retry; it defaults to 1, `0` turns automatic retries off entirely, and a manual `osq retry` grants one more. Each retry's prompt carries the previous dead marker's body, so the fresh agent sees exactly what failed.
81
+ - **Stuck tasks.** Every dead marker records a `fingerprint` over its reason and body, ignoring details a rerun changes: ISO timestamps, durations, PIDs, ANSI codes, and absolute paths under the project root. When a task dies again with the same fingerprint as its most recent retained death, the watcher stops retrying and marks it stuck — `stuck: true` on the active marker, one `stuck` event, one line. The inbox shows the task as stuck and `osq --json` gives its `task-dead` item a `stuck` field carrying the fingerprint; `osq retry <id> <n>` still retries it after you fix the cause.
82
+ - **Scope recertification.** Before each task and again before archiving, the watcher re-hashes the resolved `scope` of every done task. If a later task changed any of those files, it re-runs that task's `verify`, writes `.run/regressed/<n>.md`, and halts the change until you run `osq retry <id> <n>`.
83
+ - **Archive verification.** Before archiving, the watcher re-runs every task's `verify` and the change-level `verify` against the final tree, halting with `.run/regressed/<n>.md` (or `.run/regressed/change.md`) if any fails.
84
+ - **State from disk.** The only authoritative state is which marker files exist under `.run/`: `running/<n>.pid`, `done/<n>`, `dead/<n>.md`, `regressed/<n>.md`, and `approved`. There is no in-memory state that matters, so the watcher can be killed and restarted at any time.
85
+ - **Executor permissions.** A coding agent may write only `.run/results/<n>.md` and files inside its task's `scope`. It may not edit living capability specs, `tasks.md`, or marker files. The watcher writes markers and checkboxes automatically; a human writes the rest through `osq approve`, `osq retry`, `osq reject`, and `osq done`.
86
+
54
87
  ## Change folder
55
88
 
56
- `spec.md` is written for humans and the smart model:
89
+ `proposal.md` is written for humans and the smart model:
57
90
 
58
- ```yaml
91
+ ```markdown
59
92
  ---
60
93
  title: Order cancellation
61
- depends_on: [041]
94
+ depends_on: ["041"]
95
+ verify: pnpm test
62
96
  features:
63
- reads: [inventory-reservation]
64
- writes: [order-state-machine]
97
+ reads:
98
+ - inventory-reservation
65
99
  ---
66
100
  ## Goal
67
- ## Contract
101
+ ## Verify
68
102
  ## Non-goals
103
+ ## Surface
104
+ ## Contract
105
+ ## Human steps
69
106
  ## Delta
70
- What changes in each doc under features.writes. Applied by the watcher when the last task is done.
71
107
  ```
72
108
 
109
+ The frontmatter `verify` is the change-level command the watcher runs after every task and before archiving. Capability writes are not declared in frontmatter: the set of delta specs under `specs/<capability>/spec.md` is the authoritative declaration of what the change writes.
110
+
111
+ `## Surface` lists the user-facing names the change adds, changes, or removes — commands, flags, config keys, frontmatter fields, document sections, dead reasons, and event types; a change with none of those writes `None`.
112
+
113
+ A delta spec holds the exact text the capability spec will contain after the change, grouped under an OpenSpec operation heading:
114
+
115
+ ```markdown
116
+ # Spec Delta: Order State Machine
117
+
118
+ ## ADDED Requirements
119
+
120
+ ### Requirement: Cancellation handling
121
+ <!-- source: src/orders/cancel.ts -->
122
+ When an order is in PENDING state, cancellation SHALL release its reservation.
123
+
124
+ #### Scenario: Successful cancellation
125
+ - **WHEN** user requests cancellation for a pending order
126
+ - **THEN** status transitions to CANCELLED and reservation is released
127
+ ```
128
+
129
+ `## MODIFIED Requirements` repeats a requirement's full new text; `## REMOVED Requirements` and `## RENAMED Requirements` complete the set.
130
+
73
131
  `tasks/<n>.md` is what a coding agent gets:
74
132
 
75
133
  ```yaml
@@ -78,48 +136,64 @@ title: When a PENDING order is cancelled, its reservation is released
78
136
  verify: pnpm test -- orders/cancel
79
137
  scope: [src/orders/**, tests/orders/**]
80
138
  entry: [src/orders/service.ts]
139
+ tests:
140
+ modify: false # true lets the task change preexisting tests inside its scope
81
141
  skills: []
82
142
  ---
83
143
  ## Acceptance
84
- - [ ] each line is a test in disguise, max 7
144
+ - [ ] each line is a test in disguise
85
145
  ```
86
146
 
87
- Tasks run in order. The agent reads its task, the parent `spec.md`, the docs under `features.reads` and `features.writes`, AGENTS.md, and a previous result file for that task if there is one. Nothing else. The delta is applied by the watcher, so the agent never edits feature docs.
147
+ Tasks run in order. The agent reads its task, the parent `proposal.md`, the delta specs and capability docs it names, `AGENTS.md`, and a previous result file for that task if there is one. The runner also injects capability-specific constraints and code ownership rules extracted from living capability specs. The delta is applied by the watcher, so the agent never edits living specs under `openspec/specs/`.
148
+
149
+ Lint, run by `osq approve` and `osq lint`. Limits come from `osq.config.ts`; defaults are shown.
88
150
 
89
- Lint, run by `osq approve`:
151
+ | Check | Result |
152
+ | --- | --- |
153
+ | proposal has no `verify` in frontmatter | reject |
154
+ | proposal declares `features.writes` | reject |
155
+ | more than one table under `## Contract` | reject |
156
+ | `depends_on` names a missing change | reject |
157
+ | task `scope` has more than 8 patterns (`limits.maxScopeFiles`) | reject |
158
+ | task acceptance longer than 7 lines (`limits.maxAcceptanceLines`), or two lines fused into one | reject |
159
+ | task scope names a preexisting test without `tests.modify: true` | reject |
160
+ | task `verify` empty or chains commands | reject |
161
+ | `verify` is the planning sentinel | reject |
162
+ | `verify` names an absent package script | reject |
163
+ | `verify` names no existing path or package script | warn |
164
+ | a delta targets a requirement the living spec lacks, or is written as an instruction | reject |
165
+ | a file contains a prohibited control character | reject |
166
+ | OpenSpec schema or validator drift | reject |
167
+ | two tasks resolve the same scope file | warn |
90
168
 
91
- | Check | Result |
92
- |---------------------------------------------|--------|
93
- | task `scope` has more than 8 patterns | reject |
94
- | `features.writes` has more than 2 entries | reject |
95
- | more than one table under `## Contract` | reject |
96
- | task `verify` empty or chains commands | reject |
97
- | `depends_on` names a missing change | reject |
98
- | task acceptance longer than 7 lines | reject |
99
- | `## Delta` empty while `features.writes` is not | reject |
100
- | task title contains " and " | warn |
169
+ `osq init` and `osq new` seed `verify: node -e "process.exit(0)"`. That is a planning sentinel, not trusted coverage: replace it before approval with a command that verifies the completed change's final tree. Checked-in fixtures use a local `node verify.cjs` verifier backed by files in their own execution root, never the sentinel, the network, a TTY, or this repository's full verification suite.
101
170
 
102
- Rules the lint can't check: title reads "when X, Y happens"; slice vertically so every spec leaves `main` green on its own; no "investigate" or "decide" in a spec (that's a spike, whose output is a paragraph in a feature doc or an ADR); default to a parent with children and approve the list before writing any child in full.
171
+ The rules lint can't check live in the managed `PLANNER.md` block: titles read "When X, Y"; every task leaves the change green on its own; a file belongs to one task; approve the task list before writing any task in full.
103
172
 
104
173
  ## What the watcher guarantees
105
174
 
106
- - State is rebuilt from `specs/` on every change. Kill it and restart it any time.
107
- - One agent per spec: locks are created exclusively, stale locks (dead pid or timeout) are reaped to `dead/`.
108
- - What runs is what was approved: `.run/approved` holds a hash of the folder minus `.run/` (with `tasks.md` checkbox state normalized), checked before every spawn.
109
- - `done` means the watcher ran `verify` itself in a timeout-bounded process group after the agent exited. The agent's claim is not enough.
110
- - Feature docs are only ever changed by the watcher applying an approved delta. Agents never touch `features/`.
111
- - The agent prompt protocol restricts write paths to `.run/results/` and edits to `scope`. All markers and checkboxes are written by the watcher.
112
- - An agent that exits without writing `.run/results/<n>.md` is not lost: if the adapter captured a final text message, the watcher synthesizes a result file (`synthesized: true`) from it and proceeds to verify. Only an exit with neither a result file nor final text is `dead` with `reason: no_result`. Nothing disappears silently.
175
+ - **Rebuilt from disk**: State is rebuilt from `openspec/` on every change. Kill it and restart it any time.
176
+ - **Single active agent**: One agent per change: locks are created exclusively, and stale locks (dead pid or timeout) are reaped to `dead/`.
177
+ - **Approved integrity & Manifest**: What runs is what was approved. `.run/approved` holds a hash of the folder minus `.run/` (with `tasks.md` checkbox state normalized), checked before every spawn. Approval generates `.run/manifest.json` recording hashes of `AGENTS.md`, `PLANNER.md`, configuration, and touched capability specs, along with runtime environment metadata.
178
+ - **Stale build detection**: In repository checkouts, the watcher verifies that compiled `dist/` is up-to-date with `src/`. If source files have changed without rebuilding, the watcher refuses to run unless `--allow-stale` or `--dev` is specified.
179
+ - **Prompt rule injection**: Living capability specs declare explicit code ownership (`### Requirement: Code ownership`). The runner extracts these boundaries and injects capability rules directly into the executor prompt.
180
+ - **Test modification gating**: Before spawning, the runner snapshots every preexisting file under `tests/`. A changed or deleted one kills the task with `reason: undeclared_test_change` unless the task declares `tests.modify: true` and its scope contains that file. New test files are always allowed.
181
+ - **Raw measures events**: Every task start and end emits a `measures` event capturing files/lines under scope, files/lines changed, repository baselines, file import counts, word counts, and requirement/scenario counts.
182
+ - **Deterministic spec merges**: Capability specs are only ever changed by the watcher applying an approved delta merge (ADR 002). Agents never touch `openspec/specs/`.
183
+ - **Synthesized results**: An agent that exits without writing `.run/results/<n>.md` is not lost: if the adapter captured a final text message, the watcher synthesizes a result file (`synthesized: true`) from it and proceeds to verify. Only an exit with neither a result file nor final text is `dead` with `reason: no_result`. Nothing disappears silently.
113
184
 
114
- Reasons emitted: `verify_red` (with `timed_out: true` if verify exceeded timeout), `spec_conflict`, `already_running`, `no_result` (no result file and no final text), `crashed`, `timeout`.
185
+ Dead reasons: `verify_red` (with `timed_out: true` if verify exceeded its timeout), `change_verify_red`, `verify_precondition`, `undeclared_test_change`, `verify_path_missing` (a path the task's `verify` names did not exist after the agent exited), `no_result`, `crashed`, `timeout`, `spec_conflict`, and `already_running`. A done task whose scoped files changed afterwards is recorded under `.run/regressed/<n>.md` with `reason: scope_regression`, and a failed archive-time change verify under `.run/regressed/change.md`; either stops the run before the next task spawns. Every dead marker also carries a `fingerprint` of its reason and body, and a marker the watcher stopped retrying carries `stuck: true`.
115
186
 
116
187
  ## Harnesses
117
188
 
118
- `OSQ_HARNESS` picks an adapter. An adapter does two things: spawn an agent for a tier (`coding` or `smart`) and write its harness's config files (`osq setup`). Adapters translate the harness's own event stream into six events (`started`, `tokens`, `file_changed`, `verify_ran`, `result_written`, `exited`), appended to the task's `.run/events/<n>.jsonl`. Hooks are optional shims that append to the same file. The loop works without them.
189
+ `OSQ_HARNESS` picks an adapter. An adapter does two things: spawn an agent for a tier (`coding` or `smart`) and write its harness's config files (`osq setup`). Adapters translate the harness's own event stream into typed events (`started`, `tokens`, `tool`, `text`, `file_changed`, `result_written`, `exited`), and the watcher appends its own (`measures`, `verify_ran`, `done`, `done_manual`, `dead`, `regressed`, `retry`, `recertification`, `rejected`), all to the task's `.run/events/<n>.jsonl`. Hooks are optional shims that append to the same file. The loop works without them.
119
190
 
120
191
  Available adapters:
192
+
121
193
  - `agy`: Antigravity harness adapter
194
+ - `codex`: Codex CLI harness adapter running tasks via `codex exec` and planning via the Codex TUI
122
195
  - `opencode`: OpenCode harness adapter running tasks via `opencode run`
196
+ - `pi`: Pi coding agent harness adapter running fresh one-shot tasks in JSON mode
123
197
  - `mock`: In-memory deterministic simulation for tests
124
198
 
125
199
  Configure `opencode` in `osq.config.ts`:
@@ -138,44 +212,313 @@ export default defineConfig({
138
212
  });
139
213
  ```
140
214
 
141
- Running `osq setup` with the `opencode` harness scaffolds `.opencode/agent/osq-coder.md` with restricted permissions (denying `webfetch` and `websearch`) and the managed `AGENTS.md` execution procedure. Note that the `--auto` flag approves any action the agent file does not deny. The agent file must have mode `all` or `primary`; a subagent cannot be selected with --agent and OpenCode silently falls back to an unrestricted default. `webfetch` and `websearch` are denied at the tool level, but `bash` is allowed and unrestricted, so the agent can reach the network through the shell. Network isolation requires a sandbox and is listed under "Not yet".
215
+ Running `osq setup` with the `opencode` harness scaffolds `.opencode/agent/osq-coder.md` with restricted permissions (denying `webfetch` and `websearch`) and the managed `AGENTS.md` execution procedure. Note that the `--auto` flag approves any action the agent file does not deny. The agent file must have mode `all` or `primary`; a subagent cannot be selected with --agent and OpenCode silently falls back to an unrestricted default. `webfetch` and `websearch` are denied at the tool level, but `bash` is allowed and unrestricted, so the agent can reach the network through the shell. Network isolation requires a sandbox, which osq does not provide.
216
+
217
+ ### Codex CLI
218
+
219
+ Select Codex as the executor in `osq.config.ts`:
220
+
221
+ ```ts
222
+ import { defineConfig } from '@matteeh/osq';
223
+
224
+ export default defineConfig({
225
+ harness: 'codex',
226
+ codex: {
227
+ // All fields are optional; omit any of them to use Codex's native value.
228
+ // bin: '/path/to/codex', // codex.bin -> CODEX_PATH -> `codex`
229
+ // model: '<your-model>', // codex.model -> OSQ_MODEL (Codex executor only) -> native
230
+ // effort: '<your-effort>', // codex.effort -> native default
231
+ },
232
+ });
233
+ ```
234
+
235
+ Setting `OSQ_HARNESS=codex` in the environment or `.env` also selects Codex, but an explicit `harness` in `osq.config.ts` wins over that fallback. Binary precedence is `codex.bin`, then `CODEX_PATH`, then `codex` on `PATH`. Model precedence is `codex.model`, then `OSQ_MODEL` only when Codex is the executor, then Codex's native default; `effort` is `codex.effort` or the native default. With no model configured, osq records `default` rather than guessing one.
236
+
237
+ Planning can use a different harness and model from execution:
238
+
239
+ ```ts
240
+ export default defineConfig({
241
+ harness: 'opencode',
242
+ planner: {
243
+ harness: 'codex',
244
+ model: '<your-planner-model>', // required, must be non-empty
245
+ // agent is unsupported for codex; config validation rejects it.
246
+ },
247
+ });
248
+ ```
249
+
250
+ Codex has no planner-agent concept, so `planner.agent` is unsupported and `defineConfig` rejects it with a clear error rather than ignoring it. An explicit `planner` block never inherits the executor's `OSQ_MODEL` or effort; when planning falls back to a Codex executor, the brief records `default` and no model flag is passed to Codex.
251
+
252
+ #### Codex setup and prerequisites
253
+
254
+ Install the Codex CLI and authenticate it in the same host environment where osq runs. osq reuses Codex's native authentication and configuration; it never reads, writes, or manages your credentials or bypasses Codex policies. `osq setup` for Codex generates no Codex-specific files: it only maintains the shared managed `AGENTS.md` block and preserves foreign blocks, because Codex uses the same executor protocol as every other harness.
255
+
256
+ `osq doctor` probes the configured binary with `--version` using the same resolution as the adapter, and the watcher runs the same preflight before the first task. A missing, nonzero, or timed-out probe fails clearly before any task executes.
257
+
258
+ #### Codex permissions
259
+
260
+ Executor tasks run a fresh noninteractive process per task in the project root with `--ask-for-approval never` and `--sandbox workspace-write`, web search disabled, and workspace shell network access disabled. There is no session resume, `--auto`, or permission-bypass flag, and the prompt is passed as one literal argument.
261
+
262
+ Interactive planning launches the Codex TUI with `--ask-for-approval on-request` and `--sandbox workspace-write`, using Codex's native reasoning-effort default rather than the executor's `codex.effort`.
263
+
264
+ As with every harness, scope is a protocol, not hard confinement: the prompt and the watcher's checks restrict the agent to its declared files, but they do not sandbox the filesystem or network beyond what the harness itself enforces. osq does not provide OS or container confinement.
265
+
266
+ #### Codex observations and costs
267
+
268
+ Each task is a fresh Codex session; osq never resumes a prior conversation. The watcher, not the adapter, owns result files, markers, checkboxes, and independent verification: if Codex exits without writing a result, the watcher synthesizes one from the final completed assistant message and still runs `verify` itself before writing `done`. Token counts come only from usage Codex actually reports (`turn.completed`), broken down into observed input, output, cached, and reasoning tokens; osq does not estimate usage or cost, and it reports cost only when the harness supplies it.
269
+
270
+ #### Live Codex smoke check (optional, human-owned)
271
+
272
+ Offline tests use a deterministic fake Codex executable and require no authentication, network access, or model. A separate optional live check, after installing and authenticating the real CLI, is to run one harmless approved fixture task and one interactive planning session, then confirm the watcher's verification, the emitted events and result file, harness/model attribution, and clean exits. Record the CLI version you tested; the offline suite does not establish a minimum supported Codex release.
273
+
274
+ ### Pi
275
+
276
+ Select Pi as the executor in `osq.config.ts`:
277
+
278
+ ```ts
279
+ import { defineConfig } from '@matteeh/osq';
280
+
281
+ export default defineConfig({
282
+ harness: 'pi',
283
+ pi: {
284
+ // All fields are optional; omit any of them to use Pi's native value.
285
+ // bin: '/path/to/pi', // pi.bin -> OSQ_PI_PATH -> `pi`
286
+ // provider: '<provider>', // required only to run `pi auth check` before execution
287
+ // model: '<your-model>', // pi.model -> OSQ_MODEL (Pi executor only) -> native
288
+ // thinking: '<effort>', // pi.thinking -> native default
289
+ },
290
+ });
291
+ ```
292
+
293
+ Setting `OSQ_HARNESS=pi` in the environment or `.env` also selects Pi, but an explicit `harness` in `osq.config.ts` wins over that fallback. Binary precedence is `pi.bin`, then `OSQ_PI_PATH`, then `pi` on `PATH`. Model precedence is `pi.model`, then `OSQ_MODEL` only when Pi is the executor, then Pi's native default; with no model configured, osq records `default` rather than guessing one. `pi.thinking` is passed as Pi's `--thinking` level and recorded as the execution effort, or null when unset.
294
+
295
+ Install Pi with `npm install -g @earendil-works/pi-coding-agent`. This release is tested against `>=0.87.0 <0.88.0`; `osq doctor` reports a `harness-version` warning and the watcher warns at preflight when the installed version falls outside that range, but neither fails. When `pi.provider` is set, preflight runs `pi auth check --provider <name> --json` and fails before any task spawns unless the status is `ready`; `osq doctor` reports the same as its `harness-auth` check.
296
+
297
+ #### Pi setup and prerequisites
298
+
299
+ `osq setup` writes no Pi files, because Pi reads `AGENTS.md` itself, so the shared managed executor protocol reaches it without a harness-specific config. Pi loads only the first of `AGENTS.override.md`, `AGENTS.md`, and `CLAUDE.md` in each directory, so an `AGENTS.override.md` in your project would shadow the managed `AGENTS.md` and hide the executor protocol; do not add one if you want Pi to follow osq.
300
+
301
+ #### Pi permissions
302
+
303
+ Each task is a fresh noninteractive process in the project root with stdin closed. osq passes `--mode json --no-session --no-approve --offline --no-extensions --no-skills --no-prompt-templates`, then `--provider`, `--model`, and `--thinking` for the settings you configured, then `--` and the executor prompt as one literal argument. Extensions, skills, and prompt templates are off, so no consumer-supplied Pi customization runs. Pi applies no filesystem sandbox and asks no permission prompts, and its network access stays open.
304
+
305
+ As with every harness, scope is a protocol, not confinement: the prompt and the watcher's checks restrict the agent to its declared files, but they do not confine the filesystem or network beyond what Pi itself enforces. osq does not provide OS or container isolation.
306
+
307
+ Pi cannot plan: the adapter has no interactive session, so `osq plan --session` with Pi selected as the planner stops with the existing "does not support interactive sessions" error, and `planner.agent` is unsupported for Pi and rejected by configuration validation.
142
308
 
143
309
  ## Commands
144
310
 
145
311
  ```
146
- osq init scaffold
147
- osq setup write harness config for OSQ_HARNESS
148
- osq new <name> new change folder from the template
149
- osq watch run the watcher
150
- osq approve <id>.. lint, hash, approve. also re-approves after fixing a dead task
151
- osq status every change and task with its state
152
- osq show <id> spec, tasks, results, dead markers, event timeline
153
- osq report completion rate, dead by reason, cost and time per task
312
+ osq human attention inbox: needs you, running, landed since last look
313
+ osq --json print human attention inbox as stable JSON
314
+ osq init scaffold openspec layout, config, AGENTS.md, PLANNER.md, and the Claude plan command
315
+ osq init --refresh-schema overwrite the six scaffolded OpenSpec schema files from the installed templates
316
+ osq setup write harness config for OSQ_HARNESS
317
+ osq new <name> new change folder from template in openspec/changes/
318
+ osq plan [name] create a change, write plan-prompt.md, and hand off to your planning tool
319
+ osq queue print the read-only brief queue from openspec/queue.md
320
+ osq lint [ids...] validate change folders and OpenSpec artifacts against constraints
321
+ osq approve <ids...> lint, print the digest, approve change; write .run/approved and .run/manifest.json
322
+ osq retry <id> <target> retry a dead or regressed task, or a change-level regression
323
+ osq reject <id> move an unapproved or failed change intact into rejected history
324
+ osq done <id> <task> mark a task done manually with required justification (--manual)
325
+ osq watch run the watcher loop
326
+ osq status overview of all changes, tasks, and runtime states
327
+ osq show <id> change details, tasks, results, dead markers, and event timeline (--json for JSON)
328
+ osq report delivery metrics, completion rates, failure reasons, durations, and costs
329
+ osq serve [--port <n>] local read-only delivery dashboard on 127.0.0.1 (--open to launch it)
330
+ osq serve --export <dir> write a static dashboard snapshot to <dir> and exit
331
+ osq doctor validate repository health, harness availability, and pinned validator
332
+ osq migrate openspec migrate a legacy osq layout to the canonical openspec/ layout
154
333
  ```
155
334
 
156
- `osq report` renders completion rate, failures by reason, execution durations, token usage, and file changes. Reported cost sums the `cost` values carried by harness events. Reported cost reflects the harness's internal price table rather than the invoice.
335
+ ### Approval
336
+
337
+ ```sh
338
+ osq approve <id> --confirm # show the digest, then ask about any flags before sealing
339
+ osq show <id> --json # details, tasks, events, and the digest as JSON
340
+ ```
341
+
342
+ By default `osq approve` prints the digest and its flags, then approves without
343
+ asking; flags never block. `--confirm` asks only when flags fire, defaults to no,
344
+ and refuses without a terminal rather than waiting. A declined or refused approval
345
+ writes nothing, and `--confirm` on a flag-free change approves without a prompt.
346
+ `osq show <id> --json` prints the same details as JSON, with the digest and flags
347
+ for an unapproved change and a null digest once it is approved.
348
+
349
+ ### Human Attention Inbox
350
+
351
+ Running bare `osq` serves as the entrypoint for human attention:
352
+
353
+ - **Needs you**: unapproved proposals, active dead tasks, active regressed tasks, and change-level regressions, each ending with its exact action command (`osq approve <id>`, `osq retry <id> <n>`, or `osq reject <id> --reason <text>`). A dead task the watcher stopped retrying shows as stuck, and its `task-dead` item in `osq --json` carries an optional `stuck` field (`stuck: { fingerprint }`) that no other item has.
354
+ - **Running**: actively executing tasks with verified live PID, start time, and elapsed duration.
355
+ - **Landed since last look**: changes archived strictly after your project's previous look (tracked per project in `~/.osq/last-look/`), or the newest 10 on first look.
356
+
357
+ Use `osq --json` to consume this contract programmatically without extra terminal formatting.
358
+
359
+ ### Planning
360
+
361
+ Planning is prompt handoff by default: osq writes the complete five-section
362
+ opening prompt to `plan-prompt.md` in the change folder and hands off to the
363
+ tool you already use.
364
+
365
+ ```sh
366
+ osq plan <name> --brief <file> # create the change, write plan-prompt.md, and print the handoff line
367
+ osq plan --next # same handoff for the first eligible item in openspec/queue.md
368
+ osq plan --next --replan # allow replanning a rejected first eligible queue item
369
+ ```
370
+
371
+ The default path constructs and spawns no harness: it writes an exact prompt
372
+ file, records `planner: null` in `brief.md`, and prints one line containing the
373
+ folder path and `ask your planning tool to plan change <slug>`. Ask that tool to
374
+ plan the change.
375
+
376
+ `init` installs the planning entry points that consume the prompt:
377
+
378
+ - Claude Code reads `.claude/commands/osq-plan.md`, which takes the change slug
379
+ as its `$ARGUMENTS` argument and reads `plan-prompt.md`.
380
+ - Codex and other tools that read `AGENTS.md` find its `Planning a change`
381
+ section, which sends planners to `PLANNER.md` and names `plan-prompt.md` as
382
+ the complete prompt when `osq plan` started the session.
383
+
384
+ The managed `PLANNER.md` block covers both interactive planning and the handoff.
385
+ Every entry point tells the tool to write only inside the change folder, run
386
+ `osq lint <slug>` and fix every finding, and never run `osq approve`.
387
+
388
+ Model choice belongs to the planning tool unless osq is explicitly asked to
389
+ launch the session, so the generated `osq.config.ts` contains no required
390
+ planner model. Explicit session and print modes remain available:
391
+
392
+ ```sh
393
+ osq plan <name> --brief <file> --session # launch the configured planner in the terminal
394
+ osq plan <name> -p, --print # emit the prompt to stdout only; no file, process, or record
395
+ ```
396
+
397
+ `--session` restores the osq-owned interactive planner: it selects the
398
+ configured planner exactly as before, attributes the brief to that model, and
399
+ records the owned lifecycle and usage. Planner `harness`, `model`, and `agent`
400
+ validation applies only there. `--print` emits the same prompt bytes to stdout
401
+ without writing `plan-prompt.md`, spawning a process, or recording telemetry.
402
+
403
+ When you run `osq approve <id>`, osq observes local Codex, OpenCode, and Claude
404
+ Code sessions whose file edits fall inside the change folder during its
405
+ lifetime and records any matches as observed planning sessions. Each session is
406
+ cut into per-turn slices, so one long session planning several changes is no
407
+ longer counted once per change. Every turn goes to exactly one change: a turn
408
+ that edits a change folder belongs to it, and any other turn goes to the next
409
+ change edited before the next approval, or else to the change approved next.
410
+ Per-turn tokens are what each reader actually reports — Claude Code message
411
+ usage, Codex `token_count`, and OpenCode messages — and input excludes cached
412
+ input. A Claude `cost-state` cost counts only for a slice that holds the whole
413
+ session. osq never estimates missing values, never retains transcript content,
414
+ and never sends anything off the machine.
415
+
416
+ The `planning.idleGapMinutes` and `planning.prices` keys are configured in
417
+ `osq.config.ts`:
418
+
419
+ ```ts
420
+ import { defineConfig } from '@matteeh/osq';
421
+
422
+ export default defineConfig({
423
+ planning: {
424
+ idleGapMinutes: 10, // a longer gap between turns is not active planning
425
+ prices: {
426
+ // USD per million tokens; osq ships no price table of its own.
427
+ '<provider>/<model>': { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
428
+ },
429
+ },
430
+ });
431
+ ```
432
+
433
+ A slice gets a price-table cost only when every turn's model is priced and
434
+ reported input and output tokens.
435
+
436
+ ### Retry & Rejection
437
+
438
+ ```sh
439
+ osq retry <id> <task> # retry a dead task or recertify a regressed one (e.g. osq retry 042 1)
440
+ osq retry <id> change # clear an active change-level regression after fixing root cause
441
+ osq reject <id> --reason <text> # move an unapproved or failed change to openspec/changes/rejected/
442
+ osq done <id> <task> --manual "<reason>" # manually satisfy a task with required reason
443
+ ```
444
+
445
+ ### Watcher options
446
+
447
+ ```sh
448
+ osq watch # run watcher event loop continuously
449
+ osq watch -o, --once # process all queued approved tasks and exit
450
+ osq watch --dev # reactive dev mode running directly from src/ via tsx with auto-restart
451
+ osq watch --allow-stale # allow running from repository checkout when dist/ is older than src/
452
+ osq watch --verbose # enable verbose execution logging
453
+ osq watch -q, --quiet # suppress info and verbose output
454
+ ```
455
+
456
+ ### Metrics & Reporting
457
+
458
+ ```sh
459
+ osq report # formatted terminal report
460
+ osq report --json # raw JSON report for scripting and CI pipelines
461
+ ```
462
+
463
+ `osq report` renders completion rate, failures by reason, execution durations, token usage, and file changes. The `Planning by change` section shows each change's sessions, tokens by kind, cost, active minutes, spec words, changed lines, and spec words per changed line, plus the minutes from its last planning edit to approval; active minutes sum the gaps between a slice's turns and leave out any gap longer than `planning.idleGapMinutes`. The `Planning vs execution` section compares planning and executor tokens and cost. Reported cost sums the `cost` values carried by harness events, and any cost that no attempt or session reported reads `not reported` instead of a dollar amount. Reported cost reflects the harness's internal price table rather than the invoice. The `Approval flags` section counts, per flag and for changes that recorded none, how many changes fired it and how many later had trouble (a dead task or a regression), split by whether the flags were only shown or confirmed with `--confirm`; it counts only changes approved after this release, because older manifests carry no recorded flags and are skipped. The `Automatic retries` section counts automatic and manual retries, how many of the attempts they opened reached done, the `stuck` events, and the harness-reported cost of those attempts.
464
+
465
+ ### Delivery Dashboard
466
+
467
+ ```sh
468
+ osq serve # local dashboard at the configured serve.port, default http://127.0.0.1:4173/
469
+ osq serve --port 0 # ask the OS for an ephemeral loopback port
470
+ osq serve --open # launch the printed URL in the default browser
471
+ osq serve --export ./demo # write a static snapshot to ./demo and exit without serving
472
+ ```
473
+
474
+ `osq serve` starts a Node HTTP server bound only to `127.0.0.1` and prints its
475
+ exact URL. The CLI `--port` option overrides `serve.port` from `osq.config.ts`;
476
+ `--port 0` requests an operating-system-assigned port, and only integers from 0
477
+ through 65535 are accepted. `--open` launches the printed URL through the
478
+ platform's default browser without adding a runtime dependency.
479
+
480
+ `osq serve --export <dir>` writes a self-contained snapshot of every dashboard
481
+ view into an empty or missing `<dir>` and exits 0 without binding a port or
482
+ opening a browser. The snapshot needs a static host and cannot be opened
483
+ directly from `file://`, and it scrubs only the project root and home directory
484
+ paths, so read the export before publishing it.
485
+
486
+ The dashboard is one hash-routed read-only page: `#/report` renders delivery
487
+ charts, `#/graph` renders the capability archive graph, and `#/changes/<key>`
488
+ renders detailed change evidence. Every request recomputes its document from
489
+ the current filesystem and keeps no cache, and the page treats filesystem
490
+ notifications only as a signal to refetch. It uses system fonts, same-origin
491
+ requests, and no external asset, and respects `prefers-color-scheme`.
492
+
493
+ `osq serve` is for local inspection only. It has no write endpoint, no
494
+ authentication, no remote binding, and no hosting story; it never starts the
495
+ execution watcher or writes project, cursor, or marker files. SIGINT and SIGTERM
496
+ close the HTTP listener and its filesystem watcher. Startup failures such as an
497
+ address already in use print one actionable error and exit nonzero.
498
+
499
+ ## Diagnostics & Health
500
+
501
+ Run `osq doctor` to verify repository health:
502
+
503
+ - `config`: confirms `osq.config.ts` is valid and well-formed
504
+ - `harness`: checks that the configured harness binary (e.g. `opencode`, `agy`) exists and is executable
505
+ - `harness-version`, `harness-auth`: Pi's extra checks (only when Pi is selected) warn on an untested Pi version and, with `pi.provider` set, fail unless `pi auth check` reports `ready`
506
+ - `managed-blocks`: verifies the `AGENTS.md`, `PLANNER.md`, and `.claude/commands/osq-plan.md` managed sections match the installed osq version (run `osq init` to repair drift)
507
+ - `locks`: checks for orphaned `.run/running/*.pid` locks and processes
508
+ - `archives`: validates integrity of archived change folders
509
+ - `done-markers`: flags any done marker in an active change that neither the watcher nor `osq done --manual` wrote
510
+ - `validator`: ensures `@fission-ai/openspec` is installed and matches the pinned version (`1.13.1`)
157
511
 
158
512
  ## Release Procedure
159
513
 
160
514
  To release a new version of `osq`:
515
+
161
516
  1. Bump `"version"` in `package.json`.
162
517
  2. Add a corresponding release section in `CHANGELOG.md`.
163
518
  3. Commit the changes: `git commit -am "release: v<x.y.z>"`.
164
519
  4. Create and push the release tag: `git tag v<x.y.z> && git push --tags`.
165
520
  5. GitHub Actions (`release.yml`) verifies the build and publishes to npm with provenance via trusted publishing.
166
521
 
167
- ## Not yet
168
-
169
- Decided but deliberately unbuilt until the loop has closed on real work:
170
-
171
- - Concurrency above 1, with a worktree per running task and merge on done (`reason: merge_conflict`).
172
- - Hard OS/container sandbox confinement enforcing `scope` boundaries and filesystem write limits (`reason: scope_violation`).
173
- - Pre-spawn dependency and context verification checks (`reason: missing_dep`, `reason: missing_context`).
174
- - Deterministic section-level replacement for feature doc deltas (ADR 002).
175
- - Containerized coding agents.
176
- - A derived SQLite index under `~/.osq/` for `status` and `report` across projects. Files stay the source of truth; the index is gitignored and can be deleted at any time.
177
- - Hook shims for harnesses, and `osq import` for OpenSpec change folders.
178
-
179
522
  ## Status
180
523
 
181
524
  Early. Written in TypeScript so `npx` is the whole install and the glue (spawning, JSON streams, file watching, git) stays short; the filesystem protocol means the watcher could be rewritten in another language later without consumers noticing. Numbers in `osq.config.ts` are guesses until `osq report` says otherwise. See `decisions/` for why things are the way they are.
@@ -1,6 +1,16 @@
1
- import { type OsqConfig } from '../core/config.js';
2
- export declare function approveCommand(specIds: string[], options?: {
1
+ import { type OsqConfig } from '../core/foundation/config.js';
2
+ import type { PlanningSessionReader } from '../core/report/planning-observed.js';
3
+ export interface ApproveCommandOptions {
3
4
  cwd?: string;
4
5
  config?: OsqConfig;
5
- }): Promise<void>;
6
+ planningReaders?: readonly PlanningSessionReader[];
7
+ now?: Date | string;
8
+ /** Block on flagged approvals by asking before the seal is written. */
9
+ confirm?: boolean;
10
+ /** Injectable terminal check; defaults to both stdio streams being TTYs. */
11
+ isTerminal?: () => boolean;
12
+ /** Injectable prompt; defaults to a `node:readline/promises` question. */
13
+ ask?: (question: string) => Promise<string | null>;
14
+ }
15
+ export declare function approveCommand(specIds: string[], options?: ApproveCommandOptions): Promise<void>;
6
16
  //# sourceMappingURL=approve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"approve.d.ts","sourceRoot":"","sources":["../../src/cli/approve.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,mBAAmB,CAAC;AAE/D,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAAO,GACjD,OAAO,CAAC,IAAI,CAAC,CAuBf"}
1
+ {"version":3,"file":"approve.d.ts","sourceRoot":"","sources":["../../src/cli/approve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,8BAA8B,CAAC;AAE1E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAajF,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,eAAe,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACnD,GAAG,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IACpB,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAC3B,0EAA0E;IAC1E,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACpD;AA0BD,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAsDf"}