coding-os 0.3.2__py3-none-any.whl

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 (1304) hide show
  1. adapters/claude/README.md +6 -0
  2. adapters/claude/_install_helpers/extract_stacks.py +43 -0
  3. adapters/claude/_install_helpers/update_mcp_json.py +75 -0
  4. adapters/claude/adapter.yaml +164 -0
  5. adapters/claude/hooks/README.md +40 -0
  6. adapters/claude/hooks/agent_memory_sync.py +131 -0
  7. adapters/claude/hooks/ensure-agent-memory-link.sh +36 -0
  8. adapters/claude/hooks/sync-agent-memory.sh +21 -0
  9. adapters/claude/install.sh +86 -0
  10. adapters/claude/sdk_dispatcher.py +871 -0
  11. adapters/claude/settings.local.template.json +31 -0
  12. adapters/claude/settings.template.json +808 -0
  13. adapters/claude/update_mcp_json.py +85 -0
  14. adapters/codex/adapter.yaml +254 -0
  15. adapters/codex/chat_provider.py +230 -0
  16. adapters/codex/commands/formula-f1.md +129 -0
  17. adapters/codex/commands/formula-f10.md +100 -0
  18. adapters/codex/commands/formula-f11.md +123 -0
  19. adapters/codex/commands/formula-f2.md +139 -0
  20. adapters/codex/commands/formula-f3.md +127 -0
  21. adapters/codex/commands/formula-f4.md +101 -0
  22. adapters/codex/commands/formula-f5.md +135 -0
  23. adapters/codex/commands/formula-f6.md +147 -0
  24. adapters/codex/commands/formula-f7.md +111 -0
  25. adapters/codex/commands/formula-f8.md +133 -0
  26. adapters/codex/commands/formula-f9.md +112 -0
  27. adapters/codex/enable_codex_hooks.py +94 -0
  28. adapters/codex/ensure_codex_mcp.py +124 -0
  29. adapters/codex/hooks/codex-merge-hook-output.py +72 -0
  30. adapters/codex/hooks/codex-normalize-edit.py +96 -0
  31. adapters/codex/hooks/codex-postedit-dispatch.sh +75 -0
  32. adapters/codex/hooks/codex-posttool-dispatch.sh +70 -0
  33. adapters/codex/hooks/codex-preedit-dispatch.sh +83 -0
  34. adapters/codex/hooks/codex-pretool-dispatch.sh +82 -0
  35. adapters/codex/hooks/codex-sessionend-dispatch.sh +20 -0
  36. adapters/codex/hooks/codex-sessionstart-dispatch.sh +68 -0
  37. adapters/codex/hooks/codex-stop-dispatch.sh +73 -0
  38. adapters/codex/hooks/codex-userpromptsubmit-dispatch.sh +74 -0
  39. adapters/codex/hooks.template.json +208 -0
  40. adapters/codex/install.sh +83 -0
  41. adapters/codex/sdk_dispatcher.py +449 -0
  42. board_os/__init__.py +39 -0
  43. board_os/_agent_runtime.py +256 -0
  44. board_os/config.py +421 -0
  45. board_os/git_coherence.py +107 -0
  46. board_os/hub_adapter_manifest.py +140 -0
  47. board_os/mcp_tools.py +3228 -0
  48. board_os/migration.py +166 -0
  49. board_os/parser.py +317 -0
  50. board_os/presence.py +156 -0
  51. board_os/sync.py +320 -0
  52. board_os/transition_gates.py +224 -0
  53. board_os/transition_gates_cli.py +272 -0
  54. board_os/transition_gates_validator.py +551 -0
  55. board_os/verify_suites.py +126 -0
  56. board_os/verify_suites_cli.py +328 -0
  57. board_os/workflow.py +967 -0
  58. cli/__init__.py +0 -0
  59. cli/_data_types.py +248 -0
  60. cli/_init_helpers.py +587 -0
  61. cli/_resources.py +100 -0
  62. cli/adapter_registry.py +239 -0
  63. cli/add_stack.py +315 -0
  64. cli/aggregator.py +438 -0
  65. cli/board_commands.py +1218 -0
  66. cli/brain_commands.py +255 -0
  67. cli/cognition.py +345 -0
  68. cli/config_composer.py +349 -0
  69. cli/core_version.py +41 -0
  70. cli/cron_commands.py +278 -0
  71. cli/db_reset.py +298 -0
  72. cli/doc_commands.py +111 -0
  73. cli/doctor.py +2953 -0
  74. cli/doctor_board.py +365 -0
  75. cli/doctor_extras.py +1121 -0
  76. cli/doctor_graph.py +608 -0
  77. cli/doctor_tokens.py +254 -0
  78. cli/graph_commands.py +1265 -0
  79. cli/hook_renderer.py +393 -0
  80. cli/hub_commands.py +580 -0
  81. cli/list_adapters.py +79 -0
  82. cli/list_stacks.py +105 -0
  83. cli/logs_commands.py +89 -0
  84. cli/main.py +3070 -0
  85. cli/materialize_file.py +65 -0
  86. cli/mcp_start.py +153 -0
  87. cli/module_commands.py +513 -0
  88. cli/pr_commands.py +2024 -0
  89. cli/preset_commands.py +126 -0
  90. cli/preset_registry.py +171 -0
  91. cli/project_overrides.py +119 -0
  92. cli/registry.py +365 -0
  93. cli/remove_stack.py +492 -0
  94. cli/renderer.py +620 -0
  95. cli/setup.py +464 -0
  96. cli/skill_commands.py +689 -0
  97. cli/skill_registry.py +235 -0
  98. cli/skills_list.py +332 -0
  99. cli/stack_lint.py +351 -0
  100. cli/stack_registry.py +688 -0
  101. cli/subsystems.py +335 -0
  102. cli/sync_all.py +310 -0
  103. cli/tail_command.py +410 -0
  104. cli/update.py +608 -0
  105. cli/verify_since_edit.py +439 -0
  106. coding_os-0.3.2.dist-info/METADATA +508 -0
  107. coding_os-0.3.2.dist-info/RECORD +1304 -0
  108. coding_os-0.3.2.dist-info/WHEEL +5 -0
  109. coding_os-0.3.2.dist-info/entry_points.txt +5 -0
  110. coding_os-0.3.2.dist-info/licenses/LICENSE +201 -0
  111. coding_os-0.3.2.dist-info/top_level.txt +10 -0
  112. core/__init__.py +0 -0
  113. core/board_os/__init__.py +39 -0
  114. core/board_os/_agent_runtime.py +256 -0
  115. core/board_os/config.py +421 -0
  116. core/board_os/git_coherence.py +107 -0
  117. core/board_os/hub_adapter_manifest.py +140 -0
  118. core/board_os/mcp_tools.py +3228 -0
  119. core/board_os/migration.py +166 -0
  120. core/board_os/parser.py +317 -0
  121. core/board_os/presence.py +156 -0
  122. core/board_os/sync.py +320 -0
  123. core/board_os/transition-gates.yaml +176 -0
  124. core/board_os/transition_gates.py +224 -0
  125. core/board_os/transition_gates_cli.py +272 -0
  126. core/board_os/transition_gates_validator.py +551 -0
  127. core/board_os/verify-suites.yaml +113 -0
  128. core/board_os/verify_suites.py +126 -0
  129. core/board_os/verify_suites_cli.py +328 -0
  130. core/board_os/workflow.py +967 -0
  131. core/commands/board.md +27 -0
  132. core/commands/classify.md +23 -0
  133. core/commands/compose.md +23 -0
  134. core/commands/daily.md +31 -0
  135. core/commands/diagnose.md +7 -0
  136. core/commands/memory-search.md +23 -0
  137. core/commands/new-project.md +33 -0
  138. core/commands/retro.md +38 -0
  139. core/commands/review.md +14 -0
  140. core/commands/task.md +17 -0
  141. core/commands/verify.md +34 -0
  142. core/docs/thinking_os-final-edition.md +1449 -0
  143. core/doctor-config.yaml +74 -0
  144. core/graph_os/__init__.py +29 -0
  145. core/graph_os/backend.py +233 -0
  146. core/graph_os/backends/__init__.py +13 -0
  147. core/graph_os/backends/sqlite_backend.py +1053 -0
  148. core/graph_os/bench/__init__.py +17 -0
  149. core/graph_os/bench/fixtures.py +56 -0
  150. core/graph_os/bench/harness.py +95 -0
  151. core/graph_os/bench/persian_precision.py +142 -0
  152. core/graph_os/bench/scale_500k.py +120 -0
  153. core/graph_os/bench/token_cost.py +170 -0
  154. core/graph_os/bench/viewer_fps.py +110 -0
  155. core/graph_os/communities.py +410 -0
  156. core/graph_os/enterprise.py +218 -0
  157. core/graph_os/entry_points.py +226 -0
  158. core/graph_os/extractors/__init__.py +25 -0
  159. core/graph_os/extractors/code_generic.py +914 -0
  160. core/graph_os/extractors/code_go.py +1422 -0
  161. core/graph_os/extractors/code_json.py +340 -0
  162. core/graph_os/extractors/code_php.py +979 -0
  163. core/graph_os/extractors/code_python.py +1454 -0
  164. core/graph_os/extractors/code_shell.py +538 -0
  165. core/graph_os/extractors/code_toml.py +302 -0
  166. core/graph_os/extractors/code_ts.py +1665 -0
  167. core/graph_os/extractors/code_yaml.py +394 -0
  168. core/graph_os/extractors/contracts.py +1592 -0
  169. core/graph_os/extractors/md_links.py +890 -0
  170. core/graph_os/extractors/task_deps.py +345 -0
  171. core/graph_os/groups/__init__.py +22 -0
  172. core/graph_os/groups/cross_repo.py +156 -0
  173. core/graph_os/groups/manifest.py +141 -0
  174. core/graph_os/ingest/__init__.py +19 -0
  175. core/graph_os/ingest/base.py +306 -0
  176. core/graph_os/ingest/github.py +112 -0
  177. core/graph_os/ingest/zip.py +95 -0
  178. core/graph_os/toolchain.py +393 -0
  179. core/graph_os/tools/__init__.py +9 -0
  180. core/graph_os/tools/graph.py +5573 -0
  181. core/graph_os/tools/reindex_dispatch.py +730 -0
  182. core/graph_os/tree_sitter_overlay.py +235 -0
  183. core/graph_os/types.py +252 -0
  184. core/graph_os/vec_index.py +277 -0
  185. core/graph_os/viewer/__init__.py +12 -0
  186. core/graph_os/viewer/exporter.py +93 -0
  187. core/graph_os/viewer/template.py +189 -0
  188. core/hooks/_helpers/_paths.py +40 -0
  189. core/hooks/_helpers/advance_role.py +72 -0
  190. core/hooks/_helpers/auto_compose.py +228 -0
  191. core/hooks/_helpers/auto_validate_lessons.py +55 -0
  192. core/hooks/_helpers/branch_guard_check.py +796 -0
  193. core/hooks/_helpers/check_commit_message.py +108 -0
  194. core/hooks/_helpers/check_dangerous_rm.py +80 -0
  195. core/hooks/_helpers/check_git_bypass.py +154 -0
  196. core/hooks/_helpers/check_git_destructive.py +77 -0
  197. core/hooks/_helpers/check_settings_write.py +97 -0
  198. core/hooks/_helpers/consume_override.py +51 -0
  199. core/hooks/_helpers/context_budget.py +77 -0
  200. core/hooks/_helpers/cos_say_json.py +103 -0
  201. core/hooks/_helpers/destructive_edit_check.py +163 -0
  202. core/hooks/_helpers/detect_status_transition.py +82 -0
  203. core/hooks/_helpers/digest_regen.py +56 -0
  204. core/hooks/_helpers/doc_sync_check.py +498 -0
  205. core/hooks/_helpers/drain_embedding_outbox.py +52 -0
  206. core/hooks/_helpers/extract_additional_context.py +51 -0
  207. core/hooks/_helpers/extract_commit_msg_arg.py +74 -0
  208. core/hooks/_helpers/git_command_parse.py +424 -0
  209. core/hooks/_helpers/git_settings_fields.py +47 -0
  210. core/hooks/_helpers/graph_context_match.py +37 -0
  211. core/hooks/_helpers/graph_marker_check.py +70 -0
  212. core/hooks/_helpers/jit_recall.py +56 -0
  213. core/hooks/_helpers/json_field.py +41 -0
  214. core/hooks/_helpers/narrative_signal.py +59 -0
  215. core/hooks/_helpers/observation_count.py +31 -0
  216. core/hooks/_helpers/pre_commit_batch.py +177 -0
  217. core/hooks/_helpers/pre_commit_fake_input.py +42 -0
  218. core/hooks/_helpers/presence_gc.py +102 -0
  219. core/hooks/_helpers/presence_write.py +167 -0
  220. core/hooks/_helpers/recover_indirect.py +35 -0
  221. core/hooks/_helpers/routing_evolution.py +104 -0
  222. core/hooks/_helpers/session_recap.py +72 -0
  223. core/hooks/_helpers/skill_primer.py +229 -0
  224. core/hooks/_helpers/task_sync.py +59 -0
  225. core/hooks/_helpers/tool_failure_capture.py +147 -0
  226. core/hooks/_helpers/trajectory_autosnap.py +278 -0
  227. core/hooks/_helpers/trajectory_startup.py +62 -0
  228. core/hooks/_helpers/turn_summary.py +82 -0
  229. core/hooks/_helpers/validate_task_frontmatter.py +98 -0
  230. core/hooks/_helpers/wip_limit_check.py +103 -0
  231. core/hooks/_helpers/wip_lines.py +53 -0
  232. core/hooks/_helpers/work_log_append.py +89 -0
  233. core/hooks/_helpers/wrap_dispatch_output.py +82 -0
  234. core/hooks/advance-role.sh +48 -0
  235. core/hooks/agent-presence.sh +179 -0
  236. core/hooks/auto-brain-decay.sh +184 -0
  237. core/hooks/auto-compose-roles.sh +83 -0
  238. core/hooks/auto-graph-reconcile-shell.sh +119 -0
  239. core/hooks/auto-regen-doc-index.sh +120 -0
  240. core/hooks/auto-reindex-docs.sh +130 -0
  241. core/hooks/auto-task-sync.sh +56 -0
  242. core/hooks/auto-trace-rotate.sh +88 -0
  243. core/hooks/block-bad-patterns.sh +212 -0
  244. core/hooks/block-dangerous-commands.sh +182 -0
  245. core/hooks/block-hardcoded-literals.sh +90 -0
  246. core/hooks/block-migration-conflict.sh +114 -0
  247. core/hooks/block-protected-files.sh +129 -0
  248. core/hooks/block-secrets.sh +185 -0
  249. core/hooks/block-shared-tree-edit.sh +75 -0
  250. core/hooks/block-uv-heredoc.sh +78 -0
  251. core/hooks/branch-guard.sh +122 -0
  252. core/hooks/capture-observation.sh +76 -0
  253. core/hooks/capture-tool-failure.sh +24 -0
  254. core/hooks/capture-work-log.sh +89 -0
  255. core/hooks/check-agents-md-refs.sh +75 -0
  256. core/hooks/check-agents-md-size.sh +49 -0
  257. core/hooks/check-capture-worked.sh +148 -0
  258. core/hooks/check-doc-size.sh +61 -0
  259. core/hooks/check-mcp-extras.sh +92 -0
  260. core/hooks/check-state.sh +87 -0
  261. core/hooks/classify-task-mode.sh +103 -0
  262. core/hooks/cos-env.sh +1301 -0
  263. core/hooks/drain-embedding-outbox.sh +24 -0
  264. core/hooks/enforce-anti-ambiguity.sh +74 -0
  265. core/hooks/enforce-commit-message.sh +73 -0
  266. core/hooks/enforce-doc-anchor.sh +224 -0
  267. core/hooks/enforce-doc-sync.sh +206 -0
  268. core/hooks/enforce-graph-context.sh +89 -0
  269. core/hooks/enforce-graph-first-read.sh +94 -0
  270. core/hooks/enforce-memory-check.sh +128 -0
  271. core/hooks/enforce-rename-plan.sh +78 -0
  272. core/hooks/enforce-scaffold-boundary.sh +68 -0
  273. core/hooks/enforce-skill.sh +125 -0
  274. core/hooks/enforce-task-body.sh +52 -0
  275. core/hooks/enforce-task-start.sh +81 -0
  276. core/hooks/enforce-task-transition.sh +75 -0
  277. core/hooks/enforce-template.sh +143 -0
  278. core/hooks/enforce-verify.sh +112 -0
  279. core/hooks/enforce-wip-limit.sh +43 -0
  280. core/hooks/enforce-zoom.sh +69 -0
  281. core/hooks/ensure-hub-up.sh +67 -0
  282. core/hooks/inject-mcp-caller-session.sh +70 -0
  283. core/hooks/jit-recall.sh +65 -0
  284. core/hooks/link-commit-to-task.sh +143 -0
  285. core/hooks/lint-task.sh +40 -0
  286. core/hooks/nudge-docs-first.sh +71 -0
  287. core/hooks/nudge-git-mode.sh +29 -0
  288. core/hooks/nudge-graph-os.sh +118 -0
  289. core/hooks/nudge-learn-narrative.sh +36 -0
  290. core/hooks/nudge-model-routing.sh +32 -0
  291. core/hooks/nudge-reentry.sh +101 -0
  292. core/hooks/nudge-reuse-first.sh +68 -0
  293. core/hooks/nudge-task-discovery.sh +81 -0
  294. core/hooks/nudge-thinking-os.sh +109 -0
  295. core/hooks/pr-reap.sh +23 -0
  296. core/hooks/reclaim-sweep.sh +58 -0
  297. core/hooks/record-verify-auto.sh +77 -0
  298. core/hooks/record-verify.sh +74 -0
  299. core/hooks/regen-reminder.sh +104 -0
  300. core/hooks/registry.yaml +1262 -0
  301. core/hooks/remind-daily.sh +27 -0
  302. core/hooks/remind-dogfood.sh +70 -0
  303. core/hooks/remind-learn-validate.sh +94 -0
  304. core/hooks/rules-primer.sh +50 -0
  305. core/hooks/search-enforce-inventory.sh +108 -0
  306. core/hooks/search-verify-remaining.sh +132 -0
  307. core/hooks/session-context.sh +729 -0
  308. core/hooks/session-end.sh +145 -0
  309. core/hooks/session-skill-primer.sh +43 -0
  310. core/hooks/snapshot-transcript.sh +56 -0
  311. core/hooks/sync-task-current.sh +85 -0
  312. core/hooks/test-first-reminder.sh +120 -0
  313. core/hooks/test-governor.sh +173 -0
  314. core/hooks/thinking_os-gate.sh +52 -0
  315. core/hooks/track-backtrack.sh +35 -0
  316. core/hooks/track-discovery.sh +121 -0
  317. core/hooks/track-skill.sh +53 -0
  318. core/hooks/validate-task-frontmatter.sh +49 -0
  319. core/hooks/verify-rename-callers.sh +119 -0
  320. core/hooks/warn-abandoned-task.sh +99 -0
  321. core/hooks/warn-destructive-edit.sh +64 -0
  322. core/hooks/warn-diff-size.sh +43 -0
  323. core/hooks/warn-graph-empty.sh +81 -0
  324. core/hooks/warn-mcp-down.sh +190 -0
  325. core/hooks/write-state.sh +55 -0
  326. core/logging_os/__init__.py +33 -0
  327. core/logging_os/api.py +127 -0
  328. core/logging_os/bridge.py +80 -0
  329. core/logging_os/config.py +172 -0
  330. core/logging_os/fingerprint.py +25 -0
  331. core/logging_os/redact.py +53 -0
  332. core/logging_os/render.py +83 -0
  333. core/logging_os/sinks.py +164 -0
  334. core/rules/anti-overengineering.md +44 -0
  335. core/rules/api-contract-discipline.md +41 -0
  336. core/rules/dimension-registry.md +155 -0
  337. core/rules/git-workflow.md +57 -0
  338. core/rules/memory.md +46 -0
  339. core/rules/model-routing.md +22 -0
  340. core/rules/skill-enforcement.md +75 -0
  341. core/rules/test-discipline.md +38 -0
  342. core/rules/thinking_os.md +48 -0
  343. core/rules/transparency-banner.md +37 -0
  344. core/runtime_paths.yaml +36 -0
  345. core/scaffold_manifest.json +14430 -0
  346. core/scheduled/__init__.py +0 -0
  347. core/scheduled/_activity.py +126 -0
  348. core/scheduled/_state.py +113 -0
  349. core/scheduled/config.py +86 -0
  350. core/scheduled/dep_reconcile.py +135 -0
  351. core/scheduled/error_sweep.py +137 -0
  352. core/scheduled/nightly.py +930 -0
  353. core/scheduled/responsive_extract.py +65 -0
  354. core/schemas/adapter.schema.json +269 -0
  355. core/schemas/preset.schema.json +50 -0
  356. core/schemas/skill.schema.json +81 -0
  357. core/schemas/stack.schema.json +404 -0
  358. core/scripts/_lib.sh +9 -0
  359. core/scripts/docs-lint.sh +228 -0
  360. core/scripts/docs-nav-fix.sh +133 -0
  361. core/scripts/docs-staleness-check.sh +154 -0
  362. core/scripts/install-adapter.sh +266 -0
  363. core/scripts/link-stack-skills.sh +52 -0
  364. core/scripts/log-latest.sh +106 -0
  365. core/scripts/log-search.sh +89 -0
  366. core/scripts/log-write.sh +134 -0
  367. core/scripts/ref-resolve.sh +71 -0
  368. core/skills/a11y/SKILL.md +305 -0
  369. core/skills/a11y/assets/a11y-checklist.md +137 -0
  370. core/skills/a11y/references/aria-and-focus.md +247 -0
  371. core/skills/a11y/references/rn-accessibility.md +343 -0
  372. core/skills/a11y/references/screen-reader-testing.md +190 -0
  373. core/skills/agent-memory/SKILL.md +191 -0
  374. core/skills/agent-memory/assets/memory-checklist.md +21 -0
  375. core/skills/agent-memory/references/memory-recipes.md +57 -0
  376. core/skills/api-design/SKILL.md +232 -0
  377. core/skills/api-design/assets/api-design-checklist.md +110 -0
  378. core/skills/api-design/references/error-envelope.md +381 -0
  379. core/skills/api-design/references/idempotency-pagination.md +312 -0
  380. core/skills/api-design/references/rest-contracts.md +426 -0
  381. core/skills/auth-patterns/SKILL.md +352 -0
  382. core/skills/auth-patterns/assets/auth-checklist.md +118 -0
  383. core/skills/auth-patterns/references/jwt-and-service-tokens.md +343 -0
  384. core/skills/auth-patterns/references/passkeys-2fa.md +289 -0
  385. core/skills/auth-patterns/references/sessions-vs-jwt.md +230 -0
  386. core/skills/auth-patterns/scripts/cookie-flag-check.py +146 -0
  387. core/skills/backend-fundamentals/SKILL.md +238 -0
  388. core/skills/backend-fundamentals/assets/backend-checklist.md +27 -0
  389. core/skills/backend-fundamentals/references/backend-patterns.md +56 -0
  390. core/skills/backend-fundamentals/scripts/check_layering.py +83 -0
  391. core/skills/clean-code/SKILL.md +642 -0
  392. core/skills/clean-code/scripts/audit-fail-closed.py +167 -0
  393. core/skills/codebase-explorer/SKILL.md +89 -0
  394. core/skills/codebase-explorer/assets/reading-checklist.md +24 -0
  395. core/skills/codebase-explorer/references/reading-strategies.md +52 -0
  396. core/skills/codebase-explorer/scripts/outline.py +99 -0
  397. core/skills/db-design/SKILL.md +327 -0
  398. core/skills/db-design/assets/migration-template.sql +49 -0
  399. core/skills/db-design/references/migration-discipline.md +290 -0
  400. core/skills/db-design/references/postgres-patterns.md +340 -0
  401. core/skills/db-design/scripts/migration-safety.sh +150 -0
  402. core/skills/deployment-cicd/SKILL.md +260 -0
  403. core/skills/deployment-cicd/assets/deploy-checklist.md +26 -0
  404. core/skills/deployment-cicd/references/pipeline-and-release.md +54 -0
  405. core/skills/deployment-cicd/scripts/lint_workflow.py +79 -0
  406. core/skills/docker/SKILL.md +114 -0
  407. core/skills/docker/assets/dockerfile-checklist.md +31 -0
  408. core/skills/docker/references/compose-patterns.md +66 -0
  409. core/skills/docker/references/dockerfile-optimization.md +64 -0
  410. core/skills/docker/scripts/lint_dockerfile.sh +48 -0
  411. core/skills/docker/versions.json +16 -0
  412. core/skills/end-to-end-testing/SKILL.md +101 -0
  413. core/skills/end-to-end-testing/assets/e2e-checklist.md +23 -0
  414. core/skills/end-to-end-testing/references/maestro.md +63 -0
  415. core/skills/end-to-end-testing/references/playwright.md +68 -0
  416. core/skills/end-to-end-testing/scripts/lint_e2e.py +88 -0
  417. core/skills/end-to-end-testing/versions.json +16 -0
  418. core/skills/frontend-design/SKILL.md +76 -0
  419. core/skills/frontend-design/assets/design-checklist.md +29 -0
  420. core/skills/frontend-design/references/design-principles.md +65 -0
  421. core/skills/frontend-design/scripts/check_contrast.py +89 -0
  422. core/skills/frontend-fundamentals/SKILL.md +213 -0
  423. core/skills/frontend-fundamentals/assets/frontend-checklist.md +25 -0
  424. core/skills/frontend-fundamentals/references/rendering-and-state.md +66 -0
  425. core/skills/frontend-fundamentals/scripts/check_frontend.py +86 -0
  426. core/skills/graph-explorer/SKILL.md +215 -0
  427. core/skills/graph-explorer/scripts/explain-impact.sh +64 -0
  428. core/skills/graphql/SKILL.md +187 -0
  429. core/skills/grpc-microservices/SKILL.md +174 -0
  430. core/skills/hexagonal-architecture/SKILL.md +199 -0
  431. core/skills/hexagonal-architecture/assets/folder-scaffold.md +233 -0
  432. core/skills/hexagonal-architecture/references/anti-patterns.md +129 -0
  433. core/skills/hexagonal-architecture/references/go-fiber-layout.md +429 -0
  434. core/skills/hexagonal-architecture/references/python-fastapi-layout.md +453 -0
  435. core/skills/hexagonal-architecture/references/react-native-layout.md +428 -0
  436. core/skills/i18n/SKILL.md +126 -0
  437. core/skills/incident-response/SKILL.md +225 -0
  438. core/skills/incident-response/assets/incident-checklist.md +29 -0
  439. core/skills/incident-response/references/severity-and-runbook.md +53 -0
  440. core/skills/incident-response/scripts/classify_severity.py +86 -0
  441. core/skills/linux-sysadmin/SKILL.md +115 -0
  442. core/skills/linux-sysadmin/assets/hardening-checklist.md +29 -0
  443. core/skills/linux-sysadmin/references/ssh-hardening.md +62 -0
  444. core/skills/linux-sysadmin/references/systemd-and-services.md +77 -0
  445. core/skills/linux-sysadmin/scripts/triage.sh +50 -0
  446. core/skills/linux-sysadmin/versions.json +17 -0
  447. core/skills/llm-patterns/SKILL.md +410 -0
  448. core/skills/llm-patterns/assets/llm-feature-checklist.md +26 -0
  449. core/skills/llm-patterns/references/rag-and-evals.md +59 -0
  450. core/skills/llm-patterns/scripts/estimate_tokens.py +75 -0
  451. core/skills/messaging-queues/SKILL.md +142 -0
  452. core/skills/mobile-fundamentals/SKILL.md +406 -0
  453. core/skills/mobile-fundamentals/assets/mobile-launch-checklist.md +130 -0
  454. core/skills/mobile-fundamentals/references/navigation-and-deep-links.md +337 -0
  455. core/skills/mobile-fundamentals/references/offline-sync.md +339 -0
  456. core/skills/node-backend/SKILL.md +114 -0
  457. core/skills/node-backend/assets/node-checklist.md +25 -0
  458. core/skills/node-backend/references/async-and-errors.md +67 -0
  459. core/skills/node-backend/references/event-loop.md +65 -0
  460. core/skills/node-backend/scripts/check_package.py +78 -0
  461. core/skills/node-backend/versions.json +17 -0
  462. core/skills/observability/SKILL.md +289 -0
  463. core/skills/observability/assets/observability-checklist.md +27 -0
  464. core/skills/observability/references/instrumentation.md +57 -0
  465. core/skills/observability/scripts/lint_logging.py +77 -0
  466. core/skills/payments/SKILL.md +102 -0
  467. core/skills/performance/SKILL.md +305 -0
  468. core/skills/performance/assets/perf-checklist.md +143 -0
  469. core/skills/performance/references/mobile-performance.md +249 -0
  470. core/skills/performance/references/web-vitals.md +209 -0
  471. core/skills/php/SKILL.md +116 -0
  472. core/skills/php/assets/php-checklist.md +26 -0
  473. core/skills/php/references/modern-php.md +64 -0
  474. core/skills/php/references/security.md +72 -0
  475. core/skills/php/scripts/scan_php_smells.py +99 -0
  476. core/skills/php/versions.json +9 -0
  477. core/skills/pr-mode-driver/SKILL.md +65 -0
  478. core/skills/realtime-websockets/SKILL.md +152 -0
  479. core/skills/redis/SKILL.md +105 -0
  480. core/skills/redis/assets/redis-checklist.md +27 -0
  481. core/skills/redis/references/operations.md +66 -0
  482. core/skills/redis/references/patterns.md +62 -0
  483. core/skills/redis/scripts/analyze_info.py +101 -0
  484. core/skills/redis/versions.json +9 -0
  485. core/skills/search/SKILL.md +91 -0
  486. core/skills/search/references/grep.md +76 -0
  487. core/skills/search/scripts/verify-count.sh +73 -0
  488. core/skills/search-infra/SKILL.md +109 -0
  489. core/skills/security-mobile/SKILL.md +394 -0
  490. core/skills/security-mobile/assets/mobile-security-checklist.md +117 -0
  491. core/skills/security-mobile/references/masvs-l1-checklist.md +127 -0
  492. core/skills/security-web/SKILL.md +217 -0
  493. core/skills/security-web/assets/security-web-checklist.md +167 -0
  494. core/skills/security-web/references/owasp-top-10.md +551 -0
  495. core/skills/security-web/references/supply-chain.md +179 -0
  496. core/skills/security-web/scripts/csp-check.sh +153 -0
  497. core/skills/shell-scripting/SKILL.md +128 -0
  498. core/skills/shell-scripting/assets/script-checklist.md +33 -0
  499. core/skills/shell-scripting/references/argument-parsing.md +84 -0
  500. core/skills/shell-scripting/references/bash-robustness.md +78 -0
  501. core/skills/shell-scripting/scripts/lint_script.sh +53 -0
  502. core/skills/shell-scripting/scripts/new_script.py +131 -0
  503. core/skills/shell-scripting/versions.json +23 -0
  504. core/skills/sql-authoring/SKILL.md +104 -0
  505. core/skills/sql-authoring/assets/query-review-checklist.md +26 -0
  506. core/skills/sql-authoring/references/query-patterns.md +89 -0
  507. core/skills/sql-authoring/references/reading-explain.md +52 -0
  508. core/skills/sql-authoring/scripts/analyze_plan.py +100 -0
  509. core/skills/sql-authoring/versions.json +17 -0
  510. core/skills/state-management/SKILL.md +428 -0
  511. core/skills/state-management/references/tanstack-query-recipes.md +301 -0
  512. core/skills/state-management/references/zustand-recipes.md +364 -0
  513. core/skills/supabase/SKILL.md +108 -0
  514. core/skills/supabase/assets/supabase-checklist.md +26 -0
  515. core/skills/supabase/references/realtime-and-storage.md +55 -0
  516. core/skills/supabase/references/rls-and-auth.md +65 -0
  517. core/skills/supabase/scripts/check_rls.py +88 -0
  518. core/skills/supabase/versions.json +9 -0
  519. core/skills/task-driver/SKILL.md +272 -0
  520. core/skills/task-driver/scripts/task-lint.sh +163 -0
  521. core/skills/technical-writing/SKILL.md +85 -0
  522. core/skills/technical-writing/assets/doc-checklist.md +29 -0
  523. core/skills/technical-writing/references/doc-anatomy.md +53 -0
  524. core/skills/technical-writing/references/writing-craft.md +59 -0
  525. core/skills/technical-writing/scripts/new_doc.py +81 -0
  526. core/skills/terraform-k8s/SKILL.md +133 -0
  527. core/skills/testing-strategy/SKILL.md +266 -0
  528. core/skills/testing-strategy/assets/test-review-checklist.md +25 -0
  529. core/skills/testing-strategy/references/test-types.md +52 -0
  530. core/skills/testing-strategy/scripts/coverage_gate.py +79 -0
  531. core/skills/thinking_os/SKILL.md +288 -0
  532. core/skills/thinking_os/scripts/classify.sh +122 -0
  533. core/skills/typescript/SKILL.md +110 -0
  534. core/skills/typescript/assets/typescript-checklist.md +24 -0
  535. core/skills/typescript/references/strictness.md +53 -0
  536. core/skills/typescript/references/type-system.md +86 -0
  537. core/skills/typescript/scripts/check_tsconfig.py +92 -0
  538. core/skills/typescript/versions.json +9 -0
  539. core/subsystems.yaml +202 -0
  540. core/thinking_os/__init__.py +1 -0
  541. core/thinking_os/_agent_markers.py +32 -0
  542. core/thinking_os/agents/README.md +71 -0
  543. core/thinking_os/agents/analyst.md +139 -0
  544. core/thinking_os/agents/architect.md +127 -0
  545. core/thinking_os/agents/debugger.md +111 -0
  546. core/thinking_os/agents/deployer.md +112 -0
  547. core/thinking_os/agents/distiller.md +28 -0
  548. core/thinking_os/agents/documenter.md +101 -0
  549. core/thinking_os/agents/implementer.md +135 -0
  550. core/thinking_os/agents/internal/session_observer.md +39 -0
  551. core/thinking_os/agents/observer.md +100 -0
  552. core/thinking_os/agents/onboarder.md +81 -0
  553. core/thinking_os/agents/refactorer.md +123 -0
  554. core/thinking_os/agents/repairer.md +47 -0
  555. core/thinking_os/agents/researcher.md +129 -0
  556. core/thinking_os/agents/reviewer.md +147 -0
  557. core/thinking_os/agents/security_auditor.md +133 -0
  558. core/thinking_os/background.py +405 -0
  559. core/thinking_os/bootstrap_outcomes.py +200 -0
  560. core/thinking_os/budget.py +302 -0
  561. core/thinking_os/capture.py +495 -0
  562. core/thinking_os/cognition.py +516 -0
  563. core/thinking_os/cognition_schemas.py +517 -0
  564. core/thinking_os/compress.py +192 -0
  565. core/thinking_os/concepts.py +233 -0
  566. core/thinking_os/dashboard.py +159 -0
  567. core/thinking_os/database.py +2883 -0
  568. core/thinking_os/decay.py +393 -0
  569. core/thinking_os/digest.py +295 -0
  570. core/thinking_os/dispatcher.py +192 -0
  571. core/thinking_os/dispatcher_helpers.py +48 -0
  572. core/thinking_os/dispatchers/__init__.py +3 -0
  573. core/thinking_os/dispatchers/default.py +47 -0
  574. core/thinking_os/distill.py +192 -0
  575. core/thinking_os/doc_indexer.py +905 -0
  576. core/thinking_os/embeddings.py +943 -0
  577. core/thinking_os/formula_composer.py +556 -0
  578. core/thinking_os/gate_marker.py +75 -0
  579. core/thinking_os/graph.py +296 -0
  580. core/thinking_os/graph_indexer.py +360 -0
  581. core/thinking_os/health_check.py +517 -0
  582. core/thinking_os/impact.py +119 -0
  583. core/thinking_os/memory_gc.py +356 -0
  584. core/thinking_os/migrator_embeddings.py +318 -0
  585. core/thinking_os/precision.py +194 -0
  586. core/thinking_os/presets/registry.yaml +127 -0
  587. core/thinking_os/record_outcome.py +399 -0
  588. core/thinking_os/repair.py +105 -0
  589. core/thinking_os/retrieval_quality.py +239 -0
  590. core/thinking_os/roles/analyst.yaml +83 -0
  591. core/thinking_os/roles/architect.yaml +88 -0
  592. core/thinking_os/roles/debugger.yaml +71 -0
  593. core/thinking_os/roles/deployer.yaml +71 -0
  594. core/thinking_os/roles/documenter.yaml +72 -0
  595. core/thinking_os/roles/implementer.yaml +83 -0
  596. core/thinking_os/roles/observer.yaml +70 -0
  597. core/thinking_os/roles/refactorer.yaml +71 -0
  598. core/thinking_os/roles/researcher.yaml +72 -0
  599. core/thinking_os/roles/reviewer.yaml +79 -0
  600. core/thinking_os/roles/security_auditor.yaml +83 -0
  601. core/thinking_os/roles_state.py +168 -0
  602. core/thinking_os/sanitizer.py +320 -0
  603. core/thinking_os/server.py +3160 -0
  604. core/thinking_os/session_enrich.py +272 -0
  605. core/thinking_os/session_observe_worker.py +111 -0
  606. core/thinking_os/session_startup.py +74 -0
  607. core/thinking_os/session_summary.py +245 -0
  608. core/thinking_os/situations/registry.yaml +99 -0
  609. core/thinking_os/task_analyzer.py +462 -0
  610. core/thinking_os/task_parser.py +342 -0
  611. core/thinking_os/task_sync.py +73 -0
  612. core/thinking_os/tools/__init__.py +6 -0
  613. core/thinking_os/tools/_shared.py +947 -0
  614. core/thinking_os/tools/cognition.py +1867 -0
  615. core/thinking_os/tools/docs.py +770 -0
  616. core/thinking_os/tools/learning.py +2078 -0
  617. core/thinking_os/tools/logs.py +79 -0
  618. core/thinking_os/tools/memory.py +840 -0
  619. core/thinking_os/tools/metrics.py +200 -0
  620. core/thinking_os/tools/retrieve.py +415 -0
  621. core/thinking_os/tools/routing.py +658 -0
  622. core/thinking_os/tools/tasks.py +449 -0
  623. core/thinking_os/tools/trajectory.py +181 -0
  624. core/thinking_os/tracing.py +235 -0
  625. core/web/__init__.py +5 -0
  626. core/web/_cache.py +118 -0
  627. core/web/_deps.py +56 -0
  628. core/web/_envelope.py +85 -0
  629. core/web/_project_context.py +140 -0
  630. core/web/chat_providers.py +108 -0
  631. core/web/init_jobs.py +216 -0
  632. core/web/routes/__init__.py +25 -0
  633. core/web/routes/_bounded_read.py +76 -0
  634. core/web/routes/board.py +1089 -0
  635. core/web/routes/cognition.py +1838 -0
  636. core/web/routes/config.py +635 -0
  637. core/web/routes/graph.py +513 -0
  638. core/web/routes/health.py +180 -0
  639. core/web/routes/hooks.py +288 -0
  640. core/web/routes/hub.py +1219 -0
  641. core/web/routes/logs.py +374 -0
  642. core/web/routes/metrics.py +43 -0
  643. core/web/routes/observability.py +400 -0
  644. core/web/routes/patterns.py +227 -0
  645. core/web/routes/presence.py +609 -0
  646. core/web/routes/roles.py +446 -0
  647. core/web/routes/scheduled.py +261 -0
  648. core/web/routes/search.py +238 -0
  649. core/web/routes/sessions.py +220 -0
  650. core/web/routes/settings.py +363 -0
  651. core/web/routes/stream.py +547 -0
  652. core/web/security.py +157 -0
  653. core/web/server.py +283 -0
  654. graph_os/__init__.py +29 -0
  655. graph_os/backend.py +233 -0
  656. graph_os/backends/__init__.py +13 -0
  657. graph_os/backends/sqlite_backend.py +1053 -0
  658. graph_os/communities.py +410 -0
  659. graph_os/enterprise.py +218 -0
  660. graph_os/entry_points.py +226 -0
  661. graph_os/extractors/__init__.py +25 -0
  662. graph_os/extractors/code_generic.py +914 -0
  663. graph_os/extractors/code_go.py +1422 -0
  664. graph_os/extractors/code_json.py +340 -0
  665. graph_os/extractors/code_php.py +979 -0
  666. graph_os/extractors/code_python.py +1454 -0
  667. graph_os/extractors/code_shell.py +538 -0
  668. graph_os/extractors/code_toml.py +302 -0
  669. graph_os/extractors/code_ts.py +1665 -0
  670. graph_os/extractors/code_yaml.py +394 -0
  671. graph_os/extractors/contracts.py +1592 -0
  672. graph_os/extractors/md_links.py +890 -0
  673. graph_os/extractors/task_deps.py +345 -0
  674. graph_os/groups/__init__.py +22 -0
  675. graph_os/groups/cross_repo.py +156 -0
  676. graph_os/groups/manifest.py +141 -0
  677. graph_os/ingest/__init__.py +19 -0
  678. graph_os/ingest/base.py +306 -0
  679. graph_os/ingest/github.py +112 -0
  680. graph_os/ingest/zip.py +95 -0
  681. graph_os/toolchain.py +393 -0
  682. graph_os/tools/__init__.py +9 -0
  683. graph_os/tools/graph.py +5573 -0
  684. graph_os/tools/reindex_dispatch.py +730 -0
  685. graph_os/tree_sitter_overlay.py +235 -0
  686. graph_os/types.py +252 -0
  687. graph_os/vec_index.py +277 -0
  688. graph_os/viewer/__init__.py +12 -0
  689. graph_os/viewer/exporter.py +93 -0
  690. graph_os/viewer/template.py +189 -0
  691. scheduled/__init__.py +0 -0
  692. scheduled/_activity.py +126 -0
  693. scheduled/_state.py +113 -0
  694. scheduled/config.py +86 -0
  695. scheduled/dep_reconcile.py +135 -0
  696. scheduled/error_sweep.py +137 -0
  697. scheduled/nightly.py +930 -0
  698. scheduled/responsive_extract.py +65 -0
  699. scripts/__init__.py +4 -0
  700. scripts/_commit_msg_body.sh +31 -0
  701. scripts/_post_commit_body.sh +49 -0
  702. scripts/_pre_commit_body.sh +121 -0
  703. scripts/_prepare_commit_msg_body.sh +53 -0
  704. scripts/audit_mcp_tools.py +693 -0
  705. scripts/bench_sdk_dispatcher.py +177 -0
  706. scripts/capture_golden.py +169 -0
  707. scripts/check_graph_phantoms.py +75 -0
  708. scripts/dev/audit_doc_links.py +359 -0
  709. scripts/dev/audit_scaffold_module_tags.py +107 -0
  710. scripts/dev/backfill_doc_headers.py +328 -0
  711. scripts/dev/backfill_nav_lines.py +119 -0
  712. scripts/dev/fix_nav_placement.py +106 -0
  713. scripts/dev/inspect_sdk_options.py +45 -0
  714. scripts/dev/migrate_check_ids.py +170 -0
  715. scripts/dev/strip_purpose_blocks.py +154 -0
  716. scripts/dump_openapi.py +66 -0
  717. scripts/e2e_dispatch_tool.py +195 -0
  718. scripts/generate_manifest.py +166 -0
  719. scripts/golden_sections.py +20 -0
  720. scripts/graph_demo.py +161 -0
  721. scripts/install-git-hooks.sh +47 -0
  722. scripts/migrate_embeddings_minilm_to_bge_m3.py +84 -0
  723. scripts/operational_eval.py +445 -0
  724. scripts/probe_agent_session_resolver.py +59 -0
  725. scripts/prune_deleted_path.py +127 -0
  726. scripts/refactor_agent_dual_mode.py +171 -0
  727. scripts/refresh_skill_versions.py +302 -0
  728. scripts/regen_doc_index.py +209 -0
  729. scripts/regen_doctor_schema.py +62 -0
  730. scripts/regen_rules.py +94 -0
  731. scripts/rename_formulas_to_semantic.py +241 -0
  732. scripts/smoke_db_connections.py +183 -0
  733. scripts/smoke_doc_header.py +72 -0
  734. scripts/smoke_graph_e2e.py +374 -0
  735. scripts/smoke_sdk_dispatch.py +84 -0
  736. scripts/smoke_uid_resolver.py +164 -0
  737. scripts/verify_dispatchers.py +244 -0
  738. scripts/verify_phase_c_e2e.py +436 -0
  739. templates/__init__.py +6 -0
  740. templates/_base/Makefile.base +353 -0
  741. templates/_base/base.yaml +59 -0
  742. templates/_base/coding-os.yaml.template +39 -0
  743. templates/_base/dimension-registry.template.md +68 -0
  744. templates/_base/domain-config.template.json +46 -0
  745. templates/_base/fragments/anatomy-map.md.tmpl +11 -0
  746. templates/_base/fragments/context-discipline.md.tmpl +3 -0
  747. templates/_base/fragments/core-loop.md.tmpl +52 -0
  748. templates/_base/fragments/engineering-routing.md.tmpl +3 -0
  749. templates/_base/fragments/header.md.tmpl +6 -0
  750. templates/_base/fragments/identity.md.tmpl +3 -0
  751. templates/_base/fragments/principles.md.tmpl +3 -0
  752. templates/_base/fragments/retrieval-routing.md.tmpl +23 -0
  753. templates/_base/fragments/session-handoff.md.tmpl +3 -0
  754. templates/_base/fragments/skills.md.tmpl +3 -0
  755. templates/_base/fragments/ssot-map.md.tmpl +3 -0
  756. templates/_base/fragments/stop-conditions.md.tmpl +3 -0
  757. templates/_base/fragments/subagent-dispatch.md.tmpl +3 -0
  758. templates/_base/fragments/task-authoring.md.tmpl +69 -0
  759. templates/_base/fragments/task-logging.md.tmpl +8 -0
  760. templates/_base/fragments/tool-routing.md.tmpl +9 -0
  761. templates/_base/fragments/verification-matrix.md.tmpl +12 -0
  762. templates/_base/lang/dart/analysis_options.yaml +7 -0
  763. templates/_base/lang/php/phpcs.xml.dist +10 -0
  764. templates/_base/lang/python/pyproject.toml +19 -0
  765. templates/_base/lang/rust/clippy.toml +5 -0
  766. templates/_base/lang/rust/rustfmt.toml +3 -0
  767. templates/_base/lang/typescript/eslint.config.js +26 -0
  768. templates/_base/lang/typescript/tsconfig.json +15 -0
  769. templates/_base/lang/typescript/vitest.config.ts +10 -0
  770. templates/_base/scaffold/changes.log +1 -0
  771. templates/_base/scaffold/docs/00-index.md +55 -0
  772. templates/_base/scaffold/docs/_meta/feature-dependency-tree.md +30 -0
  773. templates/_base/scaffold/docs/_meta/foundation-map.md +56 -0
  774. templates/_base/scaffold/docs/_meta/questions.md +8 -0
  775. templates/_base/scaffold/docs/_meta/roadmap.md +33 -0
  776. templates/_base/scaffold/docs/api-contracts/00-index.md +58 -0
  777. templates/_base/scaffold/docs/api-contracts/error-format.md +58 -0
  778. templates/_base/scaffold/docs/architecture/00-index.md +42 -0
  779. templates/_base/scaffold/docs/architecture/adr/00-index.md +39 -0
  780. templates/_base/scaffold/docs/engineering/00-index.md +9 -0
  781. templates/_base/scaffold/docs/governance/00-index.md +55 -0
  782. templates/_base/scaffold/docs/governance/_templates/doc-cheat-sheet.md +202 -0
  783. templates/_base/scaffold/docs/governance/_templates/playbook-template.md +81 -0
  784. templates/_base/scaffold/docs/governance/_templates/post-mortem-template.md +85 -0
  785. templates/_base/scaffold/docs/governance/_templates/runbook-template.md +88 -0
  786. templates/_base/scaffold/docs/governance/_templates/security-review-template.md +111 -0
  787. templates/_base/scaffold/docs/governance/_templates/task-detail.md +61 -0
  788. templates/_base/scaffold/docs/governance/agent-workflow.md +101 -0
  789. templates/_base/scaffold/docs/governance/anatomy-contract.md +150 -0
  790. templates/_base/scaffold/docs/governance/critical-rules.md +224 -0
  791. templates/_base/scaffold/docs/governance/decision-records.md +58 -0
  792. templates/_base/scaffold/docs/governance/docs-first-protocol.md +157 -0
  793. templates/_base/scaffold/docs/governance/docs-system.md +151 -0
  794. templates/_base/scaffold/docs/governance/gdpr-compliance.md +66 -0
  795. templates/_base/scaffold/docs/governance/mcp-tool-inventory.md +112 -0
  796. templates/_base/scaffold/docs/governance/risk-register.md +26 -0
  797. templates/_base/scaffold/docs/governance/scaffold-boundary-contract.md +161 -0
  798. templates/_base/scaffold/docs/governance/task-lifecycle.md +125 -0
  799. templates/_base/scaffold/docs/governance/wrapper-derivation.md +50 -0
  800. templates/_base/scaffold/docs/insights/00-index.md +17 -0
  801. templates/_base/scaffold/docs/ops/00-index.md +59 -0
  802. templates/_base/scaffold/docs/ops/runbooks/00-index.md +9 -0
  803. templates/_base/scaffold/docs/playbooks/00-index.md +12 -0
  804. templates/_base/scaffold/docs/playbooks/research-validation.md +29 -0
  805. templates/_base/scaffold/docs/playbooks/security-review.md +41 -0
  806. templates/_base/scaffold/docs/prd/00-index.md +43 -0
  807. templates/_base/scaffold/docs/prd/01-snapshot-vision.md +56 -0
  808. templates/_base/scaffold/docs/workflow/workflow-guide.md +138 -0
  809. templates/_base/scaffold/src/shared/README.md +23 -0
  810. templates/_base/skill-enforcement.template.md +14 -0
  811. templates/_base/task-detail.template.md +61 -0
  812. templates/_presets/ai-saas.yaml +9 -0
  813. templates/_presets/django-next.yaml +8 -0
  814. templates/_presets/dotnet-react.yaml +8 -0
  815. templates/_presets/flutter-baas.yaml +8 -0
  816. templates/_presets/go-react.yaml +8 -0
  817. templates/_presets/hexagonal-product.yaml +16 -0
  818. templates/_presets/jamstack.yaml +8 -0
  819. templates/_presets/laravel-vue.yaml +8 -0
  820. templates/_presets/mean.yaml +8 -0
  821. templates/_presets/mern.yaml +9 -0
  822. templates/_presets/nest-angular.yaml +8 -0
  823. templates/_presets/nextjs-fastapi.yaml +10 -0
  824. templates/_presets/nuxt-fullstack.yaml +9 -0
  825. templates/_presets/pern.yaml +9 -0
  826. templates/_presets/rails-react.yaml +8 -0
  827. templates/_presets/rn-api.yaml +8 -0
  828. templates/_presets/rust-svelte.yaml +8 -0
  829. templates/_presets/spring-react.yaml +8 -0
  830. templates/_presets/t3-style.yaml +9 -0
  831. templates/_presets/tall.yaml +8 -0
  832. templates/_presets/wordpress-cms.yaml +8 -0
  833. templates/angular/rules/frontend.md +19 -0
  834. templates/angular/scaffold/docs/engineering/accessibility.md +46 -0
  835. templates/angular/scaffold/docs/engineering/angular-rules.md +35 -0
  836. templates/angular/scaffold/docs/playbooks/angular-app.md +42 -0
  837. templates/angular/scaffold/src/frontend/angular.json +52 -0
  838. templates/angular/scaffold/src/frontend/package.json +28 -0
  839. templates/angular/scaffold/src/frontend/src/app/app.component.ts +19 -0
  840. templates/angular/scaffold/src/frontend/src/app/app.config.ts +22 -0
  841. templates/angular/scaffold/src/frontend/src/app/app.routes.ts +8 -0
  842. templates/angular/scaffold/src/frontend/src/app/core/global-error-handler.ts +12 -0
  843. templates/angular/scaffold/src/frontend/src/app/health/health.component.ts +14 -0
  844. templates/angular/scaffold/src/frontend/src/app/health/health.service.spec.ts +16 -0
  845. templates/angular/scaffold/src/frontend/src/app/health/health.service.ts +10 -0
  846. templates/angular/scaffold/src/frontend/src/index.html +11 -0
  847. templates/angular/scaffold/src/frontend/src/main.ts +9 -0
  848. templates/angular/scaffold/src/frontend/src/styles.css +14 -0
  849. templates/angular/scaffold/src/frontend/tsconfig.app.json +8 -0
  850. templates/angular/scaffold/src/frontend/tsconfig.json +27 -0
  851. templates/angular/scaffold/src/frontend/tsconfig.spec.json +8 -0
  852. templates/angular/scaffold-boundary.yaml +27 -0
  853. templates/angular/skills/angular/SKILL.md +79 -0
  854. templates/angular/skills/angular/references/anatomy.md +69 -0
  855. templates/angular/stack.yaml +75 -0
  856. templates/aspnet-core/rules/backend.md +20 -0
  857. templates/aspnet-core/scaffold/docs/engineering/aspnet-core-rules.md +36 -0
  858. templates/aspnet-core/scaffold/docs/playbooks/aspnet-core-service.md +40 -0
  859. templates/aspnet-core/scaffold/src/backend/Backend.csproj +11 -0
  860. templates/aspnet-core/scaffold/src/backend/Backend.sln +27 -0
  861. templates/aspnet-core/scaffold/src/backend/Common/ExceptionHandlingMiddleware.cs +35 -0
  862. templates/aspnet-core/scaffold/src/backend/Features/Health/HealthEndpoints.cs +10 -0
  863. templates/aspnet-core/scaffold/src/backend/Features/Health/HealthService.cs +9 -0
  864. templates/aspnet-core/scaffold/src/backend/Program.cs +22 -0
  865. templates/aspnet-core/scaffold/src/backend/tests/Backend.Tests/Backend.Tests.csproj +22 -0
  866. templates/aspnet-core/scaffold/src/backend/tests/Backend.Tests/HealthServiceTests.cs +15 -0
  867. templates/aspnet-core/scaffold-boundary.yaml +24 -0
  868. templates/aspnet-core/skills/aspnet-core/SKILL.md +80 -0
  869. templates/aspnet-core/skills/aspnet-core/references/anatomy.md +65 -0
  870. templates/aspnet-core/stack.yaml +68 -0
  871. templates/astro/rules/frontend.md +20 -0
  872. templates/astro/scaffold/docs/engineering/astro-rules.md +40 -0
  873. templates/astro/scaffold/docs/playbooks/astro-app.md +57 -0
  874. templates/astro/scaffold/docs/playbooks/content-seo.md +37 -0
  875. templates/astro/scaffold/src/frontend/astro.config.mjs +10 -0
  876. templates/astro/scaffold/src/frontend/package.json +23 -0
  877. templates/astro/scaffold/src/frontend/src/components/Greeting.astro +13 -0
  878. templates/astro/scaffold/src/frontend/src/content/posts/hello.md +10 -0
  879. templates/astro/scaffold/src/frontend/src/content.config.ts +19 -0
  880. templates/astro/scaffold/src/frontend/src/lib/problem.test.ts +39 -0
  881. templates/astro/scaffold/src/frontend/src/lib/problem.ts +30 -0
  882. templates/astro/scaffold/src/frontend/src/pages/api/health.ts +13 -0
  883. templates/astro/scaffold/src/frontend/src/pages/index.astro +21 -0
  884. templates/astro/scaffold/src/frontend/tsconfig.json +9 -0
  885. templates/astro/scaffold/src/frontend/vitest.config.ts +10 -0
  886. templates/astro/scaffold-boundary.yaml +28 -0
  887. templates/astro/skills/astro/SKILL.md +71 -0
  888. templates/astro/skills/astro/references/anatomy.md +66 -0
  889. templates/astro/stack.yaml +75 -0
  890. templates/csharp-plain/scaffold/src/backend/Backend.csproj +12 -0
  891. templates/csharp-plain/scaffold/src/backend/Program.cs +1 -0
  892. templates/csharp-plain/scaffold-boundary.yaml +23 -0
  893. templates/csharp-plain/stack.yaml +50 -0
  894. templates/django/rules/backend.md +18 -0
  895. templates/django/scaffold/docs/engineering/anti-ambiguity.md +74 -0
  896. templates/django/scaffold/docs/engineering/backend-rules.md +133 -0
  897. templates/django/scaffold/docs/engineering/glossary.md +51 -0
  898. templates/django/scaffold/docs/engineering/logging-standards.md +107 -0
  899. templates/django/scaffold/docs/engineering/naming-conventions.md +68 -0
  900. templates/django/scaffold/docs/engineering/secrets-rotation-runbook.md +142 -0
  901. templates/django/scaffold/docs/playbooks/backend-api.md +119 -0
  902. templates/django/scaffold/src/backend/config/__init__.py +0 -0
  903. templates/django/scaffold/src/backend/config/settings.py +31 -0
  904. templates/django/scaffold/src/backend/config/urls.py +11 -0
  905. templates/django/scaffold/src/backend/config/wsgi.py +6 -0
  906. templates/django/scaffold/src/backend/manage.py +14 -0
  907. templates/django/scaffold/src/backend/pyproject.toml +37 -0
  908. templates/django/scaffold/src/backend/tests/test_health.py +4 -0
  909. templates/django/scaffold-boundary.yaml +25 -0
  910. templates/django/skills/python-django/SKILL.md +450 -0
  911. templates/django/skills/python-django/references/anatomy.md +117 -0
  912. templates/django/skills/python-django/scripts/new_endpoint.py +89 -0
  913. templates/django/stack.yaml +73 -0
  914. templates/fastapi/rules/backend.md +18 -0
  915. templates/fastapi/scaffold/docs/engineering/fastapi-rules.md +37 -0
  916. templates/fastapi/scaffold/docs/playbooks/fastapi-service.md +30 -0
  917. templates/fastapi/scaffold/src/backend/app/__init__.py +0 -0
  918. templates/fastapi/scaffold/src/backend/app/main.py +8 -0
  919. templates/fastapi/scaffold/src/backend/pyproject.toml +39 -0
  920. templates/fastapi/scaffold/src/backend/tests/test_health.py +11 -0
  921. templates/fastapi/scaffold-boundary.yaml +25 -0
  922. templates/fastapi/skills/python-fastapi/SKILL.md +75 -0
  923. templates/fastapi/skills/python-fastapi/references/anatomy.md +117 -0
  924. templates/fastapi/skills/python-fastapi/scripts/new_endpoint.py +101 -0
  925. templates/fastapi/stack.yaml +57 -0
  926. templates/flutter/rules/mobile.md +26 -0
  927. templates/flutter/scaffold/docs/engineering/flutter-rules.md +35 -0
  928. templates/flutter/scaffold/docs/playbooks/flutter-app.md +45 -0
  929. templates/flutter/scaffold/src/mobile/lib/core/error_mapper.dart +17 -0
  930. templates/flutter/scaffold/src/mobile/lib/core/router.dart +13 -0
  931. templates/flutter/scaffold/src/mobile/lib/main.dart +22 -0
  932. templates/flutter/scaffold/src/mobile/lib/screens/health_screen.dart +32 -0
  933. templates/flutter/scaffold/src/mobile/lib/services/health_service.dart +11 -0
  934. templates/flutter/scaffold/src/mobile/lib/state/health_provider.dart +13 -0
  935. templates/flutter/scaffold/src/mobile/pubspec.yaml +22 -0
  936. templates/flutter/scaffold/src/mobile/test/health_provider_test.dart +90 -0
  937. templates/flutter/scaffold-boundary.yaml +28 -0
  938. templates/flutter/skills/flutter/SKILL.md +76 -0
  939. templates/flutter/skills/flutter/references/anatomy.md +64 -0
  940. templates/flutter/stack.yaml +70 -0
  941. templates/go/rules/backend.md +19 -0
  942. templates/go/scaffold/docs/engineering/go-rules.md +45 -0
  943. templates/go/scaffold/docs/playbooks/go-service.md +30 -0
  944. templates/go/scaffold/src/backend/cmd/api/main.go +22 -0
  945. templates/go/scaffold/src/backend/cmd/api/main_test.go +20 -0
  946. templates/go/scaffold/src/backend/go.mod +3 -0
  947. templates/go/scaffold-boundary.yaml +25 -0
  948. templates/go/skills/go-patterns/SKILL.md +68 -0
  949. templates/go/skills/go-patterns/assets/go-checklist.md +29 -0
  950. templates/go/skills/go-patterns/references/anatomy.md +115 -0
  951. templates/go/skills/go-patterns/references/go-2026-idioms.md +92 -0
  952. templates/go/skills/go-patterns/scripts/new_endpoint.py +117 -0
  953. templates/go/skills/go-patterns/versions.json +16 -0
  954. templates/go/stack.yaml +54 -0
  955. templates/go-fiber/rules/backend.md +20 -0
  956. templates/go-fiber/scaffold/docs/engineering/fiber-rules.md +97 -0
  957. templates/go-fiber/scaffold/docs/playbooks/fiber-service.md +149 -0
  958. templates/go-fiber/scaffold/src/backend/cmd/api/main.go +21 -0
  959. templates/go-fiber/scaffold/src/backend/cmd/api/main_test.go +17 -0
  960. templates/go-fiber/scaffold/src/backend/go.mod +23 -0
  961. templates/go-fiber/scaffold/src/backend/go.sum +49 -0
  962. templates/go-fiber/scaffold-boundary.yaml +26 -0
  963. templates/go-fiber/skills/go-fiber/SKILL.md +203 -0
  964. templates/go-fiber/skills/go-fiber/assets/fiber-checklist.md +26 -0
  965. templates/go-fiber/skills/go-fiber/references/anatomy.md +116 -0
  966. templates/go-fiber/skills/go-fiber/references/fiber-v3-patterns.md +89 -0
  967. templates/go-fiber/skills/go-fiber/scripts/new_endpoint.py +107 -0
  968. templates/go-fiber/skills/go-fiber/versions.json +16 -0
  969. templates/go-fiber/stack.yaml +59 -0
  970. templates/go-plain/scaffold/src/backend/go.mod +3 -0
  971. templates/go-plain/scaffold/src/backend/main.go +7 -0
  972. templates/go-plain/scaffold-boundary.yaml +22 -0
  973. templates/go-plain/stack.yaml +51 -0
  974. templates/java-plain/scaffold/src/backend/mvnw +302 -0
  975. templates/java-plain/scaffold/src/backend/pom.xml +41 -0
  976. templates/java-plain/scaffold/src/backend/src/main/java/com/example/app/Main.java +10 -0
  977. templates/java-plain/scaffold-boundary.yaml +23 -0
  978. templates/java-plain/stack.yaml +51 -0
  979. templates/laravel/rules/backend.md +20 -0
  980. templates/laravel/scaffold/docs/engineering/laravel-rules.md +28 -0
  981. templates/laravel/scaffold/docs/playbooks/laravel-service.md +28 -0
  982. templates/laravel/scaffold/src/backend/app/Exceptions/Handler.php +27 -0
  983. templates/laravel/scaffold/src/backend/app/Http/Controllers/HealthController.php +15 -0
  984. templates/laravel/scaffold/src/backend/app/Support/HealthStatus.php +14 -0
  985. templates/laravel/scaffold/src/backend/composer.json +24 -0
  986. templates/laravel/scaffold/src/backend/phpunit.xml +10 -0
  987. templates/laravel/scaffold/src/backend/public/index.php +8 -0
  988. templates/laravel/scaffold/src/backend/routes/api.php +7 -0
  989. templates/laravel/scaffold/src/backend/tests/Unit/HealthStatusTest.php +16 -0
  990. templates/laravel/scaffold-boundary.yaml +23 -0
  991. templates/laravel/skills/laravel/SKILL.md +56 -0
  992. templates/laravel/skills/laravel/references/anatomy.md +65 -0
  993. templates/laravel/stack.yaml +66 -0
  994. templates/meta/rules/graph-first.md +27 -0
  995. templates/meta/rules/hook-author.md +19 -0
  996. templates/meta/rules/mcp-tool-author.md +18 -0
  997. templates/meta/rules/meta-engineering.md +17 -0
  998. templates/meta/scaffold-boundary.yaml +55 -0
  999. templates/meta/skills/claude-sdk-integration/SKILL.md +163 -0
  1000. templates/meta/skills/claude-sdk-integration/assets/sdk-checklist.md +27 -0
  1001. templates/meta/skills/claude-sdk-integration/scripts/check_model_ids.py +97 -0
  1002. templates/meta/skills/graph-os-authoring/SKILL.md +278 -0
  1003. templates/meta/skills/graph-os-authoring/assets/graph-os-checklist.md +25 -0
  1004. templates/meta/skills/graph-os-authoring/scripts/new_extractor.py +76 -0
  1005. templates/meta/skills/hook-authoring/SKILL.md +292 -0
  1006. templates/meta/skills/hook-authoring/assets/hook-checklist.md +30 -0
  1007. templates/meta/skills/hook-authoring/scripts/new_hook.sh +75 -0
  1008. templates/meta/skills/mcp-tool-authoring/SKILL.md +301 -0
  1009. templates/meta/skills/mcp-tool-authoring/assets/mcp-tool-checklist.md +29 -0
  1010. templates/meta/skills/mcp-tool-authoring/scripts/new_tool.py +74 -0
  1011. templates/meta/skills/meta-engineering/SKILL.md +151 -0
  1012. templates/meta/skills/meta-engineering/assets/meta-edit-checklist.md +28 -0
  1013. templates/meta/skills/meta-engineering/scripts/which_layer.py +61 -0
  1014. templates/meta/skills/python-meta-server/SKILL.md +162 -0
  1015. templates/meta/skills/python-meta-server/assets/meta-server-checklist.md +28 -0
  1016. templates/meta/skills/python-meta-server/scripts/check_envelope.py +91 -0
  1017. templates/meta/skills/react-vite-hub/SKILL.md +140 -0
  1018. templates/meta/skills/react-vite-hub/assets/hub-ui-checklist.md +23 -0
  1019. templates/meta/skills/react-vite-hub/scripts/check_vite_env.py +73 -0
  1020. templates/meta/stack.yaml +119 -0
  1021. templates/nestjs/rules/backend.md +20 -0
  1022. templates/nestjs/scaffold/docs/engineering/nestjs-rules.md +33 -0
  1023. templates/nestjs/scaffold/docs/playbooks/nestjs-service.md +39 -0
  1024. templates/nestjs/scaffold/src/backend/nest-cli.json +5 -0
  1025. templates/nestjs/scaffold/src/backend/package.json +28 -0
  1026. templates/nestjs/scaffold/src/backend/src/app.module.ts +9 -0
  1027. templates/nestjs/scaffold/src/backend/src/common/all-exceptions.filter.ts +59 -0
  1028. templates/nestjs/scaffold/src/backend/src/health/health.controller.ts +14 -0
  1029. templates/nestjs/scaffold/src/backend/src/health/health.module.ts +10 -0
  1030. templates/nestjs/scaffold/src/backend/src/health/health.service.spec.ts +21 -0
  1031. templates/nestjs/scaffold/src/backend/src/health/health.service.ts +9 -0
  1032. templates/nestjs/scaffold/src/backend/src/main.ts +26 -0
  1033. templates/nestjs/scaffold/src/backend/tsconfig.json +16 -0
  1034. templates/nestjs/scaffold/src/backend/vitest.config.ts +9 -0
  1035. templates/nestjs/scaffold-boundary.yaml +25 -0
  1036. templates/nestjs/skills/nestjs/SKILL.md +67 -0
  1037. templates/nestjs/skills/nestjs/references/anatomy.md +65 -0
  1038. templates/nestjs/stack.yaml +68 -0
  1039. templates/nextjs/rules/frontend.md +18 -0
  1040. templates/nextjs/scaffold/docs/design/00-index.md +23 -0
  1041. templates/nextjs/scaffold/docs/design/colors-tokens.md +141 -0
  1042. templates/nextjs/scaffold/docs/design/components-patterns.md +159 -0
  1043. templates/nextjs/scaffold/docs/design/motion-accessibility.md +137 -0
  1044. templates/nextjs/scaffold/docs/design/typography-spacing.md +107 -0
  1045. templates/nextjs/scaffold/docs/engineering/accessibility-web.md +56 -0
  1046. templates/nextjs/scaffold/docs/engineering/copywriting-standard.md +102 -0
  1047. templates/nextjs/scaffold/docs/engineering/formatting-rules.md +89 -0
  1048. templates/nextjs/scaffold/docs/engineering/frontend-rendering-rules.md +80 -0
  1049. templates/nextjs/scaffold/docs/engineering/frontend-rules.md +183 -0
  1050. templates/nextjs/scaffold/docs/engineering/i18n-policy.md +99 -0
  1051. templates/nextjs/scaffold/docs/pages-content-spec/00-index.md +78 -0
  1052. templates/nextjs/scaffold/docs/playbooks/content-seo.md +55 -0
  1053. templates/nextjs/scaffold/docs/playbooks/docs-governance.md +51 -0
  1054. templates/nextjs/scaffold/docs/playbooks/frontend-ui.md +63 -0
  1055. templates/nextjs/scaffold/src/frontend/app/layout.tsx +14 -0
  1056. templates/nextjs/scaffold/src/frontend/app/page.tsx +3 -0
  1057. templates/nextjs/scaffold/src/frontend/eslint.config.js +17 -0
  1058. templates/nextjs/scaffold/src/frontend/lib/greeting.test.ts +9 -0
  1059. templates/nextjs/scaffold/src/frontend/lib/greeting.ts +3 -0
  1060. templates/nextjs/scaffold/src/frontend/package.json +28 -0
  1061. templates/nextjs/scaffold/src/frontend/tsconfig.json +18 -0
  1062. templates/nextjs/scaffold/src/frontend/vitest.config.ts +10 -0
  1063. templates/nextjs/scaffold-boundary.yaml +30 -0
  1064. templates/nextjs/skills/nextjs-react/SKILL.md +485 -0
  1065. templates/nextjs/skills/nextjs-react/references/anatomy.md +116 -0
  1066. templates/nextjs/skills/nextjs-react/scripts/new_component.py +72 -0
  1067. templates/nextjs/stack.yaml +81 -0
  1068. templates/node-express/rules/backend.md +20 -0
  1069. templates/node-express/scaffold/docs/engineering/express-rules.md +30 -0
  1070. templates/node-express/scaffold/docs/playbooks/express-service.md +35 -0
  1071. templates/node-express/scaffold/src/backend/package.json +24 -0
  1072. templates/node-express/scaffold/src/backend/src/index.ts +17 -0
  1073. templates/node-express/scaffold/src/backend/src/middleware/error-handler.ts +12 -0
  1074. templates/node-express/scaffold/src/backend/src/routes/health.test.ts +33 -0
  1075. templates/node-express/scaffold/src/backend/src/routes/health.ts +7 -0
  1076. templates/node-express/scaffold/src/backend/tsconfig.json +15 -0
  1077. templates/node-express/scaffold/src/backend/types/express-bootstrap.d.ts +21 -0
  1078. templates/node-express/scaffold-boundary.yaml +25 -0
  1079. templates/node-express/skills/node-express/SKILL.md +70 -0
  1080. templates/node-express/skills/node-express/references/anatomy.md +63 -0
  1081. templates/node-express/stack.yaml +63 -0
  1082. templates/python/scaffold/docs/engineering/python-rules.md +27 -0
  1083. templates/python/scaffold/docs/playbooks/python-library.md +35 -0
  1084. templates/python/stack.yaml +60 -0
  1085. templates/rails/rules/backend.md +10 -0
  1086. templates/rails/scaffold/docs/engineering/rails-rules.md +33 -0
  1087. templates/rails/scaffold/docs/playbooks/rails-service.md +42 -0
  1088. templates/rails/scaffold/src/backend/Gemfile +12 -0
  1089. templates/rails/scaffold/src/backend/app/controllers/application_controller.rb +26 -0
  1090. templates/rails/scaffold/src/backend/app/controllers/health_controller.rb +6 -0
  1091. templates/rails/scaffold/src/backend/app/models/health.rb +6 -0
  1092. templates/rails/scaffold/src/backend/config/application.rb +12 -0
  1093. templates/rails/scaffold/src/backend/config/boot.rb +3 -0
  1094. templates/rails/scaffold/src/backend/config/routes.rb +4 -0
  1095. templates/rails/scaffold/src/backend/config.ru +5 -0
  1096. templates/rails/scaffold/src/backend/spec/rails_helper.rb +18 -0
  1097. templates/rails/scaffold/src/backend/spec/requests/health_spec.rb +24 -0
  1098. templates/rails/scaffold-boundary.yaml +25 -0
  1099. templates/rails/skills/rails/SKILL.md +62 -0
  1100. templates/rails/skills/rails/references/anatomy.md +71 -0
  1101. templates/rails/stack.yaml +72 -0
  1102. templates/react-native/rules/mobile.md +26 -0
  1103. templates/react-native/scaffold/docs/engineering/accessibility-mobile.md +95 -0
  1104. templates/react-native/scaffold/docs/engineering/mobile-rules.md +56 -0
  1105. templates/react-native/scaffold/docs/engineering/offline-first.md +61 -0
  1106. templates/react-native/scaffold/docs/playbooks/mobile-app.md +49 -0
  1107. templates/react-native/scaffold/src/mobile/App.tsx +9 -0
  1108. templates/react-native/scaffold/src/mobile/eslint.config.js +17 -0
  1109. templates/react-native/scaffold/src/mobile/package.json +23 -0
  1110. templates/react-native/scaffold/src/mobile/src/greeting.test.ts +9 -0
  1111. templates/react-native/scaffold/src/mobile/src/greeting.ts +3 -0
  1112. templates/react-native/scaffold/src/mobile/tsconfig.json +17 -0
  1113. templates/react-native/scaffold/src/mobile/vitest.config.ts +10 -0
  1114. templates/react-native/scaffold-boundary.yaml +30 -0
  1115. templates/react-native/skills/react-native-mobile/SKILL.md +119 -0
  1116. templates/react-native/skills/react-native-mobile/assets/rn-mobile-checklist.md +28 -0
  1117. templates/react-native/skills/react-native-mobile/references/anatomy.md +140 -0
  1118. templates/react-native/skills/react-native-mobile/references/rn-2026-practices.md +54 -0
  1119. templates/react-native/skills/react-native-mobile/scripts/new_screen.py +73 -0
  1120. templates/react-native/skills/react-native-mobile/versions.json +16 -0
  1121. templates/react-native/skills/react-native-patterns/SKILL.md +512 -0
  1122. templates/react-native/skills/react-native-patterns/assets/rn-review-checklist.md +26 -0
  1123. templates/react-native/skills/react-native-patterns/references/anatomy.md +62 -0
  1124. templates/react-native/skills/react-native-patterns/references/list-performance.md +70 -0
  1125. templates/react-native/skills/react-native-patterns/scripts/scan_rn_perf.py +77 -0
  1126. templates/react-native/stack.yaml +70 -0
  1127. templates/ruby-plain/scaffold/src/backend/Gemfile +8 -0
  1128. templates/ruby-plain/scaffold/src/backend/main.rb +3 -0
  1129. templates/ruby-plain/scaffold-boundary.yaml +23 -0
  1130. templates/ruby-plain/stack.yaml +50 -0
  1131. templates/rust-axum/rules/backend.md +20 -0
  1132. templates/rust-axum/scaffold/docs/engineering/rust-axum-rules.md +35 -0
  1133. templates/rust-axum/scaffold/docs/playbooks/rust-axum-service.md +43 -0
  1134. templates/rust-axum/scaffold/src/backend/Cargo.toml +20 -0
  1135. templates/rust-axum/scaffold/src/backend/src/app.rs +12 -0
  1136. templates/rust-axum/scaffold/src/backend/src/error.rs +48 -0
  1137. templates/rust-axum/scaffold/src/backend/src/main.rs +24 -0
  1138. templates/rust-axum/scaffold/src/backend/src/routes/health.rs +37 -0
  1139. templates/rust-axum/scaffold/src/backend/src/routes/mod.rs +2 -0
  1140. templates/rust-axum/scaffold-boundary.yaml +25 -0
  1141. templates/rust-axum/skills/rust/SKILL.md +73 -0
  1142. templates/rust-axum/skills/rust/references/anatomy.md +63 -0
  1143. templates/rust-axum/stack.yaml +65 -0
  1144. templates/rust-plain/scaffold/src/backend/Cargo.toml +6 -0
  1145. templates/rust-plain/scaffold/src/backend/src/main.rs +3 -0
  1146. templates/rust-plain/scaffold-boundary.yaml +23 -0
  1147. templates/rust-plain/stack.yaml +51 -0
  1148. templates/spring-boot/rules/backend.md +20 -0
  1149. templates/spring-boot/scaffold/docs/engineering/spring-boot-rules.md +35 -0
  1150. templates/spring-boot/scaffold/docs/playbooks/spring-boot-service.md +45 -0
  1151. templates/spring-boot/scaffold/src/backend/mvnw +302 -0
  1152. templates/spring-boot/scaffold/src/backend/pom.xml +69 -0
  1153. templates/spring-boot/scaffold/src/backend/src/main/java/com/example/app/Application.java +16 -0
  1154. templates/spring-boot/scaffold/src/backend/src/main/java/com/example/app/common/GlobalExceptionHandler.java +31 -0
  1155. templates/spring-boot/scaffold/src/backend/src/main/java/com/example/app/health/HealthController.java +22 -0
  1156. templates/spring-boot/scaffold/src/backend/src/main/java/com/example/app/health/HealthService.java +12 -0
  1157. templates/spring-boot/scaffold/src/backend/src/main/java/com/example/app/health/HealthStatus.java +4 -0
  1158. templates/spring-boot/scaffold/src/backend/src/test/java/com/example/app/health/HealthServiceTest.java +15 -0
  1159. templates/spring-boot/scaffold-boundary.yaml +26 -0
  1160. templates/spring-boot/skills/spring-boot/SKILL.md +84 -0
  1161. templates/spring-boot/skills/spring-boot/references/anatomy.md +63 -0
  1162. templates/spring-boot/stack.yaml +65 -0
  1163. templates/svelte-sveltekit/rules/frontend.md +20 -0
  1164. templates/svelte-sveltekit/scaffold/docs/engineering/svelte-sveltekit-rules.md +37 -0
  1165. templates/svelte-sveltekit/scaffold/docs/playbooks/svelte-sveltekit-app.md +36 -0
  1166. templates/svelte-sveltekit/scaffold/src/frontend/package.json +22 -0
  1167. templates/svelte-sveltekit/scaffold/src/frontend/src/app.html +12 -0
  1168. templates/svelte-sveltekit/scaffold/src/frontend/src/hooks.server.ts +14 -0
  1169. templates/svelte-sveltekit/scaffold/src/frontend/src/lib/components/Greeting.svelte +6 -0
  1170. templates/svelte-sveltekit/scaffold/src/frontend/src/lib/stores/count.test.ts +26 -0
  1171. templates/svelte-sveltekit/scaffold/src/frontend/src/lib/stores/count.ts +4 -0
  1172. templates/svelte-sveltekit/scaffold/src/frontend/src/routes/+layout.svelte +24 -0
  1173. templates/svelte-sveltekit/scaffold/src/frontend/src/routes/+page.svelte +9 -0
  1174. templates/svelte-sveltekit/scaffold/src/frontend/src/routes/+page.ts +7 -0
  1175. templates/svelte-sveltekit/scaffold/src/frontend/src/routes/health/+server.ts +7 -0
  1176. templates/svelte-sveltekit/scaffold/src/frontend/svelte.config.js +10 -0
  1177. templates/svelte-sveltekit/scaffold/src/frontend/tsconfig.json +7 -0
  1178. templates/svelte-sveltekit/scaffold/src/frontend/vite.config.ts +7 -0
  1179. templates/svelte-sveltekit/scaffold/src/frontend/vitest.config.ts +11 -0
  1180. templates/svelte-sveltekit/scaffold-boundary.yaml +29 -0
  1181. templates/svelte-sveltekit/skills/svelte/SKILL.md +90 -0
  1182. templates/svelte-sveltekit/skills/svelte/references/anatomy.md +62 -0
  1183. templates/svelte-sveltekit/stack.yaml +70 -0
  1184. templates/typescript-plain/scaffold/src/index.ts +3 -0
  1185. templates/typescript-plain/scaffold/tsconfig.json +13 -0
  1186. templates/typescript-plain/scaffold-boundary.yaml +22 -0
  1187. templates/typescript-plain/stack.yaml +44 -0
  1188. templates/vue-nuxt/rules/frontend.md +19 -0
  1189. templates/vue-nuxt/scaffold/docs/engineering/nuxt-rules.md +30 -0
  1190. templates/vue-nuxt/scaffold/docs/playbooks/nuxt-app.md +29 -0
  1191. templates/vue-nuxt/scaffold/src/frontend/app.vue +3 -0
  1192. templates/vue-nuxt/scaffold/src/frontend/nuxt.config.ts +11 -0
  1193. templates/vue-nuxt/scaffold/src/frontend/package.json +20 -0
  1194. templates/vue-nuxt/scaffold/src/frontend/pages/index.test.ts +19 -0
  1195. templates/vue-nuxt/scaffold/src/frontend/pages/index.vue +11 -0
  1196. templates/vue-nuxt/scaffold/src/frontend/vitest.config.ts +12 -0
  1197. templates/vue-nuxt/scaffold-boundary.yaml +26 -0
  1198. templates/vue-nuxt/skills/vue-nuxt/SKILL.md +57 -0
  1199. templates/vue-nuxt/skills/vue-nuxt/references/anatomy.md +60 -0
  1200. templates/vue-nuxt/stack.yaml +61 -0
  1201. templates/wordpress/rules/backend.md +19 -0
  1202. templates/wordpress/scaffold/docs/engineering/wordpress-rules.md +28 -0
  1203. templates/wordpress/scaffold/docs/playbooks/wordpress-service.md +29 -0
  1204. templates/wordpress/scaffold/src/backend/composer.json +17 -0
  1205. templates/wordpress/scaffold/src/backend/phpcs.xml.dist +11 -0
  1206. templates/wordpress/scaffold/src/backend/phpunit.xml +10 -0
  1207. templates/wordpress/scaffold/src/backend/plugin/inc/health.php +8 -0
  1208. templates/wordpress/scaffold/src/backend/plugin/plugin.php +28 -0
  1209. templates/wordpress/scaffold/src/backend/tests/HealthStatusTest.php +15 -0
  1210. templates/wordpress/scaffold/src/backend/theme/functions.php +18 -0
  1211. templates/wordpress/scaffold/src/backend/theme/style.css +11 -0
  1212. templates/wordpress/scaffold-boundary.yaml +23 -0
  1213. templates/wordpress/skills/wordpress/SKILL.md +110 -0
  1214. templates/wordpress/skills/wordpress/assets/wp-checklist.md +28 -0
  1215. templates/wordpress/skills/wordpress/references/wp-development.md +75 -0
  1216. templates/wordpress/skills/wordpress/references/wp-security.md +68 -0
  1217. templates/wordpress/skills/wordpress/scripts/scan_wp_smells.py +91 -0
  1218. templates/wordpress/skills/wordpress/versions.json +16 -0
  1219. templates/wordpress/stack.yaml +60 -0
  1220. thinking_os/__init__.py +1 -0
  1221. thinking_os/_agent_markers.py +32 -0
  1222. thinking_os/background.py +405 -0
  1223. thinking_os/bootstrap_outcomes.py +200 -0
  1224. thinking_os/budget.py +302 -0
  1225. thinking_os/capture.py +495 -0
  1226. thinking_os/cognition.py +516 -0
  1227. thinking_os/cognition_schemas.py +517 -0
  1228. thinking_os/compress.py +192 -0
  1229. thinking_os/concepts.py +233 -0
  1230. thinking_os/dashboard.py +159 -0
  1231. thinking_os/database.py +2883 -0
  1232. thinking_os/decay.py +393 -0
  1233. thinking_os/digest.py +295 -0
  1234. thinking_os/dispatcher.py +192 -0
  1235. thinking_os/dispatcher_helpers.py +48 -0
  1236. thinking_os/dispatchers/__init__.py +3 -0
  1237. thinking_os/dispatchers/default.py +47 -0
  1238. thinking_os/distill.py +192 -0
  1239. thinking_os/doc_indexer.py +905 -0
  1240. thinking_os/embeddings.py +943 -0
  1241. thinking_os/formula_composer.py +556 -0
  1242. thinking_os/gate_marker.py +75 -0
  1243. thinking_os/graph.py +296 -0
  1244. thinking_os/graph_indexer.py +360 -0
  1245. thinking_os/health_check.py +517 -0
  1246. thinking_os/impact.py +119 -0
  1247. thinking_os/memory_gc.py +356 -0
  1248. thinking_os/migrator_embeddings.py +318 -0
  1249. thinking_os/precision.py +194 -0
  1250. thinking_os/record_outcome.py +399 -0
  1251. thinking_os/repair.py +105 -0
  1252. thinking_os/retrieval_quality.py +239 -0
  1253. thinking_os/roles_state.py +168 -0
  1254. thinking_os/sanitizer.py +320 -0
  1255. thinking_os/server.py +3160 -0
  1256. thinking_os/session_enrich.py +272 -0
  1257. thinking_os/session_observe_worker.py +111 -0
  1258. thinking_os/session_startup.py +74 -0
  1259. thinking_os/session_summary.py +245 -0
  1260. thinking_os/task_analyzer.py +462 -0
  1261. thinking_os/task_parser.py +342 -0
  1262. thinking_os/task_sync.py +73 -0
  1263. thinking_os/tools/__init__.py +6 -0
  1264. thinking_os/tools/_shared.py +947 -0
  1265. thinking_os/tools/cognition.py +1867 -0
  1266. thinking_os/tools/docs.py +770 -0
  1267. thinking_os/tools/learning.py +2078 -0
  1268. thinking_os/tools/logs.py +79 -0
  1269. thinking_os/tools/memory.py +840 -0
  1270. thinking_os/tools/metrics.py +200 -0
  1271. thinking_os/tools/retrieve.py +415 -0
  1272. thinking_os/tools/routing.py +658 -0
  1273. thinking_os/tools/tasks.py +449 -0
  1274. thinking_os/tools/trajectory.py +181 -0
  1275. thinking_os/tracing.py +235 -0
  1276. web/__init__.py +5 -0
  1277. web/_cache.py +118 -0
  1278. web/_deps.py +56 -0
  1279. web/_envelope.py +85 -0
  1280. web/_project_context.py +140 -0
  1281. web/chat_providers.py +108 -0
  1282. web/init_jobs.py +216 -0
  1283. web/routes/__init__.py +25 -0
  1284. web/routes/_bounded_read.py +76 -0
  1285. web/routes/board.py +1089 -0
  1286. web/routes/cognition.py +1838 -0
  1287. web/routes/config.py +635 -0
  1288. web/routes/graph.py +513 -0
  1289. web/routes/health.py +180 -0
  1290. web/routes/hooks.py +288 -0
  1291. web/routes/hub.py +1219 -0
  1292. web/routes/logs.py +374 -0
  1293. web/routes/metrics.py +43 -0
  1294. web/routes/observability.py +400 -0
  1295. web/routes/patterns.py +227 -0
  1296. web/routes/presence.py +609 -0
  1297. web/routes/roles.py +446 -0
  1298. web/routes/scheduled.py +261 -0
  1299. web/routes/search.py +238 -0
  1300. web/routes/sessions.py +220 -0
  1301. web/routes/settings.py +363 -0
  1302. web/routes/stream.py +547 -0
  1303. web/security.py +157 -0
  1304. web/server.py +283 -0
cli/board_commands.py ADDED
@@ -0,0 +1,1218 @@
1
+ """cos board-* CLI commands.
2
+
3
+ Commands:
4
+ cos board [--web] [--port N] [--swimlane] [--kind] [--epic] [--priority]
5
+ cos task-create
6
+ cos task-move
7
+ cos task-start / task-done / task-block / task-cancel
8
+ cos task-pick
9
+ cos task-archive
10
+ cos daily / retro
11
+ cos task-show / task-log / task-history / wip
12
+ cos task-validate
13
+ cos board-config --init
14
+
15
+ Thin click wrappers over core.board_os.{mcp_tools,workflow,parser,sync}.
16
+ All commands use the project's SQLite DB (.coding-os/coding-os.db)
17
+ unless COS_DB_PATH overrides.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import json
23
+ import os
24
+ import sqlite3
25
+ import sys
26
+ from pathlib import Path
27
+
28
+ import click
29
+
30
+ # Bootstrap so imports work whether invoked via `cos` entry-point or bare python.
31
+ _REPO_ROOT = Path(__file__).resolve().parent.parent.parent
32
+ if str(_REPO_ROOT) not in sys.path:
33
+ sys.path.insert(0, str(_REPO_ROOT))
34
+
35
+
36
+ def _project_root() -> Path:
37
+ from thinking_os.database import project_root
38
+
39
+ return project_root()
40
+
41
+
42
+ def _db_conn() -> sqlite3.Connection:
43
+ root = _project_root()
44
+ db_path = os.environ.get(
45
+ "COS_DB_PATH",
46
+ str(root / ".coding-os" / "coding-os.db"),
47
+ )
48
+ if not Path(db_path).exists():
49
+ click.echo(f"ERROR: DB not found at {db_path}. Run `cos setup` first.", err=True)
50
+ sys.exit(1)
51
+ return sqlite3.connect(db_path)
52
+
53
+
54
+ def _known_agent_ids() -> tuple[frozenset[str], dict[str, tuple[str, ...]]]:
55
+ """Load adapter ids + their runtime env markers from adapter registry."""
56
+ from cli._resources import adapters_dir as _adapters_root
57
+
58
+ adapters_dir = _adapters_root()
59
+ try:
60
+ from cli.adapter_registry import load_adapter_registry
61
+
62
+ reg = load_adapter_registry(adapters_dir)
63
+ except Exception as exc:
64
+ import logging as _logging
65
+
66
+ _logging.getLogger("cli.board_commands").debug(
67
+ "adapter registry unreachable, agent detection degrades to marker-only: %s",
68
+ exc,
69
+ )
70
+ return frozenset(), {}
71
+ ids = frozenset(reg.keys())
72
+ markers = {aid: tuple(p.runtime_env_markers) for aid, p in reg.items()}
73
+ return ids, markers
74
+
75
+
76
+ def _detect_agent_runtime() -> str | None:
77
+ """Detect which agent runtime is invoking this CLI process.
78
+
79
+ DRIFT WARNING: The same priority table is maintained in shell form
80
+ at src/core/hooks/cos-env.sh. Update both sides when changing
81
+ priorities. Only the adapter-id names are data-driven; the
82
+ overall ordering (explicit override → vendor markers →
83
+ marker file → legacy Claude alias) lives in both files.
84
+ """
85
+ known_ids, markers_by_id = _known_agent_ids()
86
+
87
+ explicit = (os.environ.get("COS_AGENT") or "").strip().lower()
88
+ if explicit and explicit in known_ids:
89
+ return explicit
90
+
91
+ # Alphabetical sort keeps detection deterministic. The env-marker
92
+ # sets declared by each adapter.yaml don't overlap (CODEX_* vs
93
+ # CLAUDE_*) so order is irrelevant to correctness — and
94
+ # we never hardcode adapter-name literals here (rule #11). The
95
+ # legacy CLAUDE_PROJECT_DIR fallback below is the only place
96
+ # disambiguation matters, and it gates on "no stronger marker
97
+ # fired" so a real vendor-marker match already short-circuited.
98
+ for agent_id in sorted(known_ids):
99
+ for env_key in markers_by_id.get(agent_id, ()):
100
+ if os.environ.get(env_key):
101
+ return agent_id
102
+
103
+ marker = _project_root() / ".coding-os" / ".agent"
104
+ if marker.is_file():
105
+ try:
106
+ raw = marker.read_text(encoding="utf-8", errors="ignore").strip().lower()
107
+ except OSError:
108
+ raw = ""
109
+ if raw and raw in known_ids:
110
+ return raw
111
+
112
+ # Legacy compatibility marker: other IDEs also set CLAUDE_PROJECT_DIR, so
113
+ # only trust it when no stronger signal fired. The target adapter id
114
+ # is looked up rather than hardcoded so the Claude rename never
115
+ # strands this path.
116
+ if os.environ.get("CLAUDE_PROJECT_DIR"):
117
+ for aid in known_ids:
118
+ if any(env_key.startswith("CLAUDE") for env_key in markers_by_id.get(aid, ())):
119
+ return aid
120
+ return None
121
+
122
+
123
+ def _agent_session_id() -> str | None:
124
+ """Best-effort agent session resolver for CLI-originated task transitions."""
125
+ sid = os.environ.get("COS_AGENT_SESSION_ID")
126
+ if sid:
127
+ return sid.strip() or None
128
+
129
+ def _first(p: Path) -> str | None:
130
+ if not p.is_absolute():
131
+ p = _project_root() / p
132
+ if not p.is_file():
133
+ return None
134
+ try:
135
+ raw = p.read_text(encoding="utf-8", errors="ignore").strip()
136
+ except OSError:
137
+ return None
138
+ return raw or None
139
+
140
+ # Panel-first (most accurate when a hook set $COS_PANEL_DIR), then the
141
+ # agent-level fresh `.active-session` pointer session-context.sh keeps
142
+ # current, then the legacy flat session-id fossil. Mirrors the MCP
143
+ # server's _detect_agent_session_default.
144
+ panel_dir_env = os.environ.get("COS_PANEL_DIR")
145
+ if panel_dir_env:
146
+ raw = _first(Path(panel_dir_env) / "session-id")
147
+ if raw:
148
+ return raw
149
+ agent_dir_env = os.environ.get("COS_AGENT_DIR")
150
+ if agent_dir_env:
151
+ for _fname in (".active-session", "session-id"):
152
+ raw = _first(Path(agent_dir_env) / _fname)
153
+ if raw:
154
+ return raw
155
+
156
+ runtime = _detect_agent_runtime()
157
+ if runtime is None:
158
+ return None
159
+ # Plain shells (no COS_* env) land here. Mirror the env'd branch above:
160
+ # `.active-session` is refreshed every prompt by session-context.sh,
161
+ # while the flat `session-id` is a legacy fossil frozen at its last
162
+ # SessionStart — trusting it first mis-attributed weeks-old session ids
163
+ # to fresh CLI mutations (TASK-341).
164
+ runtime_dir = _project_root() / ".coding-os" / runtime
165
+ for _fname in (".active-session", "session-id"):
166
+ raw = _first(runtime_dir / _fname)
167
+ if raw:
168
+ return raw
169
+ return None
170
+
171
+
172
+ def _parse_envelope(envelope: str) -> dict:
173
+ return json.loads(envelope)
174
+
175
+
176
+ def _print_envelope(envelope: str, *, format: str = "text") -> int:
177
+ data = _parse_envelope(envelope)
178
+ if format == "json":
179
+ click.echo(json.dumps(data, indent=2, ensure_ascii=False))
180
+ return 0 if data.get("ok") else 1
181
+ if not data.get("ok"):
182
+ click.echo(f"ERROR [{data['error']['category']}]: {data['error']['message']}", err=True)
183
+ return 1
184
+ click.echo(json.dumps(data["data"], indent=2, ensure_ascii=False))
185
+ return 0
186
+
187
+
188
+ # ---------------------------------------------------------------------------
189
+ # cos board
190
+ # ---------------------------------------------------------------------------
191
+
192
+
193
+ def _launch_board_in_spa(*, host: str, port: int) -> None:
194
+ """Open the unified SPA Board page; auto-start `cos web` if needed."""
195
+ import urllib.error
196
+ import urllib.request
197
+ import webbrowser
198
+
199
+ url = f"http://{host}:{port}/board"
200
+ health_url = f"http://{host}:{port}/health"
201
+
202
+ def _server_up() -> bool:
203
+ try:
204
+ with urllib.request.urlopen(health_url, timeout=0.5) as resp:
205
+ return resp.status == 200
206
+ except (urllib.error.URLError, OSError):
207
+ return False
208
+
209
+ if _server_up():
210
+ click.echo(f"Opening {url} (web server already running).")
211
+ webbrowser.open(url)
212
+ return
213
+
214
+ click.echo(f"Starting Coding OS web server on {host}:{port} ... (Ctrl-C to stop)")
215
+ click.echo(f"Once it is up, open {url} in your browser.")
216
+ try:
217
+ from web.server import run_server
218
+ except ImportError as exc:
219
+ click.echo(
220
+ f"ERROR: could not import core.web.server: {exc}\nInstall web extras: uv sync",
221
+ err=True,
222
+ )
223
+ sys.exit(1)
224
+ run_server(host=host, port=port)
225
+
226
+
227
+ @click.command("board", help="Show Scrumban board (ASCII or --web)")
228
+ @click.option(
229
+ "--web",
230
+ is_flag=True,
231
+ default=False,
232
+ help="Open board in browser (redirects to unified SPA at /board)",
233
+ )
234
+ @click.option(
235
+ "--port", type=int, default=9188, help="Port for the unified web server when --web is used."
236
+ )
237
+ @click.option("--host", default="127.0.0.1")
238
+ @click.option("--bind", default=None, help="Bind address (overrides --host)")
239
+ @click.option("--swimlane", default=None)
240
+ @click.option("--kind", default=None)
241
+ @click.option("--epic", default=None)
242
+ @click.option("--priority", default=None, help="Comma-separated (e.g. P0,P1)")
243
+ @click.option("--format", type=click.Choice(["text", "json"]), default="text")
244
+ def board_cmd(web, port, host, bind, swimlane, kind, epic, priority, format):
245
+ from board_os import mcp_tools
246
+
247
+ if web:
248
+ _launch_board_in_spa(host=(bind or host), port=port)
249
+ return
250
+ conn = _db_conn()
251
+ try:
252
+ envelope = mcp_tools.cos_task_board(
253
+ conn,
254
+ swimlane=swimlane,
255
+ kind=kind,
256
+ epic=epic,
257
+ )
258
+ finally:
259
+ conn.close()
260
+
261
+ # Client-side priority filter (MCP tool doesn't expose it yet).
262
+ if priority:
263
+ allowed = {p.strip().upper() for p in priority.split(",") if p.strip()}
264
+ parsed = _parse_envelope(envelope)
265
+ if parsed.get("ok"):
266
+ cards = parsed["data"].get("cards", [])
267
+ parsed["data"]["cards"] = [c for c in cards if c.get("priority") in allowed]
268
+ parsed["data"]["count"] = len(parsed["data"]["cards"])
269
+ envelope = json.dumps(parsed)
270
+
271
+ if format == "text":
272
+ _render_board_ascii(envelope)
273
+ else:
274
+ click.echo(envelope)
275
+
276
+
277
+ def _render_board_ascii(envelope: str) -> None:
278
+ env = _parse_envelope(envelope)
279
+ if not env.get("ok"):
280
+ click.echo(f"ERROR: {env['error']['message']}", err=True)
281
+ return
282
+ data = env["data"]
283
+ grouped = data.get("grouped", {})
284
+ wip = data.get("wip") or {}
285
+
286
+ click.echo("\n Scrumban Board")
287
+ click.echo(" " + "─" * 60)
288
+ if wip.get("counts"):
289
+ parts = []
290
+ for col in ("in_progress", "testing", "emergency"):
291
+ n = wip["counts"].get(col, 0)
292
+ c = wip["caps"].get(col, "?")
293
+ mark = "🔴" if col in wip.get("violations", []) else "·"
294
+ parts.append(f"{col} {n}/{c} {mark}")
295
+ click.echo(" WIP: " + " | ".join(parts))
296
+ click.echo()
297
+
298
+ statuses = ["icebox", "ready", "emergency", "in_progress", "testing", "blocked"]
299
+ for lane in sorted(grouped.keys()):
300
+ click.echo(f" ── {lane} ──")
301
+ for status in statuses:
302
+ cards = grouped[lane].get(status, [])
303
+ if not cards:
304
+ continue
305
+ click.echo(f" [{status}]")
306
+ for card in cards:
307
+ badge = {
308
+ "bug": "🔴",
309
+ "feature": "🟡",
310
+ "chore": "🟢",
311
+ "spike": "🔵",
312
+ "docs": "🟣",
313
+ "refactor": "🟦",
314
+ "test": "🟧",
315
+ "security": "🟠",
316
+ }.get(card["kind"], "⚪")
317
+ # READY overlay: icebox cards carrying the "ready" label are
318
+ # pickup candidates (see board_os.config::READY_LABEL). We
319
+ # surface this as a "✓READY" prefix so the CLI matches the
320
+ # green pill rendered by the web Board.
321
+ labels = card.get("labels") or []
322
+ ready_prefix = " ✓READY " if status == "icebox" and "ready" in labels else ""
323
+ click.echo(
324
+ f" {badge}{ready_prefix} {card['id']} [{card['priority']}] {card['title']}"
325
+ )
326
+ click.echo()
327
+
328
+
329
+ # ---------------------------------------------------------------------------
330
+ # task-create / task-move / task-start / task-done / task-block / task-cancel
331
+ # ---------------------------------------------------------------------------
332
+
333
+
334
+ @click.command("task-create", help="Create a new Scrumban task (lean template).")
335
+ @click.option("--title", required=True)
336
+ @click.option("--swimlane", required=True)
337
+ @click.option(
338
+ "--kind",
339
+ required=True,
340
+ type=click.Choice(["feature", "bug", "chore", "spike", "docs", "refactor", "test", "security"]),
341
+ )
342
+ @click.option("--priority", default="P2", type=click.Choice(["P0", "P1", "P2", "P3"]))
343
+ @click.option("--appetite", default="1d")
344
+ @click.option("--epic", default=None)
345
+ @click.option("--labels", default="", help="Comma-separated free tags")
346
+ @click.option("--outcome", default=None, help="One measurable sentence — the task's goal.")
347
+ @click.option(
348
+ "--acceptance",
349
+ default=None,
350
+ help="Acceptance G/W/T markdown (e.g. '- **Given** ...\\n- **When** ...\\n- **Then** ...'). "
351
+ "Required to start feature/bug/refactor/test/security tasks.",
352
+ )
353
+ @click.option(
354
+ "--read-first",
355
+ multiple=True,
356
+ help="Doc path(s) for the Read First section — repeatable and/or comma-separated. "
357
+ "(Was a single comma-only flag; repeating it silently kept only the last value.)",
358
+ )
359
+ @click.option("--depends-on", default="", help="Comma-separated TASK-IDs")
360
+ @click.option("--ready", is_flag=True, default=False, help="Mark the task pullable in one shot.")
361
+ def task_create_cmd(
362
+ title,
363
+ swimlane,
364
+ kind,
365
+ priority,
366
+ appetite,
367
+ epic,
368
+ labels,
369
+ outcome,
370
+ acceptance,
371
+ read_first,
372
+ depends_on,
373
+ ready,
374
+ ):
375
+ from board_os import mcp_tools
376
+
377
+ conn = _db_conn()
378
+ try:
379
+ envelope = mcp_tools.cos_task_create(
380
+ conn,
381
+ title=title,
382
+ swimlane=swimlane,
383
+ kind=kind,
384
+ priority=priority,
385
+ appetite=appetite,
386
+ epic=epic,
387
+ labels=[l.strip() for l in labels.split(",") if l.strip()],
388
+ outcome=outcome,
389
+ acceptance=acceptance,
390
+ read_first=[p.strip() for chunk in read_first for p in chunk.split(",") if p.strip()]
391
+ or None,
392
+ depends_on=[d.strip() for d in depends_on.split(",") if d.strip()],
393
+ ready=ready,
394
+ agent_session=_agent_session_id(),
395
+ )
396
+ finally:
397
+ conn.close()
398
+ sys.exit(_print_envelope(envelope))
399
+
400
+
401
+ @click.command("task-move")
402
+ @click.argument("task_id")
403
+ @click.option("--to", required=True)
404
+ @click.option("--reason", default=None)
405
+ @click.option(
406
+ "--force",
407
+ is_flag=True,
408
+ default=False,
409
+ help="Override WIP caps AND state-machine validation "
410
+ "(e.g. archive → in_progress after an accidental archive).",
411
+ )
412
+ def task_move_cmd(task_id, to, reason, force):
413
+ from board_os import mcp_tools
414
+
415
+ conn = _db_conn()
416
+ try:
417
+ envelope = mcp_tools.cos_task_move(
418
+ conn,
419
+ task_id=task_id,
420
+ to=to,
421
+ reason=reason or "cli:task-move (no --reason given)",
422
+ bypass_wip=force,
423
+ force=force,
424
+ agent_session=_agent_session_id(),
425
+ )
426
+ finally:
427
+ conn.close()
428
+ sys.exit(_print_envelope(envelope))
429
+
430
+
431
+ def _simple_move(task_id: str, to: str, *, reason: str | None = None, force: bool = False):
432
+ from board_os import mcp_tools
433
+
434
+ conn = _db_conn()
435
+ try:
436
+ envelope = mcp_tools.cos_task_move(
437
+ conn,
438
+ task_id=task_id,
439
+ to=to,
440
+ reason=reason,
441
+ bypass_wip=force,
442
+ agent_session=_agent_session_id(),
443
+ )
444
+ finally:
445
+ conn.close()
446
+ sys.exit(_print_envelope(envelope))
447
+
448
+
449
+ @click.command(
450
+ "task-reconcile",
451
+ help="Review stranded tasks with completion evidence — recommends complete/resume/park (read-only).",
452
+ )
453
+ @click.option(
454
+ "--include-active",
455
+ is_flag=True,
456
+ default=False,
457
+ help="Also review tasks whose owner session is still active.",
458
+ )
459
+ def task_reconcile_cmd(include_active):
460
+ from board_os import mcp_tools
461
+
462
+ conn = _db_conn()
463
+ try:
464
+ envelope = mcp_tools.cos_task_reconcile(conn, include_active=include_active)
465
+ finally:
466
+ conn.close()
467
+ env = _parse_envelope(envelope)
468
+ if not env["ok"]:
469
+ click.echo(f"ERROR: {env['error']['message']}", err=True)
470
+ sys.exit(1)
471
+ data = env["data"]
472
+ s = data["summary"]
473
+ click.echo(
474
+ f"\n Stranded tasks: {data['count']} "
475
+ f"(likely-complete {s['likely_complete']} · "
476
+ f"likely-abandoned {s['likely_abandoned']} · needs-review {s['needs_review']})"
477
+ )
478
+ for it in data["stranded"]:
479
+ commits = it["commits_referencing"]
480
+ commits_str = "?" if commits is None else commits
481
+ click.echo(
482
+ f"\n {it['task_id']} [{it['status']} {it['status_dwell_human']}] "
483
+ f"→ {it['classification']} ({commits_str} commit(s))"
484
+ )
485
+ click.echo(f" {it['recommendation']}")
486
+ click.echo()
487
+
488
+
489
+ def _current_status(task_id: str) -> str | None:
490
+ conn = _db_conn()
491
+ try:
492
+ row = conn.execute("SELECT status FROM tasks WHERE task_id = ?", (task_id,)).fetchone()
493
+ finally:
494
+ conn.close()
495
+ return row[0] if row else None
496
+
497
+
498
+ @click.command("task-start")
499
+ @click.argument("task_id")
500
+ @click.option(
501
+ "--force",
502
+ is_flag=True,
503
+ default=False,
504
+ help="Override the WIP cap only. Readiness + Definition-of-Ready stay enforced; "
505
+ "set COS_DOR_OVERRIDE=1 with COS_OVERRIDE_REASON to bypass the gate.",
506
+ )
507
+ def task_start_cmd(task_id, force):
508
+ _simple_move(task_id, "in_progress", force=force)
509
+
510
+
511
+ @click.command("task-ready", help="Toggle the 'ready' label that gates icebox→in_progress.")
512
+ @click.argument("task_id")
513
+ @click.option(
514
+ "--off", is_flag=True, default=False, help="Remove the ready label instead of adding it."
515
+ )
516
+ def task_ready_cmd(task_id, off):
517
+ from board_os import mcp_tools
518
+
519
+ conn = _db_conn()
520
+ try:
521
+ envelope = mcp_tools.cos_task_ready(
522
+ conn,
523
+ task_id=task_id,
524
+ ready=not off,
525
+ agent_session=_agent_session_id(),
526
+ )
527
+ finally:
528
+ conn.close()
529
+ sys.exit(_print_envelope(envelope))
530
+
531
+
532
+ @click.command(
533
+ "task-reclaim", help="Reclaim zombie in_progress tasks (idle + owner inactive) to icebox+ready."
534
+ )
535
+ @click.option(
536
+ "--idle-hours", type=int, default=0, help="Override the idle threshold (0 = config default)."
537
+ )
538
+ @click.option("--dry-run", is_flag=True, default=False, help="List candidates without moving them.")
539
+ def task_reclaim_cmd(idle_hours, dry_run):
540
+ from board_os import mcp_tools
541
+
542
+ conn = _db_conn()
543
+ try:
544
+ envelope = mcp_tools.cos_task_reclaim(
545
+ conn,
546
+ idle_hours=idle_hours or None,
547
+ dry_run=dry_run,
548
+ agent_session=_agent_session_id(),
549
+ )
550
+ finally:
551
+ conn.close()
552
+ sys.exit(_print_envelope(envelope))
553
+
554
+
555
+ _KIND_TO_OUTCOME_TYPE = {
556
+ "bug": "fix",
557
+ "feature": "feat",
558
+ "refactor": "refactor",
559
+ "docs": "docs",
560
+ "test": "test",
561
+ "chore": "infra",
562
+ }
563
+
564
+ _brain_logger = __import__("logging").getLogger("cli.board.brain")
565
+
566
+
567
+ def _record_brain_outcome_safe(conn: sqlite3.Connection, task_id: str) -> None:
568
+ """Fire-and-forget: mirror task-done into the thinking_os learning loop.
569
+
570
+ Writes task_outcomes + outcome_history, back-fills retrievals.outcome for
571
+ every row that cited this task, and triggers learn_extract each 10th
572
+ successful outcome. Any failure is logged at DEBUG — task-done must never
573
+ surface a brain-pipeline failure to the user.
574
+ """
575
+ derived_outcome = "success" # refined below if record_outcome derives 'rework'
576
+ try:
577
+ from thinking_os.record_outcome import record_outcome
578
+
579
+ row = conn.execute(
580
+ "SELECT kind, title FROM tasks WHERE task_id = ?",
581
+ (task_id,),
582
+ ).fetchone()
583
+ kind = row[0] if row else "feature"
584
+ msg = row[1] if row else ""
585
+ task_type = _KIND_TO_OUTCOME_TYPE.get(kind, "feat")
586
+ db_path = os.environ.get(
587
+ "COS_DB_PATH",
588
+ str(_project_root() / ".coding-os" / "coding-os.db"),
589
+ )
590
+ _oc = record_outcome(
591
+ task_id=task_id,
592
+ task_type=task_type,
593
+ outcome="success",
594
+ msg=msg,
595
+ db_path=db_path,
596
+ )
597
+ # record_outcome refines 'success' → 'rework' from task history; carry
598
+ # that derived value to the retrievals back-fill below so it is not a
599
+ # SECOND hardcoded-'success' writer (the exact bug class in this file).
600
+ if isinstance(_oc, dict) and _oc.get("outcome"):
601
+ derived_outcome = _oc["outcome"]
602
+ # Stamp the model onto the fresh row so routing_weights has input.
603
+ # COS_AGENT_MODEL is set by adapter startup; unknown → leave null.
604
+ model = os.environ.get("COS_AGENT_MODEL") or os.environ.get("ANTHROPIC_MODEL")
605
+ if model:
606
+ try:
607
+ conn.execute(
608
+ "UPDATE task_outcomes SET model = ? WHERE task_id = ? AND model IS NULL",
609
+ (model, task_id),
610
+ )
611
+ conn.commit()
612
+ except Exception as exc:
613
+ _brain_logger.debug("model stamp failed for %s: %s", task_id, exc)
614
+ except Exception as exc:
615
+ _brain_logger.debug("record_outcome failed for %s: %s", task_id, exc)
616
+ return
617
+
618
+ # retrievals.task_id is composite ("<session_id> <task_slug>") in some
619
+ # writers, plain TASK-NNN in others — match both shapes defensively.
620
+ try:
621
+ conn.execute(
622
+ "UPDATE retrievals SET outcome = ?, outcome_at = CURRENT_TIMESTAMP "
623
+ "WHERE outcome IS NULL AND (task_id = ? OR task_id LIKE ?)",
624
+ (derived_outcome, task_id, f"%{task_id}%"),
625
+ )
626
+ conn.commit()
627
+ except Exception as exc:
628
+ _brain_logger.debug("retrieval back-fill failed for %s: %s", task_id, exc)
629
+
630
+ try:
631
+ count = conn.execute("SELECT COUNT(*) FROM task_outcomes").fetchone()[0]
632
+ if count > 0 and count % 10 == 0:
633
+ from scheduled._activity import outcomes_since_marker
634
+ from scheduled._state import state_dir, touch_marker
635
+ from thinking_os.database import resolve_db_path
636
+ from thinking_os.tools.learning import learn_extract
637
+
638
+ # Respect the shared .last-extract marker so this every-10 path does
639
+ # not double-extract with nightly / responsive (audit: it bypassed
640
+ # the marker, breaking the shared idempotency contract).
641
+ root = _project_root()
642
+ marker = state_dir(root) / ".last-extract"
643
+ # Only extract when there ARE outcomes since the last extract by ANY
644
+ # path; skip silently otherwise (don't return — routing/doc rebuild
645
+ # below must still run).
646
+ if outcomes_since_marker(resolve_db_path(root), marker) > 0:
647
+ result = learn_extract(conn)
648
+ touch_marker(marker)
649
+ extracted = result.get("extracted", [])
650
+ if extracted:
651
+ click.echo(
652
+ f"\n🧠 Learning: {len(extracted)} new pattern(s) from {count} outcomes:",
653
+ )
654
+ for p in extracted:
655
+ click.echo(
656
+ f" • {p.get('pattern')} (confidence: {p.get('confidence', 0):.2f})",
657
+ )
658
+ except Exception as exc:
659
+ _brain_logger.debug("learn_extract trigger failed: %s", exc)
660
+
661
+ # Rebuild routing_weights every 10 outcomes so `cos_route_model` /
662
+ # `cos_route_skill` have current empirical success rates. No-op until
663
+ # task_outcomes has rows with non-null `model`.
664
+ try:
665
+ count = conn.execute("SELECT COUNT(*) FROM task_outcomes").fetchone()[0]
666
+ if count > 0 and count % 10 == 0:
667
+ from thinking_os.tools.routing import recalculate_weights
668
+
669
+ recalculate_weights(conn)
670
+ except Exception as exc:
671
+ _brain_logger.debug("recalculate_weights failed: %s", exc)
672
+
673
+ # Shift document_chunks.priority based on (retrieval, outcome) pairs
674
+ # every 10 outcomes so docs that supported successful work get gently
675
+ # boosted and failed ones decay. Bounded by _DELTA_* constants inside
676
+ # learn_from_retrievals; never cliff-jumps a single chunk.
677
+ try:
678
+ count = conn.execute("SELECT COUNT(*) FROM task_outcomes").fetchone()[0]
679
+ if count > 0 and count % 10 == 0:
680
+ from thinking_os.tools.retrieve import learn_from_retrievals
681
+
682
+ learn_from_retrievals(conn, lookback_days=14)
683
+ except Exception as exc:
684
+ _brain_logger.debug("learn_from_retrievals failed: %s", exc)
685
+
686
+ # Sweep dangling embeddings + concept-graph edges + trash observations
687
+ # every 10 outcomes. Cheap because NOT EXISTS / LIKE globs are indexed
688
+ # and the row counts are small in practice.
689
+ try:
690
+ count = conn.execute("SELECT COUNT(*) FROM task_outcomes").fetchone()[0]
691
+ if count > 0 and count % 10 == 0:
692
+ from thinking_os.memory_gc import gc_memory
693
+
694
+ _db_path = os.environ.get(
695
+ "COS_DB_PATH",
696
+ str(_project_root() / ".coding-os" / "coding-os.db"),
697
+ )
698
+ gc_memory(db_path=_db_path)
699
+ except Exception as exc:
700
+ _brain_logger.debug("gc_memory failed: %s", exc)
701
+
702
+
703
+ @click.command("task-done")
704
+ @click.argument("task_id")
705
+ def task_done_cmd(task_id):
706
+ from board_os import mcp_tools
707
+
708
+ conn = _db_conn()
709
+ try:
710
+ envelope = mcp_tools.cos_task_move(
711
+ conn,
712
+ task_id=task_id,
713
+ to="complete",
714
+ agent_session=_agent_session_id(),
715
+ )
716
+ parsed = _parse_envelope(envelope)
717
+ if parsed.get("ok"):
718
+ # Codex sessions can bypass Claude's post-write Work Log hook.
719
+ # Record one deterministic completion line in the task markdown.
720
+ mcp_tools.cos_work_log_append(
721
+ conn,
722
+ task_id=task_id,
723
+ summary="Status transitioned to complete via cos task-done.",
724
+ agent_session=_agent_session_id(),
725
+ source="task-done",
726
+ )
727
+ _record_brain_outcome_safe(conn, task_id)
728
+ finally:
729
+ conn.close()
730
+ sys.exit(_print_envelope(envelope))
731
+
732
+
733
+ @click.command("task-block")
734
+ @click.argument("task_id")
735
+ @click.option("--reason", required=True)
736
+ def task_block_cmd(task_id, reason):
737
+ _simple_move(task_id, "blocked", reason=reason)
738
+
739
+
740
+ @click.command("task-cancel")
741
+ @click.argument("task_id")
742
+ @click.option("--reason", default=None)
743
+ @click.option(
744
+ "--park",
745
+ is_flag=True,
746
+ default=False,
747
+ help="Soft-cancel: park in icebox instead of archiving (keeps it in the backlog).",
748
+ )
749
+ def task_cancel_cmd(task_id, reason, park):
750
+ # Default cancel now DRAINS the board: a terminal-eligible task (icebox /
751
+ # complete) goes to the terminal `archive` sink instead of back to icebox
752
+ # where it would rot. Active work (in_progress / testing /
753
+ # blocked) parks in icebox since the state machine has no direct edge from
754
+ # those states to archive. --park forces the soft icebox cancel everywhere.
755
+ note = f"cancelled: {reason or 'no reason given'}"
756
+ if park:
757
+ _simple_move(task_id, "icebox", reason=note)
758
+ return
759
+ dest = "archive" if _current_status(task_id) in ("icebox", "complete") else "icebox"
760
+ _simple_move(task_id, dest, reason=note)
761
+
762
+
763
+ @click.command(
764
+ "task-archive",
765
+ help="Move a task to the terminal `archive` status (drains icebox/complete off the board).",
766
+ )
767
+ @click.argument("task_id")
768
+ @click.option("--reason", default=None)
769
+ def task_archive_cmd(task_id, reason):
770
+ _simple_move(task_id, "archive", reason=f"archived: {reason or 'no reason given'}")
771
+
772
+
773
+ # ---------------------------------------------------------------------------
774
+ # task-pick / daily / retro / wip
775
+ # ---------------------------------------------------------------------------
776
+
777
+
778
+ @click.command("task-pick", help="Print top candidate tasks to work on next.")
779
+ @click.option("--swimlane", default=None)
780
+ @click.option("--priority-min", default="P2", type=click.Choice(["P0", "P1", "P2", "P3"]))
781
+ @click.option("--max-candidates", default=3, type=int)
782
+ def task_pick_cmd(swimlane, priority_min, max_candidates):
783
+ from board_os import mcp_tools
784
+
785
+ conn = _db_conn()
786
+ try:
787
+ envelope = mcp_tools.cos_task_pick(
788
+ conn,
789
+ swimlane=swimlane,
790
+ priority_min=priority_min,
791
+ max_candidates=max_candidates,
792
+ )
793
+ finally:
794
+ conn.close()
795
+ env = _parse_envelope(envelope)
796
+ if not env["ok"]:
797
+ click.echo(f"ERROR: {env['error']['message']}", err=True)
798
+ sys.exit(1)
799
+ cands = env["data"]["candidates"]
800
+ click.echo("\n Top candidates:")
801
+ for i, c in enumerate(cands, 1):
802
+ click.echo(
803
+ f" {i}. {c['id']} [{c['priority']}] {c['title']} ({c['swimlane']}/{c['kind']})"
804
+ )
805
+ click.echo()
806
+
807
+
808
+ @click.command("daily", help="Morning standup — summary of last 24h.")
809
+ @click.option("--since", default="24h")
810
+ def daily_cmd(since):
811
+ from board_os import mcp_tools
812
+
813
+ conn = _db_conn()
814
+ try:
815
+ envelope = mcp_tools.cos_task_daily(conn, since=since)
816
+ finally:
817
+ conn.close()
818
+ # Touch daily marker for remind-daily.sh.
819
+ # $COS_AGENT_DIR is agent-scoped (.coding-os/<agent>/); default to generic
820
+ # .coding-os/ to avoid hardcoding a specific adapter here.
821
+ marker = (
822
+ Path(
823
+ os.environ.get("COS_AGENT_DIR", str(_project_root() / ".coding-os")),
824
+ )
825
+ / ".daily-last-run"
826
+ )
827
+ marker.parent.mkdir(parents=True, exist_ok=True)
828
+ marker.write_text("", encoding="utf-8")
829
+ sys.exit(_print_envelope(envelope))
830
+
831
+
832
+ @click.command("retro", help="Weekly retrospective — throughput + cycle time.")
833
+ @click.option("--since", default="7d")
834
+ def retro_cmd(since):
835
+ from board_os import mcp_tools
836
+
837
+ conn = _db_conn()
838
+ try:
839
+ envelope = mcp_tools.cos_task_retro(conn, since=since)
840
+ finally:
841
+ conn.close()
842
+ sys.exit(_print_envelope(envelope))
843
+
844
+
845
+ @click.command("wip", help="Current WIP counts vs. caps.")
846
+ def wip_cmd():
847
+ from board_os import mcp_tools
848
+
849
+ conn = _db_conn()
850
+ try:
851
+ envelope = mcp_tools.cos_task_wip_check(conn)
852
+ finally:
853
+ conn.close()
854
+ sys.exit(_print_envelope(envelope))
855
+
856
+
857
+ # ---------------------------------------------------------------------------
858
+ # task-show / task-log / task-history
859
+ # ---------------------------------------------------------------------------
860
+
861
+
862
+ @click.command(
863
+ "task-show",
864
+ help="Show a task's full content + frontmatter. Without TASK_ID, falls back to the current session task.",
865
+ )
866
+ @click.argument("task_id", required=False)
867
+ def task_show_cmd(task_id):
868
+ if not task_id:
869
+ agent_dir = os.environ.get("COS_AGENT_DIR")
870
+ if agent_dir:
871
+ current_file = Path(agent_dir) / ".task-current"
872
+ if current_file.exists():
873
+ # write-state.sh stores "<session-id> <value>" on one line.
874
+ # Split off the session prefix and pull the first TASK-NNN
875
+ # token out of the remainder (handles slugged values like
876
+ # "TASK-NNN-some-slug").
877
+ content = current_file.read_text(encoding="utf-8").strip()
878
+ tokens = content.split()
879
+ value = " ".join(tokens[1:]) if len(tokens) >= 2 else content
880
+ import re as _re
881
+
882
+ match = _re.search(r"TASK-(?:[A-Z][A-Z0-9]*-)?\d+", value, _re.IGNORECASE)
883
+ if match:
884
+ task_id = match.group(0).upper()
885
+ if not task_id:
886
+ click.echo(
887
+ "ERROR: no TASK_ID and no active task in $COS_PANEL_DIR/.task-current.\n"
888
+ " Hint: cos task-start TASK-NNN (or pass TASK-NNN explicitly).",
889
+ err=True,
890
+ )
891
+ sys.exit(1)
892
+ conn = _db_conn()
893
+ try:
894
+ row = conn.execute(
895
+ "SELECT task_id, title, status, swimlane, kind, priority, "
896
+ "appetite, file_path FROM tasks WHERE task_id = ?",
897
+ (task_id,),
898
+ ).fetchone()
899
+ finally:
900
+ conn.close()
901
+ if not row:
902
+ click.echo(f"ERROR: {task_id} not found", err=True)
903
+ sys.exit(1)
904
+ click.echo(f" {row[0]}: {row[1]}")
905
+ click.echo(
906
+ f" status={row[2]} swimlane={row[3]} kind={row[4]} priority={row[5]} appetite={row[6]}"
907
+ )
908
+ click.echo(f" file: {row[7]}")
909
+ if row[7]:
910
+ full_path = _project_root() / row[7]
911
+ if full_path.exists():
912
+ click.echo("\n" + full_path.read_text(encoding="utf-8"))
913
+
914
+
915
+ @click.command("task-log", help="Show a task's Work Log.")
916
+ @click.argument("task_id")
917
+ @click.option("--full", is_flag=True, default=False)
918
+ def task_log_cmd(task_id, full):
919
+ conn = _db_conn()
920
+ try:
921
+ row = conn.execute(
922
+ "SELECT file_path, work_log_last_5 FROM tasks WHERE task_id = ?",
923
+ (task_id,),
924
+ ).fetchone()
925
+ finally:
926
+ conn.close()
927
+ if not row:
928
+ click.echo(f"ERROR: {task_id} not found", err=True)
929
+ sys.exit(1)
930
+ if full and row[0]:
931
+ full_path = _project_root() / row[0]
932
+ if full_path.exists():
933
+ content = full_path.read_text(encoding="utf-8")
934
+ idx = content.find("## Work Log")
935
+ if idx != -1:
936
+ click.echo(content[idx:])
937
+ return
938
+ last_5 = json.loads(row[1] or "[]")
939
+ for line in last_5:
940
+ click.echo(" " + line)
941
+
942
+
943
+ @click.command("task-history", help="Show task status transitions.")
944
+ @click.argument("task_id")
945
+ def task_history_cmd(task_id):
946
+ conn = _db_conn()
947
+ try:
948
+ rows = conn.execute(
949
+ "SELECT old_status, new_status, agent_session, reason, transitioned_at "
950
+ "FROM task_status_history WHERE task_id = ? "
951
+ "ORDER BY transitioned_at",
952
+ (task_id,),
953
+ ).fetchall()
954
+ finally:
955
+ conn.close()
956
+ if not rows:
957
+ click.echo(f" (no transitions for {task_id})")
958
+ return
959
+ click.echo(f"\n Transitions for {task_id}:")
960
+ import time
961
+
962
+ for r in rows:
963
+ ts = time.strftime("%Y-%m-%d %H:%M", time.localtime(r[4]))
964
+ click.echo(f" {ts} {r[0]:>12} → {r[1]:<12} {r[3] or ''}")
965
+
966
+
967
+ # ---------------------------------------------------------------------------
968
+ # task-validate / board-config
969
+ # ---------------------------------------------------------------------------
970
+
971
+
972
+ @click.command(
973
+ "task-validate",
974
+ help=(
975
+ "Lint task files, OR pre-flight a transition without applying it.\n\n"
976
+ " cos task-validate lint all docs/tasks/*.md (default)\n"
977
+ " cos task-validate TASK-NN preview DoR for in_progress on TASK-NN\n"
978
+ " cos task-validate TASK-NN --for complete preview DoD for complete\n"
979
+ " cos task-validate TASK-NN --json machine-readable ValidationResult"
980
+ ),
981
+ )
982
+ @click.argument("task_id", required=False)
983
+ @click.option(
984
+ "--for",
985
+ "for_status",
986
+ type=click.Choice(["in_progress", "complete"]),
987
+ default="in_progress",
988
+ help="Status to validate as the target. Default: in_progress (DoR check).",
989
+ )
990
+ @click.option("--json", "as_json", is_flag=True, default=False)
991
+ def task_validate_cmd(task_id, for_status, as_json):
992
+ """Two modes:
993
+
994
+ 1. No TASK_ID → lint every TASK-*.md file (legacy behavior).
995
+ 2. TASK_ID given → run the transition gate for the given
996
+ target status WITHOUT applying it. Same validator as the live
997
+ gate, so the verdict matches what `cos task-start` would do.
998
+ """
999
+ if not task_id:
1000
+ _task_validate_lint_all()
1001
+ return
1002
+ _task_validate_preflight(task_id, for_status, as_json)
1003
+
1004
+
1005
+ def _task_validate_lint_all() -> None:
1006
+ from board_os.parser import detect_duplicate_frontmatter, parse_task
1007
+
1008
+ root = _project_root()
1009
+ tasks_dir = root / "docs" / "tasks"
1010
+ if not tasks_dir.exists():
1011
+ click.echo(f" (no {tasks_dir})")
1012
+ return
1013
+ errors = 0
1014
+ warnings = 0
1015
+ for p in sorted(tasks_dir.glob("TASK-*.md")):
1016
+ content = p.read_text(encoding="utf-8")
1017
+ duplicate = detect_duplicate_frontmatter(content)
1018
+ if duplicate:
1019
+ click.echo(f" ✗ {p.name}: {duplicate}", err=True)
1020
+ errors += 1
1021
+ continue
1022
+ parsed = parse_task(content, path=p)
1023
+ if parsed is None:
1024
+ click.echo(f" ✗ {p.name}: unparseable", err=True)
1025
+ errors += 1
1026
+ continue
1027
+ if parsed.parse_warnings:
1028
+ for w in parsed.parse_warnings:
1029
+ click.echo(f" ⚠ {p.name}: {w}")
1030
+ warnings += 1
1031
+ else:
1032
+ click.echo(f" ✓ {p.name}")
1033
+ click.echo(f"\n Total: {errors} errors, {warnings} warnings")
1034
+ sys.exit(1 if errors > 0 else 0)
1035
+
1036
+
1037
+ def _task_validate_preflight(task_id: str, for_status: str, as_json: bool) -> None:
1038
+ """Run the transition gate validator without applying any change."""
1039
+ import json as _json
1040
+
1041
+ from board_os.parser import extract_frontmatter
1042
+ from board_os.transition_gates import GatesConfigError, load_gates_config
1043
+ from board_os.transition_gates_cli import (
1044
+ _has_work_log_entries,
1045
+ _verify_state,
1046
+ )
1047
+ from board_os.transition_gates_validator import (
1048
+ Verdict,
1049
+ validate_transition,
1050
+ )
1051
+
1052
+ conn = _db_conn()
1053
+ try:
1054
+ row = conn.execute(
1055
+ "SELECT file_path, kind FROM tasks WHERE task_id = ?",
1056
+ (task_id,),
1057
+ ).fetchone()
1058
+ finally:
1059
+ conn.close()
1060
+ if not row:
1061
+ click.echo(f"ERROR: {task_id} not found", err=True)
1062
+ sys.exit(1)
1063
+
1064
+ file_path = _project_root() / row[0] if row[0] else None
1065
+ body = ""
1066
+ kind = str(row[1] or "feature")
1067
+ if file_path and file_path.exists():
1068
+ body = file_path.read_text(encoding="utf-8")
1069
+ fm = extract_frontmatter(body) or {}
1070
+ if fm.get("kind"):
1071
+ kind = str(fm["kind"])
1072
+
1073
+ try:
1074
+ config = load_gates_config()
1075
+ except GatesConfigError as exc:
1076
+ click.echo(f"ERROR: gates config: {exc}", err=True)
1077
+ sys.exit(2)
1078
+
1079
+ has_recent, age = _verify_state()
1080
+ has_work_log = _has_work_log_entries(body)
1081
+
1082
+ result = validate_transition(
1083
+ task_id=task_id,
1084
+ kind=kind,
1085
+ body=body,
1086
+ new_status=for_status,
1087
+ config=config,
1088
+ has_recent_verify=has_recent,
1089
+ verify_age_seconds=age,
1090
+ has_work_log=has_work_log,
1091
+ override_reason=os.environ.get("COS_OVERRIDE_REASON"),
1092
+ override_actor=os.environ.get("COS_AGENT"),
1093
+ )
1094
+
1095
+ if as_json:
1096
+ click.echo(result.model_dump_json(indent=2))
1097
+ sys.exit(0 if result.verdict is not Verdict.BLOCK else 2)
1098
+
1099
+ glyph = {
1100
+ Verdict.PASS: "✓ PASS",
1101
+ Verdict.WARN: "⚠ WARN",
1102
+ Verdict.BLOCK: "✗ BLOCK",
1103
+ }[result.verdict]
1104
+ click.echo(f" {task_id} (kind={kind}, target={for_status}): {glyph}")
1105
+ for msg in result.messages:
1106
+ sev = msg.severity.value.upper()
1107
+ click.echo(f" [{msg.code}] {sev}: {msg.message}")
1108
+ if result.verdict is Verdict.PASS:
1109
+ click.echo(
1110
+ f" Run: cos task-start {task_id}"
1111
+ if for_status == "in_progress"
1112
+ else f" Run: cos task-done {task_id}"
1113
+ )
1114
+ sys.exit(0 if result.verdict is not Verdict.BLOCK else 2)
1115
+
1116
+
1117
+ def _discover_stacks() -> list[str]:
1118
+ """Data-driven — read templates/ to find available stack ids."""
1119
+ templates_dir = _REPO_ROOT / "src" / "templates"
1120
+ if not templates_dir.exists():
1121
+ return []
1122
+ return sorted(
1123
+ p.name for p in templates_dir.iterdir() if p.is_dir() and (p / "scaffold").exists()
1124
+ )
1125
+
1126
+
1127
+ @click.command("board-config", help="Scaffold or inspect scrumban-config.yaml")
1128
+ @click.option("--init", is_flag=True, default=False)
1129
+ @click.option("--stack", default="_base")
1130
+ def board_config_cmd(init, stack):
1131
+ valid_stacks = _discover_stacks() or ["_base"]
1132
+ if stack not in valid_stacks:
1133
+ click.echo(
1134
+ f"ERROR: stack {stack!r} not in {valid_stacks}",
1135
+ err=True,
1136
+ )
1137
+ sys.exit(1)
1138
+ root = _project_root()
1139
+ config_path = root / ".coding-os" / "scrumban-config.yaml"
1140
+ if init:
1141
+ if config_path.exists():
1142
+ click.echo(f"ERROR: {config_path} already exists", err=True)
1143
+ sys.exit(1)
1144
+ source = (
1145
+ _REPO_ROOT
1146
+ / "src"
1147
+ / "templates"
1148
+ / stack
1149
+ / "scaffold"
1150
+ / ".coding-os"
1151
+ / "scrumban-config.yaml"
1152
+ )
1153
+ if not source.exists():
1154
+ source = (
1155
+ _REPO_ROOT
1156
+ / "src"
1157
+ / "templates"
1158
+ / "_base"
1159
+ / "scaffold"
1160
+ / ".coding-os"
1161
+ / "scrumban-config.yaml"
1162
+ )
1163
+ config_path.parent.mkdir(parents=True, exist_ok=True)
1164
+ config_path.write_text(source.read_text(encoding="utf-8"), encoding="utf-8")
1165
+ click.echo(f" Created {config_path} (from {stack})")
1166
+ else:
1167
+ if not config_path.exists():
1168
+ click.echo(f"ERROR: {config_path} not found; run --init", err=True)
1169
+ sys.exit(1)
1170
+ click.echo(config_path.read_text(encoding="utf-8"))
1171
+
1172
+
1173
+ # ---------------------------------------------------------------------------
1174
+ @click.command(
1175
+ "task-link",
1176
+ help="Link a task to a forge issue/PR — sets external_ref (e.g. github#42). "
1177
+ "Forge auto-detected from origin. REF accepts 42, github#42, or an issue URL.",
1178
+ )
1179
+ @click.argument("task_id")
1180
+ @click.argument("ref")
1181
+ def task_link_cmd(task_id, ref):
1182
+ from board_os import mcp_tools
1183
+
1184
+ conn = _db_conn()
1185
+ try:
1186
+ envelope = mcp_tools.cos_task_link(conn, task_id=task_id, ref=ref)
1187
+ finally:
1188
+ conn.close()
1189
+ sys.exit(_print_envelope(envelope))
1190
+
1191
+
1192
+ # Commands bundle — register via cli.add_command(each)
1193
+ # ---------------------------------------------------------------------------
1194
+
1195
+
1196
+ BOARD_COMMANDS = [
1197
+ task_link_cmd,
1198
+ board_cmd,
1199
+ task_create_cmd,
1200
+ task_move_cmd,
1201
+ task_start_cmd,
1202
+ task_ready_cmd,
1203
+ task_reclaim_cmd,
1204
+ task_reconcile_cmd,
1205
+ task_done_cmd,
1206
+ task_block_cmd,
1207
+ task_cancel_cmd,
1208
+ task_archive_cmd,
1209
+ task_pick_cmd,
1210
+ daily_cmd,
1211
+ retro_cmd,
1212
+ wip_cmd,
1213
+ task_show_cmd,
1214
+ task_log_cmd,
1215
+ task_history_cmd,
1216
+ task_validate_cmd,
1217
+ board_config_cmd,
1218
+ ]