@zerwiz/ymir 0.1.3 → 0.1.5

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 (850) hide show
  1. package/.agents/README.md +291 -0
  2. package/.agents/agents/bragi-marketer.md +111 -0
  3. package/.agents/agents/brokk.md +352 -0
  4. package/.agents/agents/forseti-reviewer.md +93 -0
  5. package/.agents/agents/frigg-consent.md +77 -0
  6. package/.agents/agents/groa-update.md +77 -0
  7. package/.agents/agents/hnoss-designer.md +69 -0
  8. package/.agents/agents/huginn-researcher.md +99 -0
  9. package/.agents/agents/jord-projects.md +78 -0
  10. package/.agents/agents/kvasir-scout.md +91 -0
  11. package/.agents/agents/mimir-planner.md +92 -0
  12. package/.agents/agents/muninn-stow.md +77 -0
  13. package/.agents/agents/saga-bearings.md +78 -0
  14. package/.agents/agents/sindri-developer.md +114 -0
  15. package/.agents/agents/snotra-documenter.md +105 -0
  16. package/.agents/agents/syn-recovery.md +78 -0
  17. package/.agents/agents/tyr-check.md +78 -0
  18. package/.agents/agents/urdh-hold.md +77 -0
  19. package/.agents/agents/volundr-smith.md +80 -0
  20. package/.agents/agents/vor-diagnostics.md +77 -0
  21. package/.agents/assets/agents/naming.md +50 -0
  22. package/.agents/assets/agents/registry.md +93 -0
  23. package/.agents/assets/agents/runtime.md +36 -0
  24. package/.agents/assets/agents/toon-tasks-cli.md +42 -0
  25. package/.agents/assets/templates/company_entity.template.md +37 -0
  26. package/.agents/backend/backends/cmux.sh +649 -0
  27. package/.agents/backend/backends/herdr-eventwait.py +157 -0
  28. package/.agents/backend/backends/herdr-workspace-move.py +114 -0
  29. package/.agents/backend/backends/herdr.sh +3386 -0
  30. package/.agents/backend/backends/orca.sh +290 -0
  31. package/.agents/backend/backends/tmux.sh +357 -0
  32. package/.agents/backend/backends/zellij.sh +700 -0
  33. package/.agents/backend/fm-afk-launch.sh +654 -0
  34. package/.agents/backend/fm-afk-return.sh +241 -0
  35. package/.agents/backend/fm-afk-start.sh +172 -0
  36. package/.agents/backend/fm-arm-command-policy.mjs +960 -0
  37. package/.agents/backend/fm-arm-pretool-check.sh +200 -0
  38. package/.agents/backend/fm-backend-hometag-lib.sh +52 -0
  39. package/.agents/backend/fm-backend.sh +981 -0
  40. package/.agents/backend/fm-backlog-handoff.sh +909 -0
  41. package/.agents/backend/fm-backlog-receive.sh +187 -0
  42. package/.agents/backend/fm-backlog-transition-lib.sh +779 -0
  43. package/.agents/backend/fm-bearings-board.sh +204 -0
  44. package/.agents/backend/fm-bearings-snapshot.sh +546 -0
  45. package/.agents/backend/fm-bootstrap.sh +1568 -0
  46. package/.agents/backend/fm-branch-outcome.sh +203 -0
  47. package/.agents/backend/fm-branch-prompt.sh +101 -0
  48. package/.agents/backend/fm-brief.sh +452 -0
  49. package/.agents/backend/fm-busy-event.sh +234 -0
  50. package/.agents/backend/fm-busy-lib.sh +986 -0
  51. package/.agents/backend/fm-captain-hold.sh +1001 -0
  52. package/.agents/backend/fm-cd-command-policy.mjs +153 -0
  53. package/.agents/backend/fm-cd-pretool-check.sh +190 -0
  54. package/.agents/backend/fm-check-lib.sh +74 -0
  55. package/.agents/backend/fm-check-register.sh +42 -0
  56. package/.agents/backend/fm-check-unregister.sh +52 -0
  57. package/.agents/backend/fm-classify-lib.sh +1770 -0
  58. package/.agents/backend/fm-claude-stop-autoarm.sh +334 -0
  59. package/.agents/backend/fm-composer-lib.sh +1416 -0
  60. package/.agents/backend/fm-config-inherit-lib.sh +1202 -0
  61. package/.agents/backend/fm-config-push.sh +254 -0
  62. package/.agents/backend/fm-control-lib.sh +251 -0
  63. package/.agents/backend/fm-control.sh +878 -0
  64. package/.agents/backend/fm-crew-state.sh +625 -0
  65. package/.agents/backend/fm-cursor-lib.sh +243 -0
  66. package/.agents/backend/fm-decision-hold.sh +232 -0
  67. package/.agents/backend/fm-doc-audience-check.sh +269 -0
  68. package/.agents/backend/fm-dod-lib.sh +67 -0
  69. package/.agents/backend/fm-ensure-agents-md.sh +253 -0
  70. package/.agents/backend/fm-extension-launch-barrier.mjs +129 -0
  71. package/.agents/backend/fm-extension.mjs +2577 -0
  72. package/.agents/backend/fm-extension.sh +16 -0
  73. package/.agents/backend/fm-ff-lib.sh +420 -0
  74. package/.agents/backend/fm-fleet-snapshot.sh +1463 -0
  75. package/.agents/backend/fm-fleet-sync.sh +458 -0
  76. package/.agents/backend/fm-fleet-view.sh +96 -0
  77. package/.agents/backend/fm-gate-refuse-lib.sh +102 -0
  78. package/.agents/backend/fm-guard.sh +242 -0
  79. package/.agents/backend/fm-harness.sh +195 -0
  80. package/.agents/backend/fm-herdr-ci-cleanup.sh +115 -0
  81. package/.agents/backend/fm-herdr-lab.sh +346 -0
  82. package/.agents/backend/fm-herdr-session-cleanup.sh +337 -0
  83. package/.agents/backend/fm-home-seed.sh +984 -0
  84. package/.agents/backend/fm-home-summary-refresh.sh +255 -0
  85. package/.agents/backend/fm-hook-host-lib.sh +36 -0
  86. package/.agents/backend/fm-inactive-reconcile.sh +531 -0
  87. package/.agents/backend/fm-inbox.sh +399 -0
  88. package/.agents/backend/fm-install-actionlint.sh +84 -0
  89. package/.agents/backend/fm-install-herdr.sh +96 -0
  90. package/.agents/backend/fm-install-shellcheck.sh +84 -0
  91. package/.agents/backend/fm-install-treehouse.sh +95 -0
  92. package/.agents/backend/fm-kimi-turnend-hook.sh +276 -0
  93. package/.agents/backend/fm-lease-lib.sh +218 -0
  94. package/.agents/backend/fm-lease.sh +189 -0
  95. package/.agents/backend/fm-line-cap-lib.sh +51 -0
  96. package/.agents/backend/fm-lint-workflows.sh +137 -0
  97. package/.agents/backend/fm-lint.sh +591 -0
  98. package/.agents/backend/fm-lock-lib.sh +104 -0
  99. package/.agents/backend/fm-lock.sh +107 -0
  100. package/.agents/backend/fm-marker-lib.sh +12 -0
  101. package/.agents/backend/fm-merge-local.sh +74 -0
  102. package/.agents/backend/fm-merge-outcome-lib.sh +138 -0
  103. package/.agents/backend/fm-nm-run-lib.sh +124 -0
  104. package/.agents/backend/fm-on.sh +125 -0
  105. package/.agents/backend/fm-operational-input.sh +253 -0
  106. package/.agents/backend/fm-peek.sh +46 -0
  107. package/.agents/backend/fm-pending-reply-lib.sh +1409 -0
  108. package/.agents/backend/fm-pr-check.sh +135 -0
  109. package/.agents/backend/fm-pr-lib.sh +1016 -0
  110. package/.agents/backend/fm-pr-merge.sh +707 -0
  111. package/.agents/backend/fm-pr-poll.sh +110 -0
  112. package/.agents/backend/fm-primary-scope-lib.sh +33 -0
  113. package/.agents/backend/fm-procevent-extension-capture.pl +259 -0
  114. package/.agents/backend/fm-procevent-lavish.sh +628 -0
  115. package/.agents/backend/fm-procevent-lib.sh +892 -0
  116. package/.agents/backend/fm-procevent-quota.sh +290 -0
  117. package/.agents/backend/fm-procevent-remote-reply.sh +577 -0
  118. package/.agents/backend/fm-procevent-when.sh +504 -0
  119. package/.agents/backend/fm-procevent.sh +1466 -0
  120. package/.agents/backend/fm-project-mode.sh +92 -0
  121. package/.agents/backend/fm-project-origin-lib.sh +180 -0
  122. package/.agents/backend/fm-promote.sh +282 -0
  123. package/.agents/backend/fm-public-followup-emit.sh +260 -0
  124. package/.agents/backend/fm-public-followup-lib.sh +398 -0
  125. package/.agents/backend/fm-public-followup.sh +1330 -0
  126. package/.agents/backend/fm-push-transition-lib.sh +168 -0
  127. package/.agents/backend/fm-quota-axi-lib.sh +93 -0
  128. package/.agents/backend/fm-quota-choose.sh +384 -0
  129. package/.agents/backend/fm-remote-delta-read.sh +189 -0
  130. package/.agents/backend/fm-remote-doctor.sh +800 -0
  131. package/.agents/backend/fm-remote-entrypoint.sh +193 -0
  132. package/.agents/backend/fm-remote-file.sh +234 -0
  133. package/.agents/backend/fm-remote-home-provision.sh +259 -0
  134. package/.agents/backend/fm-remote-home-seed.sh +259 -0
  135. package/.agents/backend/fm-remote-inherit-push.sh +90 -0
  136. package/.agents/backend/fm-remote-inherit.sh +179 -0
  137. package/.agents/backend/fm-remote-job-lib.sh +1241 -0
  138. package/.agents/backend/fm-remote-job-reap-orphans.sh +137 -0
  139. package/.agents/backend/fm-remote-job-worker.sh +1124 -0
  140. package/.agents/backend/fm-remote-readiness-lib.sh +44 -0
  141. package/.agents/backend/fm-remote-secondmate-control.sh +340 -0
  142. package/.agents/backend/fm-review-diff.sh +158 -0
  143. package/.agents/backend/fm-secondmate-charter-lib.sh +44 -0
  144. package/.agents/backend/fm-secondmate-nudge-lib.sh +68 -0
  145. package/.agents/backend/fm-secondmate-parent-lib.sh +70 -0
  146. package/.agents/backend/fm-secondmate-reconcile.sh +371 -0
  147. package/.agents/backend/fm-secondmate-registry-lib.sh +311 -0
  148. package/.agents/backend/fm-secondmate-report.sh +88 -0
  149. package/.agents/backend/fm-send.sh +1059 -0
  150. package/.agents/backend/fm-session-lock-lib.sh +176 -0
  151. package/.agents/backend/fm-session-start.sh +970 -0
  152. package/.agents/backend/fm-sessionstart-cursor.sh +40 -0
  153. package/.agents/backend/fm-sessionstart-nudge.sh +45 -0
  154. package/.agents/backend/fm-sessionstart-run.sh +145 -0
  155. package/.agents/backend/fm-spawn.sh +3153 -0
  156. package/.agents/backend/fm-startup-memory-budget-lib.sh +224 -0
  157. package/.agents/backend/fm-startup-memory-budget.sh +94 -0
  158. package/.agents/backend/fm-startup-network.sh +642 -0
  159. package/.agents/backend/fm-stow-cascade.sh +251 -0
  160. package/.agents/backend/fm-subagent-pretool-check.sh +207 -0
  161. package/.agents/backend/fm-supervise-daemon.sh +1732 -0
  162. package/.agents/backend/fm-supervision-instructions.sh +215 -0
  163. package/.agents/backend/fm-supervision-lib.sh +90 -0
  164. package/.agents/backend/fm-supervisor-target-lib.sh +78 -0
  165. package/.agents/backend/fm-tangle-lib.sh +53 -0
  166. package/.agents/backend/fm-task-inbox-lib.sh +402 -0
  167. package/.agents/backend/fm-tasks-axi-lib.sh +123 -0
  168. package/.agents/backend/fm-teardown.sh +2922 -0
  169. package/.agents/backend/fm-test-isolation-proof.sh +588 -0
  170. package/.agents/backend/fm-test-run.sh +2191 -0
  171. package/.agents/backend/fm-timeout-lib.sh +141 -0
  172. package/.agents/backend/fm-timing-lib.sh +179 -0
  173. package/.agents/backend/fm-tmux-lib.sh +291 -0
  174. package/.agents/backend/fm-tool-update-check.sh +898 -0
  175. package/.agents/backend/fm-trace-context-lib.sh +227 -0
  176. package/.agents/backend/fm-transition-lib.sh +103 -0
  177. package/.agents/backend/fm-turnend-guard-cursor.sh +391 -0
  178. package/.agents/backend/fm-turnend-guard-grok.sh +90 -0
  179. package/.agents/backend/fm-turnend-guard.sh +432 -0
  180. package/.agents/backend/fm-update.sh +110 -0
  181. package/.agents/backend/fm-vendor-auth-probe.sh +190 -0
  182. package/.agents/backend/fm-voice-client.py +1373 -0
  183. package/.agents/backend/fm-voice-relay.py +1256 -0
  184. package/.agents/backend/fm-wake-drain.sh +592 -0
  185. package/.agents/backend/fm-wake-grant.sh +127 -0
  186. package/.agents/backend/fm-wake-lib.sh +1849 -0
  187. package/.agents/backend/fm-watch-arm.sh +602 -0
  188. package/.agents/backend/fm-watch-checkpoint.sh +109 -0
  189. package/.agents/backend/fm-watch.sh +1962 -0
  190. package/.agents/backend/fm-x-dismiss.sh +116 -0
  191. package/.agents/backend/fm-x-followup.sh +286 -0
  192. package/.agents/backend/fm-x-lib.sh +1000 -0
  193. package/.agents/backend/fm-x-link.sh +234 -0
  194. package/.agents/backend/fm-x-poll.sh +185 -0
  195. package/.agents/backend/fm-x-reply.sh +385 -0
  196. package/.agents/backend/fm_voice_frame.py +166 -0
  197. package/.agents/backend/fm_voice_records.py +574 -0
  198. package/.agents/backend/model-bridge.py +290 -0
  199. package/.agents/backend/opencode-go-bridge.py +30 -0
  200. package/.agents/bus/README.md +12 -0
  201. package/.agents/bus/messages.json +1 -0
  202. package/.agents/config/agents.machine.example.yaml +16 -0
  203. package/.agents/config/agents.yaml +50 -0
  204. package/.agents/config/agents.yaml.example +72 -0
  205. package/.agents/config/crew-dispatch.json +22 -0
  206. package/.agents/config/cron.yaml +9 -0
  207. package/.agents/config/eindri-dispatch.json +67 -0
  208. package/.agents/config/eindri-harness +1 -0
  209. package/.agents/config/startup-memory-budget +1 -0
  210. package/.agents/config/tailscale-sync.yaml +27 -0
  211. package/.agents/filebrowser/.filebrowser.json +6 -0
  212. package/.agents/filebrowser/README.md +11 -0
  213. package/.agents/gateway/README.md +12 -0
  214. package/.agents/github/README.md +15 -0
  215. package/.agents/github/webhooks/.gitkeep +0 -0
  216. package/.agents/github/workflows/.gitkeep +0 -0
  217. package/.agents/harness/opencode/plugins/lib/rodd-operational-input.js +37 -0
  218. package/.agents/harness/opencode/plugins/package.json +4 -0
  219. package/.agents/harness/opencode/plugins/saga-sessionstart.js +77 -0
  220. package/.agents/harness/opencode/plugins/syn-cd-check.js +61 -0
  221. package/.agents/harness/opencode/plugins/syn-pretool-check.js +68 -0
  222. package/.agents/harness/opencode/plugins/syn-turnend-guard.js +105 -0
  223. package/.agents/harness/opencode/plugins/syn-watch-arm.js +521 -0
  224. package/.agents/memory/README.md +46 -0
  225. package/.agents/memory/kaia.engram +0 -0
  226. package/.agents/memory/kaia.engram-shm +0 -0
  227. package/.agents/memory/kaia.engram-wal +0 -0
  228. package/.agents/memory/runes_audit.md +5 -0
  229. package/.agents/memory/well/episodes.jsonl +367 -0
  230. package/.agents/memory/well/workspace.jsonl +27 -0
  231. package/.agents/migrations/0001-hodd-layout.sh +38 -0
  232. package/.agents/migrations/0002-a2a-mcp.sh +27 -0
  233. package/.agents/migrations/0003-private-data-separation.sh +111 -0
  234. package/.agents/migrations/0004-hoard-and-realms.sh +104 -0
  235. package/.agents/sandbox/Dockerfile.utgard +19 -0
  236. package/.agents/sandbox/README.md +14 -0
  237. package/.agents/sandbox/utgard.config.json +14 -0
  238. package/.agents/skills/README.md +59 -0
  239. package/.agents/skills/bragi-marketing/README.md +3 -0
  240. package/.agents/skills/bragi-marketing/SKILL.md +82 -0
  241. package/.agents/skills/eindri-homes/README.md +3 -0
  242. package/.agents/skills/eindri-homes/SKILL.md +291 -0
  243. package/.agents/skills/eindri-homes/assets/control-plane.md +122 -0
  244. package/.agents/skills/eindri-homes/assets/dispatch.md +80 -0
  245. package/.agents/skills/frigg-consent/README.md +3 -0
  246. package/.agents/skills/frigg-consent/SKILL.md +56 -0
  247. package/.agents/skills/galdr-ymirsystem/README.md +3 -0
  248. package/.agents/skills/galdr-ymirsystem/SKILL.md +158 -0
  249. package/.agents/skills/galdr-ymirsystem/assets/README.md +74 -0
  250. package/.agents/skills/galdr-ymirsystem/assets/brokk-distro-runtime.md +390 -0
  251. package/.agents/skills/galdr-ymirsystem/assets/build-method.md +113 -0
  252. package/.agents/skills/galdr-ymirsystem/assets/build-tool-categories.md +178 -0
  253. package/.agents/skills/galdr-ymirsystem/assets/eindri-orchestration.md +518 -0
  254. package/.agents/skills/galdr-ymirsystem/assets/eindri-profiles.md +136 -0
  255. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +673 -0
  256. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/claude-code.md +197 -0
  257. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/codex.md +191 -0
  258. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/cursor.md +193 -0
  259. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/opencode.md +262 -0
  260. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/pi.md +295 -0
  261. package/.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md +496 -0
  262. package/.agents/skills/galdr-ymirsystem/assets/installation.md +571 -0
  263. package/.agents/skills/galdr-ymirsystem/assets/local-models/HOST-DATA.example.md +72 -0
  264. package/.agents/skills/galdr-ymirsystem/assets/local-models.md +274 -0
  265. package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +161 -0
  266. package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +377 -0
  267. package/.agents/skills/galdr-ymirsystem/assets/norse-naming.md +325 -0
  268. package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +129 -0
  269. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/einherjar-spawn.schema.json +81 -0
  270. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/herdr-profile.toml +75 -0
  271. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml +96 -0
  272. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/supervision-tree.yml +163 -0
  273. package/.agents/skills/galdr-ymirsystem/assets/pi-boot-guide.md +58 -0
  274. package/.agents/skills/galdr-ymirsystem/assets/porting-upstream-to-norse.md +301 -0
  275. package/.agents/skills/galdr-ymirsystem/assets/principles.md +385 -0
  276. package/.agents/skills/galdr-ymirsystem/assets/reference-adoption.md +99 -0
  277. package/.agents/skills/galdr-ymirsystem/assets/registry.md +379 -0
  278. package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +463 -0
  279. package/.agents/skills/galdr-ymirsystem/assets/runtime-components.md +553 -0
  280. package/.agents/skills/galdr-ymirsystem/assets/smidja.md +175 -0
  281. package/.agents/skills/galdr-ymirsystem/schemas/toon-schemas.md +190 -0
  282. package/.agents/skills/galdr-ymirsystem/scripts/README.md +45 -0
  283. package/.agents/skills/galdr-ymirsystem/scripts/bench-one.sh +248 -0
  284. package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +360 -0
  285. package/.agents/skills/galdr-ymirsystem/scripts/gpu-sample.sh +43 -0
  286. package/.agents/skills/galdr-ymirsystem/scripts/stop-all.sh +34 -0
  287. package/.agents/skills/galdr-ymirsystem/scripts/toon-check.py +188 -0
  288. package/.agents/skills/gjallarhorn-relay/README.md +3 -0
  289. package/.agents/skills/gjallarhorn-relay/SKILL.md +283 -0
  290. package/.agents/skills/groa-update/SKILL.md +70 -0
  291. package/.agents/skills/hamr-adapters/README.md +3 -0
  292. package/.agents/skills/hamr-adapters/SKILL.md +123 -0
  293. package/.agents/skills/hamr-adapters/references/common/control-and-recovery.md +37 -0
  294. package/.agents/skills/hamr-adapters/references/common/dispatch.md +32 -0
  295. package/.agents/skills/hamr-adapters/references/common/model-and-effort.md +42 -0
  296. package/.agents/skills/hamr-adapters/references/common/primary-hooks.md +40 -0
  297. package/.agents/skills/hamr-adapters/references/harness/claude.md +55 -0
  298. package/.agents/skills/hamr-adapters/references/harness/codex.md +43 -0
  299. package/.agents/skills/hamr-adapters/references/harness/cursor.md +75 -0
  300. package/.agents/skills/hamr-adapters/references/harness/grok.md +69 -0
  301. package/.agents/skills/hamr-adapters/references/harness/kimi.md +51 -0
  302. package/.agents/skills/hamr-adapters/references/harness/muse.md +70 -0
  303. package/.agents/skills/hamr-adapters/references/harness/opencode.md +42 -0
  304. package/.agents/skills/hamr-adapters/references/harness/pi.md +56 -0
  305. package/.agents/skills/herdr-panes/README.md +3 -0
  306. package/.agents/skills/herdr-panes/SKILL.md +92 -0
  307. package/.agents/skills/herdr-panes/assets/herdr-backend.md +346 -0
  308. package/.agents/skills/herdr-panes/assets/tmux-backend.md +115 -0
  309. package/.agents/skills/hnoss-design/DESIGN.md +19 -0
  310. package/.agents/skills/hnoss-design/README.md +3 -0
  311. package/.agents/skills/hnoss-design/SKILL.md +83 -0
  312. package/.agents/skills/hvild-afk/README.md +3 -0
  313. package/.agents/skills/hvild-afk/SKILL.md +241 -0
  314. package/.agents/skills/jord-projects/README.md +3 -0
  315. package/.agents/skills/jord-projects/SKILL.md +92 -0
  316. package/.agents/skills/lifecycle/SKILL.md +56 -0
  317. package/.agents/skills/lifecycle/smoke_test.sh +52 -0
  318. package/.agents/skills/lifecycle/start.sh +21 -0
  319. package/.agents/skills/lifecycle/status.sh +35 -0
  320. package/.agents/skills/lifecycle/stop.sh +16 -0
  321. package/.agents/skills/muninn-stow/README.md +3 -0
  322. package/.agents/skills/muninn-stow/SKILL.md +309 -0
  323. package/.agents/skills/no-mistakes/SKILL.md +379 -0
  324. package/.agents/skills/nornir-schedule/README.md +3 -0
  325. package/.agents/skills/nornir-schedule/SKILL.md +25 -0
  326. package/.agents/skills/nornir-schedule/assets/events.md +137 -0
  327. package/.agents/skills/nornir-schedule/assets/quota.md +131 -0
  328. package/.agents/skills/nsr-compliance/README.md +3 -0
  329. package/.agents/skills/nsr-compliance/SKILL.md +29 -0
  330. package/.agents/skills/nsr-compliance/assets/nsr/README.md +40 -0
  331. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/README.md +15 -0
  332. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/git-workflow.md +18 -0
  333. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/security.md +22 -0
  334. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/tech-stack.md +8 -0
  335. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/SKILL.md +71 -0
  336. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/config/core_four.yaml +16 -0
  337. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_danger.sh +102 -0
  338. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_wiring.sh +69 -0
  339. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/validate_code.sh +29 -0
  340. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/verify_docs.py +66 -0
  341. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/generate.sh +109 -0
  342. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/result_envelope.json +14 -0
  343. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/task_envelope.json +20 -0
  344. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/runner.py +303 -0
  345. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/telemetry/logger.py +112 -0
  346. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/README.md +18 -0
  347. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/config/README.md +10 -0
  348. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/README.md +12 -0
  349. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_env.sh +23 -0
  350. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_paths.sh +20 -0
  351. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_platform.sh +23 -0
  352. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/README.md +11 -0
  353. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/envelopes/README.md +10 -0
  354. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/README.md +10 -0
  355. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/install.sh +125 -0
  356. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/telemetry/README.md +11 -0
  357. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/README.md +20 -0
  358. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/README.md +36 -0
  359. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/SKILL-template.md +14 -0
  360. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/README.md +25 -0
  361. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/SKILL.md +13 -0
  362. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/create_branch.sh +6 -0
  363. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/safe_commit.sh +9 -0
  364. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/sync_upstream.sh +6 -0
  365. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/README.md +27 -0
  366. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/SKILL.md +15 -0
  367. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/smoke_test.sh +12 -0
  368. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/start.sh +19 -0
  369. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/status.sh +12 -0
  370. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/stop.sh +15 -0
  371. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/README.md +18 -0
  372. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/README.md +10 -0
  373. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/core_four.yaml +13 -0
  374. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/README.md +12 -0
  375. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_danger.sh +102 -0
  376. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_env.sh +23 -0
  377. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_paths.sh +20 -0
  378. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_platform.sh +23 -0
  379. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_wiring.sh +69 -0
  380. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/README.md +11 -0
  381. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/README.md +10 -0
  382. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/result_envelope.json +14 -0
  383. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/task_envelope.json +20 -0
  384. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/runner.py +303 -0
  385. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/README.md +10 -0
  386. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/install.sh +125 -0
  387. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/README.md +11 -0
  388. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/logger.py +112 -0
  389. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/README.md +14 -0
  390. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/api.md +17 -0
  391. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/compliance-wiring.md +155 -0
  392. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/frontend.md +15 -0
  393. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/README.md +11 -0
  394. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/README.md +23 -0
  395. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/README.md +16 -0
  396. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/template-README.md +11 -0
  397. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/deploy.sh +49 -0
  398. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/README.md +12 -0
  399. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/development.env.example +17 -0
  400. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/production.env.example +17 -0
  401. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/staging.env.example +17 -0
  402. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/README.md +11 -0
  403. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/template.env.example +8 -0
  404. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/README.md +26 -0
  405. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/agent.md +7 -0
  406. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/developers/dev-1.md +20 -0
  407. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/linux.md +9 -0
  408. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/macos.md +10 -0
  409. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/shared.md +19 -0
  410. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/windows.md +14 -0
  411. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/README.md +25 -0
  412. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/_template.md +41 -0
  413. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/hosting-1.md +41 -0
  414. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/README.md +21 -0
  415. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/README.md +15 -0
  416. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/deployment.md +19 -0
  417. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/disaster-recovery.md +15 -0
  418. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/ops-tasks.md +14 -0
  419. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/features/README.md +16 -0
  420. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/project-skills.md +146 -0
  421. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/README.md +11 -0
  422. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/software-compliance-research.md +269 -0
  423. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/working-with-agents.md +260 -0
  424. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/AGENTS.md +38 -0
  425. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/ARCHITECTURE.md +36 -0
  426. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/BEST_PRACTICES.md +27 -0
  427. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/CI_CD.md +23 -0
  428. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/FEATURES.md +15 -0
  429. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/README.md +22 -0
  430. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/RULES.md +37 -0
  431. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/STRUCTURE.md +45 -0
  432. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/TECH_STACK.md +28 -0
  433. package/.agents/skills/nsr-compliance/assets/nsr/scaffold-spec.md +63 -0
  434. package/.agents/skills/nsr-compliance/assets/nsr/scripts/scaffold.sh +103 -0
  435. package/.agents/skills/nsr-compliance/assets/nsr/scripts/validate.sh +52 -0
  436. package/.agents/skills/nsr-compliance/assets/nsrcompliance/SKILL.md +71 -0
  437. package/.agents/skills/nsr-compliance/assets/nsrcompliance/config/core_four.yaml +16 -0
  438. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_danger.sh +102 -0
  439. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_wiring.sh +69 -0
  440. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/validate_code.sh +29 -0
  441. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/verify_docs.py +66 -0
  442. package/.agents/skills/nsr-compliance/assets/nsrcompliance/generate.sh +109 -0
  443. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/result_envelope.json +14 -0
  444. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/task_envelope.json +20 -0
  445. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/runner.py +303 -0
  446. package/.agents/skills/nsr-compliance/assets/nsrcompliance/telemetry/logger.py +112 -0
  447. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/README.md +18 -0
  448. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/config/README.md +10 -0
  449. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/README.md +12 -0
  450. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_env.sh +23 -0
  451. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_paths.sh +20 -0
  452. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_platform.sh +23 -0
  453. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/README.md +11 -0
  454. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/envelopes/README.md +10 -0
  455. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/README.md +10 -0
  456. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/install.sh +125 -0
  457. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/telemetry/README.md +11 -0
  458. package/.agents/skills/pr-ops/README.md +3 -0
  459. package/.agents/skills/pr-ops/SKILL.md +109 -0
  460. package/.agents/skills/ratatoskr-a2a/README.md +3 -0
  461. package/.agents/skills/ratatoskr-a2a/SKILL.md +148 -0
  462. package/.agents/skills/rules-check-drift/SKILL.md +81 -0
  463. package/.agents/skills/saga-bearings/README.md +3 -0
  464. package/.agents/skills/saga-bearings/SKILL.md +26 -0
  465. package/.agents/skills/saga-bearings/assets/bearings.md +161 -0
  466. package/.agents/skills/saga-bearings/assets/board-template.html +731 -0
  467. package/.agents/skills/saga-bearings/assets/recap.md +56 -0
  468. package/.agents/skills/syn-recovery/README.md +3 -0
  469. package/.agents/skills/syn-recovery/SKILL.md +54 -0
  470. package/.agents/skills/tyr-check/README.md +3 -0
  471. package/.agents/skills/tyr-check/SKILL.md +218 -0
  472. package/.agents/skills/urdh-hold/README.md +3 -0
  473. package/.agents/skills/urdh-hold/SKILL.md +25 -0
  474. package/.agents/skills/urdh-hold/assets/decisions.md +15 -0
  475. package/.agents/skills/urdh-hold/assets/hold.md +54 -0
  476. package/.agents/skills/vor-diagnostics/README.md +3 -0
  477. package/.agents/skills/vor-diagnostics/SKILL.md +68 -0
  478. package/.agents/skills/ymir-host/README.md +3 -0
  479. package/.agents/skills/ymir-host/SKILL.md +34 -0
  480. package/.agents/skills/ymir-host/assets/desktop.md +36 -0
  481. package/.agents/skills/ymir-host/assets/omarchy.md +297 -0
  482. package/.agents/skills/ymir-host/assets/runbooks.md +15 -0
  483. package/.agents/skills/ymir-host/assets/thjazi.md +220 -0
  484. package/.agents/skills/ymir-host/assets/update.md +64 -0
  485. package/.agents/tests/assets/board-render-harness.mjs +117 -0
  486. package/.agents/tests/cmux-test-safety.sh +51 -0
  487. package/.agents/tests/fixtures.sh +291 -0
  488. package/.agents/tests/fm-afk-inject-e2e.test.sh +428 -0
  489. package/.agents/tests/fm-afk-inject-herdr-e2e.test.sh +536 -0
  490. package/.agents/tests/fm-afk-launch.test.sh +961 -0
  491. package/.agents/tests/fm-afk-pi-herdr-return-e2e.test.sh +297 -0
  492. package/.agents/tests/fm-afk-return.test.sh +283 -0
  493. package/.agents/tests/fm-arm-pretool-check.test.sh +482 -0
  494. package/.agents/tests/fm-ask-user-authority.test.sh +42 -0
  495. package/.agents/tests/fm-backend-autodetect-smoke.test.sh +176 -0
  496. package/.agents/tests/fm-backend-cmux-smoke.test.sh +188 -0
  497. package/.agents/tests/fm-backend-cmux.test.sh +1166 -0
  498. package/.agents/tests/fm-backend-herdr-eventwait-smoke.test.sh +136 -0
  499. package/.agents/tests/fm-backend-herdr-eventwait.test.py +106 -0
  500. package/.agents/tests/fm-backend-herdr-focus-flash-e2e.test.sh +409 -0
  501. package/.agents/tests/fm-backend-herdr-launcher-workspace-e2e.test.sh +437 -0
  502. package/.agents/tests/fm-backend-herdr-presentation-e2e.test.sh +1424 -0
  503. package/.agents/tests/fm-backend-herdr-prune-safety-e2e.test.sh +180 -0
  504. package/.agents/tests/fm-backend-herdr-respawn-idem-e2e.test.sh +182 -0
  505. package/.agents/tests/fm-backend-herdr-smoke.test.sh +355 -0
  506. package/.agents/tests/fm-backend-herdr-workspace-per-home-e2e.test.sh +251 -0
  507. package/.agents/tests/fm-backend-herdr.test.sh +4606 -0
  508. package/.agents/tests/fm-backend-orca.test.sh +1357 -0
  509. package/.agents/tests/fm-backend-tmux-smoke.test.sh +173 -0
  510. package/.agents/tests/fm-backend-zellij-smoke.test.sh +205 -0
  511. package/.agents/tests/fm-backend-zellij.test.sh +1360 -0
  512. package/.agents/tests/fm-backend.test.sh +1142 -0
  513. package/.agents/tests/fm-backlog-atomicity.test.sh +2302 -0
  514. package/.agents/tests/fm-backlog-handoff.test.sh +1360 -0
  515. package/.agents/tests/fm-bearings-board-render.test.sh +135 -0
  516. package/.agents/tests/fm-bearings-board.test.sh +414 -0
  517. package/.agents/tests/fm-bearings-snapshot.test.sh +1990 -0
  518. package/.agents/tests/fm-bootstrap-network-parallel.test.sh +316 -0
  519. package/.agents/tests/fm-bootstrap.test.sh +1178 -0
  520. package/.agents/tests/fm-branch-supervision.test.sh +552 -0
  521. package/.agents/tests/fm-brief.test.sh +785 -0
  522. package/.agents/tests/fm-busy-adapter-wiring.test.sh +324 -0
  523. package/.agents/tests/fm-busy-state.test.sh +465 -0
  524. package/.agents/tests/fm-calm-pi-extension.test.sh +3979 -0
  525. package/.agents/tests/fm-captain-hold-lifecycle.test.sh +1187 -0
  526. package/.agents/tests/fm-cd-pretool-check.test.sh +400 -0
  527. package/.agents/tests/fm-check-unregister.test.sh +198 -0
  528. package/.agents/tests/fm-classify-corr-token.test.sh +543 -0
  529. package/.agents/tests/fm-classify-decision-key.test.sh +340 -0
  530. package/.agents/tests/fm-claude-stop-autoarm-live-e2e.test.sh +164 -0
  531. package/.agents/tests/fm-claude-stop-autoarm.test.sh +1190 -0
  532. package/.agents/tests/fm-cmux-claude-composer-live-e2e.test.sh +110 -0
  533. package/.agents/tests/fm-codex-continuity-live-e2e.test.sh +55 -0
  534. package/.agents/tests/fm-composer-ghost.test.sh +716 -0
  535. package/.agents/tests/fm-composer-lib.test.sh +666 -0
  536. package/.agents/tests/fm-composer-matrix-live-e2e.test.sh +220 -0
  537. package/.agents/tests/fm-control-herdr-smoke.test.sh +149 -0
  538. package/.agents/tests/fm-control-relaunch.test.sh +1530 -0
  539. package/.agents/tests/fm-control.test.sh +910 -0
  540. package/.agents/tests/fm-crew-state.test.sh +1610 -0
  541. package/.agents/tests/fm-cursor-harness.test.sh +404 -0
  542. package/.agents/tests/fm-cursor-primary-live-e2e.test.sh +217 -0
  543. package/.agents/tests/fm-cursor-primary.test.sh +708 -0
  544. package/.agents/tests/fm-daemon.test.sh +2740 -0
  545. package/.agents/tests/fm-documentation-audiences.test.sh +141 -0
  546. package/.agents/tests/fm-ensure-agents-md.test.sh +371 -0
  547. package/.agents/tests/fm-extension-binding.test.sh +2187 -0
  548. package/.agents/tests/fm-fleet-snapshot-view.test.sh +816 -0
  549. package/.agents/tests/fm-fleet-sync.test.sh +721 -0
  550. package/.agents/tests/fm-gate-refuse.test.sh +356 -0
  551. package/.agents/tests/fm-gitignore-config.test.sh +89 -0
  552. package/.agents/tests/fm-gotmp.test.sh +230 -0
  553. package/.agents/tests/fm-grok-continuity-live-e2e.test.sh +112 -0
  554. package/.agents/tests/fm-grok-harness.test.sh +117 -0
  555. package/.agents/tests/fm-grok-stop-live-e2e.test.sh +219 -0
  556. package/.agents/tests/fm-guard-stale-banner.test.sh +709 -0
  557. package/.agents/tests/fm-harness-adapter-instructions-live-e2e.test.sh +134 -0
  558. package/.agents/tests/fm-harness-adapter-references.test.sh +30 -0
  559. package/.agents/tests/fm-harness-liveness-drift-live-e2e.test.sh +151 -0
  560. package/.agents/tests/fm-herdr-lab.test.sh +243 -0
  561. package/.agents/tests/fm-herdr-session-cleanup-e2e.test.sh +146 -0
  562. package/.agents/tests/fm-herdr-session-cleanup.test.sh +329 -0
  563. package/.agents/tests/fm-herdr-submit-confirm-live-e2e.test.sh +125 -0
  564. package/.agents/tests/fm-herdr-version-floor-live-e2e.test.sh +144 -0
  565. package/.agents/tests/fm-home-summary-refresh.test.sh +971 -0
  566. package/.agents/tests/fm-inactive-reconcile.test.sh +485 -0
  567. package/.agents/tests/fm-kimi-harness.test.sh +687 -0
  568. package/.agents/tests/fm-lint-workflows.test.sh +532 -0
  569. package/.agents/tests/fm-lint.test.sh +1023 -0
  570. package/.agents/tests/fm-muse-harness.test.sh +932 -0
  571. package/.agents/tests/fm-muse-signals-live-e2e.test.sh +205 -0
  572. package/.agents/tests/fm-no-mistakes-required.test.sh +72 -0
  573. package/.agents/tests/fm-on.test.sh +507 -0
  574. package/.agents/tests/fm-opencode-primary-live-e2e.test.sh +357 -0
  575. package/.agents/tests/fm-operational-input.test.sh +160 -0
  576. package/.agents/tests/fm-peek-remote.test.sh +110 -0
  577. package/.agents/tests/fm-pending-reply.test.sh +1288 -0
  578. package/.agents/tests/fm-pi-branch-extension.test.sh +3182 -0
  579. package/.agents/tests/fm-pi-branch-live-e2e.test.sh +527 -0
  580. package/.agents/tests/fm-pi-primary-live-e2e.test.sh +345 -0
  581. package/.agents/tests/fm-pi-primary-types.test.sh +68 -0
  582. package/.agents/tests/fm-pi-watch-extension.test.sh +2843 -0
  583. package/.agents/tests/fm-pr-check-security.test.sh +2140 -0
  584. package/.agents/tests/fm-pr-merge.test.sh +2135 -0
  585. package/.agents/tests/fm-procevent-quota.test.sh +225 -0
  586. package/.agents/tests/fm-procevent-when.test.sh +406 -0
  587. package/.agents/tests/fm-procevent.test.sh +1745 -0
  588. package/.agents/tests/fm-project-origin.test.sh +110 -0
  589. package/.agents/tests/fm-public-followup.test.sh +2272 -0
  590. package/.agents/tests/fm-quota-array-dispatch-live-e2e.test.sh +526 -0
  591. package/.agents/tests/fm-quota-choose.test.sh +626 -0
  592. package/.agents/tests/fm-remote-backlog-handoff.test.sh +453 -0
  593. package/.agents/tests/fm-remote-doctor.test.sh +625 -0
  594. package/.agents/tests/fm-remote-entrypoint.test.sh +59 -0
  595. package/.agents/tests/fm-remote-job-orphan-reap.test.sh +205 -0
  596. package/.agents/tests/fm-remote-job.test.sh +768 -0
  597. package/.agents/tests/fm-remote-reply.test.sh +520 -0
  598. package/.agents/tests/fm-remote-secondmate-lifecycle-e2e.test.sh +1256 -0
  599. package/.agents/tests/fm-remote-secondmate-parent-binding.test.sh +326 -0
  600. package/.agents/tests/fm-remote-secondmate-trace-context.test.sh +310 -0
  601. package/.agents/tests/fm-remote-transport-lanes.test.sh +431 -0
  602. package/.agents/tests/fm-review-diff.test.sh +176 -0
  603. package/.agents/tests/fm-secondmate-harness.test.sh +2600 -0
  604. package/.agents/tests/fm-secondmate-lifecycle-e2e.test.sh +259 -0
  605. package/.agents/tests/fm-secondmate-liveness.test.sh +559 -0
  606. package/.agents/tests/fm-secondmate-reconcile.test.sh +732 -0
  607. package/.agents/tests/fm-secondmate-safety.test.sh +2972 -0
  608. package/.agents/tests/fm-secondmate-sync.test.sh +913 -0
  609. package/.agents/tests/fm-send-inbox-doorbell-live-e2e.test.sh +206 -0
  610. package/.agents/tests/fm-send-inbox.test.sh +352 -0
  611. package/.agents/tests/fm-send-popup-settle.test.sh +167 -0
  612. package/.agents/tests/fm-send-remote-delivery.test.sh +796 -0
  613. package/.agents/tests/fm-send-resolve-key.test.sh +551 -0
  614. package/.agents/tests/fm-send-secondmate-marker-herdr-e2e.test.sh +187 -0
  615. package/.agents/tests/fm-send-secondmate-marker.test.sh +278 -0
  616. package/.agents/tests/fm-send-settle.test.sh +147 -0
  617. package/.agents/tests/fm-send-strict.test.sh +241 -0
  618. package/.agents/tests/fm-session-lock-ancestry.test.sh +365 -0
  619. package/.agents/tests/fm-session-start.test.sh +2515 -0
  620. package/.agents/tests/fm-sessionstart-hook-live-e2e.test.sh +631 -0
  621. package/.agents/tests/fm-sessionstart-instruction-refresh-live-e2e.test.sh +230 -0
  622. package/.agents/tests/fm-sessionstart-nudge.test.sh +1039 -0
  623. package/.agents/tests/fm-shared-captain-inheritance.test.sh +404 -0
  624. package/.agents/tests/fm-spawn-batch.test.sh +148 -0
  625. package/.agents/tests/fm-spawn-dispatch-profile.test.sh +827 -0
  626. package/.agents/tests/fm-spawn-pool-base-freshen.test.sh +440 -0
  627. package/.agents/tests/fm-spawn-worktree-settle.test.sh +147 -0
  628. package/.agents/tests/fm-startup-memory-budget.test.sh +333 -0
  629. package/.agents/tests/fm-startup-network.test.sh +712 -0
  630. package/.agents/tests/fm-stow-cascade.test.sh +370 -0
  631. package/.agents/tests/fm-subagent-pretool-check.test.sh +291 -0
  632. package/.agents/tests/fm-supervision-events.test.sh +156 -0
  633. package/.agents/tests/fm-supervision-instructions.test.sh +189 -0
  634. package/.agents/tests/fm-tangle-guard.test.sh +277 -0
  635. package/.agents/tests/fm-task-delivery.test.sh +420 -0
  636. package/.agents/tests/fm-task-inbox.test.sh +513 -0
  637. package/.agents/tests/fm-teardown-endpoint-safety.test.sh +374 -0
  638. package/.agents/tests/fm-teardown.test.sh +2665 -0
  639. package/.agents/tests/fm-test-fixture-cleanup.test.sh +172 -0
  640. package/.agents/tests/fm-test-fixtures.test.sh +132 -0
  641. package/.agents/tests/fm-test-isolation-proof.test.sh +278 -0
  642. package/.agents/tests/fm-test-run.test.sh +1196 -0
  643. package/.agents/tests/fm-tmux-agent-liveness.test.sh +354 -0
  644. package/.agents/tests/fm-tmux-submit-busy.test.sh +340 -0
  645. package/.agents/tests/fm-tool-update-check.test.sh +1044 -0
  646. package/.agents/tests/fm-trace-context-lib.test.sh +253 -0
  647. package/.agents/tests/fm-trace-context-spawn.test.sh +581 -0
  648. package/.agents/tests/fm-transition-lib.test.sh +54 -0
  649. package/.agents/tests/fm-turnend-guard.test.sh +1822 -0
  650. package/.agents/tests/fm-update.test.sh +304 -0
  651. package/.agents/tests/fm-vendor-auth-probe.test.sh +395 -0
  652. package/.agents/tests/fm-voice-relay.test.sh +4741 -0
  653. package/.agents/tests/fm-wake-daemon-lifecycle-e2e.test.sh +171 -0
  654. package/.agents/tests/fm-wake-drain-open-decisions-cursor.test.sh +356 -0
  655. package/.agents/tests/fm-wake-drain-open-decisions.test.sh +226 -0
  656. package/.agents/tests/fm-wake-drain-unread-status.test.sh +379 -0
  657. package/.agents/tests/fm-wake-queue.test.sh +1224 -0
  658. package/.agents/tests/fm-watch-arm.test.sh +821 -0
  659. package/.agents/tests/fm-watch-checkpoint.test.sh +87 -0
  660. package/.agents/tests/fm-watch-recovery-loop.test.sh +223 -0
  661. package/.agents/tests/fm-watch-triage.test.sh +3889 -0
  662. package/.agents/tests/fm-watcher-lock.test.sh +1133 -0
  663. package/.agents/tests/fm-x-mode.test.sh +3042 -0
  664. package/.agents/tests/gleipnir-guard-pretool-check.test.sh +51 -0
  665. package/.agents/tests/gleipnir-machine-lock.test.sh +130 -0
  666. package/.agents/tests/herdr-test-safety.sh +42 -0
  667. package/.agents/tests/lib.sh +315 -0
  668. package/.agents/tests/remote-herdr-fixture.sh +125 -0
  669. package/.agents/tests/secondmate-helpers.sh +193 -0
  670. package/.agents/tests/smoke.test.sh +93 -0
  671. package/.agents/tests/wake-helpers.sh +338 -0
  672. package/.agents/tests/zellij-test-safety.sh +60 -0
  673. package/.agents/tools/README.md +10 -0
  674. package/.agents/tools/bin/tasks-cli +267 -0
  675. package/.agents/tools/tasks-cli.ts +216 -0
  676. package/AGENTS.md +454 -0
  677. package/CHANGELOG.md +881 -0
  678. package/LICENSE +1 -1
  679. package/NOTICE +63 -0
  680. package/README.md +113 -39
  681. package/RULES/01-domains.md +51 -0
  682. package/RULES/02-agents.md +78 -0
  683. package/RULES/03-houses.md +61 -0
  684. package/RULES/04-hoard.md +65 -0
  685. package/RULES/05-platforms.md +67 -0
  686. package/RULES/06-append-only.md +58 -0
  687. package/RULES/07-config.md +45 -0
  688. package/RULES/08-delivery-gate.md +75 -0
  689. package/RULES/README.md +20 -0
  690. package/bin/README.md +107 -0
  691. package/bin/a2a-mcp.sh +98 -0
  692. package/bin/a2a-serve.py +103 -0
  693. package/bin/a2a-serve.sh +8 -0
  694. package/bin/a2a-talk.sh +50 -0
  695. package/bin/a2abridge-ensure.sh +108 -0
  696. package/bin/agent-run.sh +43 -0
  697. package/bin/agents-config.sh +233 -0
  698. package/bin/apodex-smoke-test.sh +92 -0
  699. package/bin/bifrost-bridge.sh +112 -0
  700. package/bin/bifrost-ingress.sh +77 -0
  701. package/bin/bootstrap-macos.sh +107 -0
  702. package/bin/bootstrap-windows.ps1 +112 -0
  703. package/bin/branch-guard.sh +64 -0
  704. package/bin/brokk +73 -0
  705. package/bin/brokk-classify-lib.sh +1770 -0
  706. package/bin/brokk-lease-lib.sh +222 -0
  707. package/bin/brokk-lease.sh +193 -0
  708. package/bin/brokk-lint.sh +65 -0
  709. package/bin/brokk-send.sh +38 -0
  710. package/bin/brokk-update.sh +9 -0
  711. package/bin/brokk-wake-grant.sh +127 -0
  712. package/bin/brokk-wake-lib.sh +1849 -0
  713. package/bin/changelog-guard.sh +165 -0
  714. package/bin/crash-sense.sh +160 -0
  715. package/bin/desktop-place.sh +224 -0
  716. package/bin/docs-guard.sh +39 -0
  717. package/bin/editor-place.sh +207 -0
  718. package/bin/eindri-acclaim.sh +34 -0
  719. package/bin/eindri-control.sh +28 -0
  720. package/bin/eindri-role.sh +83 -0
  721. package/bin/eindri-seen.sh +41 -0
  722. package/bin/eindri-send.sh +15 -0
  723. package/bin/eindri-start.sh +85 -0
  724. package/bin/eindri-watch.sh +57 -0
  725. package/bin/einherjar-spawn.sh +576 -0
  726. package/bin/eir-doctor.sh +112 -0
  727. package/bin/erindi-brief.sh +271 -0
  728. package/bin/fleet-apply.sh +68 -0
  729. package/bin/github-deploy.sh +81 -0
  730. package/bin/gjallarhorn-expose.sh +102 -0
  731. package/bin/gjallarhorn-notify.sh +58 -0
  732. package/bin/gjallarhorn-purge.sh +54 -0
  733. package/bin/gjallarhorn-tunnel.sh +72 -0
  734. package/bin/gleipnir-lock-lib.sh +284 -0
  735. package/bin/groa-update.sh +122 -0
  736. package/bin/hall-snapshot.sh +92 -0
  737. package/bin/hamr-harness.sh +246 -0
  738. package/bin/heimdall-ssh-keys.sh +374 -0
  739. package/bin/herdr-agents.py +44 -0
  740. package/bin/herdr-ensure.sh +104 -0
  741. package/bin/herdr-run.sh +431 -0
  742. package/bin/hermes-ensure.sh +88 -0
  743. package/bin/hoard-lib.sh +25 -0
  744. package/bin/hodd.sh +78 -0
  745. package/bin/host-sense.sh +199 -0
  746. package/bin/huginn-research-worker.sh +108 -0
  747. package/bin/local-model-lock.sh +51 -0
  748. package/bin/mimir-bridge.py +226 -0
  749. package/bin/mimir-bridge.sh +87 -0
  750. package/bin/mimir-ingest.sh +131 -0
  751. package/bin/mimir.sh +113 -0
  752. package/bin/mjollnir-webhook.sh +59 -0
  753. package/bin/mjollnir.sh +85 -0
  754. package/bin/model-hardware.sh +82 -0
  755. package/bin/model-resolve.sh +147 -0
  756. package/bin/models-detect.sh +178 -0
  757. package/bin/nornir-cron-start.sh +162 -0
  758. package/bin/nornir-job-daily-briefing.sh +191 -0
  759. package/bin/nornir-job-git-sync.sh +152 -0
  760. package/bin/nornir-job-memory-housekeeping.sh +114 -0
  761. package/bin/nornir-job-observer.sh +166 -0
  762. package/bin/nornir-job-skillopt-sleep.sh +76 -0
  763. package/bin/omarchy-hook-install.sh +60 -0
  764. package/bin/omarchy-install.sh +148 -0
  765. package/bin/omarchy-plugins.sh +174 -0
  766. package/bin/omarchy-sense.sh +149 -0
  767. package/bin/perm-guard.sh +30 -0
  768. package/bin/pi-agent.sh +68 -0
  769. package/bin/pi-ensure.sh +77 -0
  770. package/bin/pi-local.sh +37 -0
  771. package/bin/pi-seat.sh +63 -0
  772. package/bin/prereq-ensure.sh +166 -0
  773. package/bin/private-guard.sh +38 -0
  774. package/bin/project-git.sh +55 -0
  775. package/bin/public-guard.sh +70 -0
  776. package/bin/ratatoskr.sh +49 -0
  777. package/bin/realm-lib.sh +32 -0
  778. package/bin/repo-scrub.sh +62 -0
  779. package/bin/rodd-operational-input.sh +250 -0
  780. package/bin/runes-append.sh +198 -0
  781. package/bin/saga-session-start.sh +172 -0
  782. package/bin/saga-sessionstart-run.sh +79 -0
  783. package/bin/saga-wake-drain.sh +41 -0
  784. package/bin/secret-guard.sh +63 -0
  785. package/bin/sessrumnir-ensure.sh +100 -0
  786. package/bin/sessrumnir-sync.sh +237 -0
  787. package/bin/sessrumnir.sh +91 -0
  788. package/bin/skillopt-setup.sh +76 -0
  789. package/bin/skuld-branch-outcome.sh +203 -0
  790. package/bin/skuld-branch-prompt.sh +101 -0
  791. package/bin/smidja-bootstrap.sh +90 -0
  792. package/bin/smidja-observe.sh +86 -0
  793. package/bin/syn-arm-pretool-check.sh +57 -0
  794. package/bin/syn-asset-pretool-check.sh +76 -0
  795. package/bin/syn-cd-pretool-check.sh +28 -0
  796. package/bin/syn-guard-pretool-check.sh +83 -0
  797. package/bin/syn-turnend-guard.sh +36 -0
  798. package/bin/syn-watch-arm.sh +99 -0
  799. package/bin/tailscale-sync.sh +190 -0
  800. package/bin/telegram-bot.sh +69 -0
  801. package/bin/toolchain.sh +74 -0
  802. package/bin/utgard.sh +111 -0
  803. package/bin/valhalla.sh +115 -0
  804. package/bin/valknut-load.sh +260 -0
  805. package/bin/vor-crew-state.sh +124 -0
  806. package/bin/wedge-notify.sh +47 -0
  807. package/bin/workspace-provision.sh +80 -0
  808. package/bin/workspace-rag.sh +150 -0
  809. package/bin/wyrd-db.sh +47 -0
  810. package/bin/yggdrasil.sh +152 -0
  811. package/bin/ymir-edit.sh +145 -0
  812. package/bin/ymir-install.sh +641 -0
  813. package/bin/ymir-invite.sh +93 -0
  814. package/bin/ymir-isolation.sh +88 -0
  815. package/bin/ymir-migrate.sh +61 -0
  816. package/bin/ymir-platform.sh +348 -0
  817. package/bin/ymir-say.sh +97 -0
  818. package/bin/ymir-setup-auth.sh +108 -0
  819. package/bin/ymir-validate.sh +173 -0
  820. package/bin/ymir.js +74 -16
  821. package/docs/Architecture.md +339 -0
  822. package/docs/design.md +351 -0
  823. package/docs/installations/README.md +63 -0
  824. package/docs/installations/ymir-home.md +93 -0
  825. package/docs/integration.md +105 -0
  826. package/docs/lore.md +1056 -0
  827. package/docs/research/agent-harnesses.md +290 -0
  828. package/docs/runbooks/README.md +19 -0
  829. package/docs/runbooks/a2a.md +91 -0
  830. package/docs/runbooks/agent-permissions.md +99 -0
  831. package/docs/runbooks/agents.md +57 -0
  832. package/docs/runbooks/models.md +69 -0
  833. package/docs/runbooks/realm-onboarding.md +60 -0
  834. package/docs/runbooks/secrets-and-hoard.md +60 -0
  835. package/docs/runbooks/updates-and-migrations.md +110 -0
  836. package/docs/runbooks/worktrees-isolation.md +72 -0
  837. package/docs/session-start.md +105 -0
  838. package/docs/skillopt-integration.md +321 -0
  839. package/docs/sync-system.md +66 -0
  840. package/docs/workspaces.md +104 -0
  841. package/docs/ymir-rut.md +260 -0
  842. package/package.json +44 -14
  843. package/packaging/build.sh +74 -0
  844. package/packaging/macos/Ymir Installer.command +43 -0
  845. package/packaging/windows/ymir-setup.nsi +74 -0
  846. package/scripts/README.md +22 -0
  847. package/scripts/electron.sh +210 -0
  848. package/scripts/start.sh +167 -0
  849. package/scripts/stop.sh +113 -0
  850. package/install.sh +0 -35
@@ -0,0 +1,816 @@
1
+ #!/usr/bin/env bash
2
+ # Behavior tests for the read-only fleet snapshot and its human renderer.
3
+ set -u
4
+
5
+ # shellcheck source=tests/lib.sh
6
+ # shellcheck disable=SC1091
7
+ . "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
8
+
9
+ SNAPSHOT="$ROOT/bin/fm-fleet-snapshot.sh"
10
+ VIEW="$ROOT/bin/fm-fleet-view.sh"
11
+ TMP_ROOT=$(fm_test_tmproot fm-fleet-snapshot)
12
+
13
+ command -v jq >/dev/null 2>&1 || { echo "skip: jq not found"; exit 0; }
14
+
15
+ make_fakebin() { # <dir>
16
+ local fb
17
+ fb=$(fm_fakebin "$1")
18
+ cat > "$fb/no-mistakes" <<'SH'
19
+ #!/usr/bin/env bash
20
+ exit 0
21
+ SH
22
+ cat > "$fb/tmux" <<'SH'
23
+ #!/usr/bin/env bash
24
+ set -u
25
+ target=""
26
+ prev=""
27
+ for arg in "$@"; do
28
+ if [ "$prev" = "-t" ]; then target=$arg; fi
29
+ prev=$arg
30
+ done
31
+ case "${1:-}" in
32
+ list-windows)
33
+ sed -n 's/^window=[^:]*://p' "${FM_HOME:?}"/state/*.meta
34
+ ;;
35
+ display-message)
36
+ case "$*" in
37
+ *pane_current_command*)
38
+ case "$target" in
39
+ *dead-secondmate*) printf 'zsh\n' ;;
40
+ *) printf 'codex\n' ;;
41
+ esac
42
+ ;;
43
+ *) printf '%%1\n' ;;
44
+ esac
45
+ ;;
46
+ capture-pane)
47
+ case "$target" in
48
+ *ship-task*|*active-secondmate*) printf 'work in progress\nesc to interrupt\n' ;;
49
+ *) printf 'all quiet\n> \n' ;;
50
+ esac
51
+ ;;
52
+ esac
53
+ exit 0
54
+ SH
55
+ chmod +x "$fb/no-mistakes" "$fb/tmux"
56
+ printf '%s\n' "$fb"
57
+ }
58
+
59
+ make_home() { # <name>
60
+ local home=$TMP_ROOT/$1
61
+ mkdir -p "$home/state" "$home/data" "$home/projects" "$home/config"
62
+ printf '%s\n' "$home"
63
+ }
64
+
65
+ record_claude_idle() { # <state-dir> <id>
66
+ local state=$1 id=$2 gen
67
+ gen=$("$ROOT/bin/fm-busy-event.sh" arm "$state" "$id")
68
+ "$ROOT/bin/fm-busy-event.sh" apply "$state" "$id" idle --gen "$gen" \
69
+ --source claude-hook --event stop
70
+ }
71
+
72
+ write_fixture() { # <home>
73
+ local home=$1 fixture_gen
74
+ mkdir -p "$home/projects/alpha-worktree" "$home/projects/scout-worktree" "$home/secondmate-home"
75
+ cat > "$home/data/backlog.md" <<EOF
76
+ ## In flight
77
+ - [ ] scout-task - Scout Task data/scout-task/report.md (repo: alpha) (kind: scout) (since 2026-07-07)
78
+ - [ ] ship-task - Ship Task https://github.com/kunchenguid/firstmate/pull/9 (repo: alpha) (kind: ship) (priority: 2) (since 2026-07-07)
79
+ Preserve this detail for bearings.
80
+
81
+ ## Queued
82
+ - [ ] queued-task - Queued Task blocked-by: ship-task (repo: alpha) (kind: ship) (since 2026-07-08)
83
+ handoff note without canonical syntax
84
+
85
+ ## Done
86
+ - [x] done-task - Done Task https://github.com/kunchenguid/firstmate/pull/7 (repo: alpha) (kind: ship) (merged 2026-07-06)
87
+ EOF
88
+ mkdir -p "$home/data/scout-task"
89
+ printf '# Scout\n' > "$home/data/scout-task/report.md"
90
+ fm_write_meta "$home/state/ship-task.meta" \
91
+ "window=firstmate:fm-ship-task" \
92
+ "worktree=$home/projects/alpha-worktree" \
93
+ "project=alpha" \
94
+ "harness=claude" \
95
+ "kind=ship" \
96
+ "mode=ship" \
97
+ "yolo=off" \
98
+ "pr=https://github.com/kunchenguid/firstmate/pull/9"
99
+ printf 'needs-decision: choose an API shape\n' > "$home/state/ship-task.status"
100
+ # A working ship task proves it through its own semantic busy-state record
101
+ # (bin/fm-busy-lib.sh), which is what the snapshot's current-state read
102
+ # consults; rendered pane text is no longer a state source.
103
+ fixture_gen=$("$ROOT/bin/fm-busy-event.sh" arm "$home/state" ship-task)
104
+ "$ROOT/bin/fm-busy-event.sh" apply "$home/state" ship-task busy --gen "$fixture_gen" \
105
+ --source claude-hook --event user-prompt-submit
106
+ fm_write_meta "$home/state/scout-task.meta" \
107
+ "window=firstmate:fm-scout-task" \
108
+ "worktree=$home/projects/scout-worktree" \
109
+ "project=alpha" \
110
+ "harness=codex" \
111
+ "kind=scout" \
112
+ "mode=scout" \
113
+ "yolo=off"
114
+ printf 'done: report ready\n' > "$home/state/scout-task.status"
115
+ fm_write_meta "$home/state/secondmate-task.meta" \
116
+ "window=firstmate:fm-secondmate-task" \
117
+ "worktree=$home/secondmate-home" \
118
+ "project=$home/secondmate-home" \
119
+ "harness=codex" \
120
+ "kind=secondmate" \
121
+ "mode=secondmate" \
122
+ "home=$home/secondmate-home" \
123
+ "projects=alpha, beta, gamma, "
124
+ printf 'working: watching delegated scope\n' > "$home/state/secondmate-task.status"
125
+ fm_write_meta "$home/state/cmux-task.meta" \
126
+ "backend=cmux" \
127
+ "window=workspace:surface" \
128
+ "worktree=$home/projects/missing-cmux" \
129
+ "project=alpha" \
130
+ "harness=codex" \
131
+ "kind=ship" \
132
+ "mode=ship"
133
+ }
134
+
135
+ test_empty_fleet_json() {
136
+ local home out view
137
+ home=$(make_home empty)
138
+ out=$(FM_HOME="$home" "$SNAPSHOT" --json)
139
+ printf '%s' "$out" | jq -e '
140
+ .schema == "fm-fleet-snapshot.v1"
141
+ and .backlog.present == false
142
+ and (.tasks|length == 0)
143
+ and .main_inventory.valid == true
144
+ and .main_inventory.reason == null
145
+ and (.main_inventory.orphan_in_flight | length) == 0
146
+ and .main_inventory.unstructured_current_count == 0
147
+ ' >/dev/null \
148
+ || fail "empty snapshot schema or absence markers wrong: $out"
149
+ view=$(FM_HOME="$home" "$VIEW")
150
+ assert_contains "$view" "No live task metadata found." "empty fleet view should say no live metadata"
151
+ pass "empty fleet snapshot and view use explicit absence markers"
152
+ }
153
+
154
+ test_fixture_snapshot_json() {
155
+ local home fakebin out ids
156
+ home=$(make_home fixture)
157
+ write_fixture "$home"
158
+ fakebin=$(make_fakebin "$home")
159
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
160
+ printf '%s' "$out" | jq -e . >/dev/null || fail "snapshot must be valid JSON"
161
+ ids=$(printf '%s' "$out" | jq -r '.tasks | map(.id) | join(",")')
162
+ [ "$ids" = "cmux-task,scout-task,secondmate-task,ship-task" ] \
163
+ || fail "task ordering must be stable by id, got $ids"
164
+ printf '%s' "$out" | jq -e '
165
+ .tasks[] | select(.id == "ship-task")
166
+ | .current_state.state == "working"
167
+ and .current_state.source == "pane"
168
+ and .pr.url == "https://github.com/kunchenguid/firstmate/pull/9"
169
+ and .backlog.body_excerpt == "Preserve this detail for bearings."
170
+ and .hints.pending_decision == false
171
+ and .paths.status_log.kind == "event_history"
172
+ ' >/dev/null || fail "ship task state, PR, body, and stale event hints wrong"
173
+ printf '%s' "$out" | jq -e '
174
+ .tasks[] | select(.id == "scout-task")
175
+ | .paths.report.present == true
176
+ and .hints.scout_report_present == true
177
+ ' >/dev/null || fail "scout report pointer missing"
178
+ printf '%s' "$out" | jq -e '
179
+ .tasks[] | select(.id == "secondmate-task")
180
+ | .secondmate_projects == ["alpha","beta","gamma"]
181
+ and .endpoint.agent_alive == "alive"
182
+ and (.actions.watch | contains("do not routinely fm-peek"))
183
+ ' >/dev/null || fail "secondmate return-channel guidance missing"
184
+ printf '%s' "$out" | jq -e '
185
+ .tasks[] | select(.id == "cmux-task")
186
+ | .backend == "cmux"
187
+ and .paths.worktree.present == false
188
+ and .current_state.state == "unknown"
189
+ ' >/dev/null || fail "cmux missing-file row missing"
190
+ printf '%s' "$out" | jq -e '
191
+ [.backlog.records[] | select(.state == "queued")] | length == 2
192
+ ' >/dev/null || fail "queued canonical and unstructured backlog records missing"
193
+ printf '%s' "$out" | jq -e '
194
+ .backlog.records[] | select(.id == "done-task")
195
+ | .state == "done" and .pr_url == "https://github.com/kunchenguid/firstmate/pull/7"
196
+ ' >/dev/null || fail "done backlog PR row missing"
197
+ pass "fixture snapshot covers task rows, backlog rows, pointers, and stable ordering"
198
+ }
199
+
200
+ # R1 owner contract: main_inventory discloses orphan in-flight and unstructured
201
+ # current rows without inventing task rows.
202
+ test_main_inventory_orphan_and_unstructured_disclosure() {
203
+ local home fakebin out
204
+ home=$(make_home main-inventory)
205
+ mkdir -p "$home/projects/visible"
206
+ cat > "$home/data/backlog.md" <<'EOF'
207
+ ## In flight
208
+ free-form current note
209
+ - [ ] orphan-ship - Structured without meta (repo: alpha) (kind: ship) (since 2026-07-11)
210
+ - [ ] visible-ship - Structured with meta (repo: alpha) (kind: ship) (since 2026-07-11)
211
+
212
+ ## Queued
213
+ another free-form queued note
214
+ - [ ] queued-ship - Structured queued (repo: alpha) (kind: ship)
215
+
216
+ ## Done
217
+ EOF
218
+ fm_write_meta "$home/state/visible-ship.meta" \
219
+ "window=firstmate:fm-visible-ship" \
220
+ "worktree=$home/projects/visible" \
221
+ "project=alpha" \
222
+ "harness=codex" \
223
+ "kind=ship" \
224
+ "mode=ship"
225
+ printf 'working: visible\n' > "$home/state/visible-ship.status"
226
+ fakebin=$(make_fakebin "$home")
227
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
228
+ printf '%s' "$out" | jq -e '
229
+ .main_inventory.valid == false
230
+ and .main_inventory.reason == "unstructured current backlog row"
231
+ and .main_inventory.unstructured_current_count == 2
232
+ and (.main_inventory.orphan_in_flight == ["orphan-ship"])
233
+ and ([.tasks[].id] == ["visible-ship"])
234
+ ' >/dev/null || fail "main_inventory did not disclose orphan/unstructured: $out"
235
+ # Counterfactual: add meta for the orphan and strip free-form current lines.
236
+ cat > "$home/data/backlog.md" <<'EOF'
237
+ ## In flight
238
+ - [ ] orphan-ship - Structured without meta (repo: alpha) (kind: ship) (since 2026-07-11)
239
+ - [ ] visible-ship - Structured with meta (repo: alpha) (kind: ship) (since 2026-07-11)
240
+
241
+ ## Queued
242
+ - [ ] queued-ship - Structured queued (repo: alpha) (kind: ship)
243
+
244
+ ## Done
245
+ EOF
246
+ fm_write_meta "$home/state/orphan-ship.meta" \
247
+ "window=firstmate:fm-orphan-ship" \
248
+ "worktree=$home/projects/visible" \
249
+ "project=alpha" \
250
+ "harness=codex" \
251
+ "kind=ship" \
252
+ "mode=ship"
253
+ printf 'working: orphan now live\n' > "$home/state/orphan-ship.status"
254
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
255
+ printf '%s' "$out" | jq -e '
256
+ .main_inventory.valid == true
257
+ and .main_inventory.reason == null
258
+ and .main_inventory.unstructured_current_count == 0
259
+ and (.main_inventory.orphan_in_flight | length) == 0
260
+ and (([.tasks[].id] | sort) == ["orphan-ship", "visible-ship"])
261
+ ' >/dev/null || fail "main_inventory stayed invalid after meta + structured cleanup: $out"
262
+ pass "main_inventory discloses orphan/unstructured and clears when inventory is consistent"
263
+ }
264
+
265
+ test_normalized_roles_and_plural_blocker_readiness() {
266
+ local home fakebin out
267
+ home=$(make_home normalized-records)
268
+ mkdir -p "$home/projects/worker"
269
+ cat > "$home/data/backlog.md" <<'EOF'
270
+ ## In flight
271
+ - [ ] program - Aggregate program (repo: alpha) (kind: program)
272
+ - [ ] observation - Held observation (repo: alpha) (kind: scout) (hold: watch production) (hold-kind: external)
273
+ - [ ] worker - Real worker (repo: alpha) (kind: ship)
274
+ - [ ] orphan - Ordinary missing worker (repo: alpha) (kind: ship)
275
+
276
+ ## Queued
277
+ - [ ] review - Security review (repo: alpha) (kind: ship)
278
+ - [ ] captain-run - Run canary blocked-by: worker blocked-by: review (repo: alpha) (kind: captain) (hold: captain runs canary) (hold-kind: captain)
279
+
280
+ ## Done
281
+ EOF
282
+ fm_write_meta "$home/state/worker.meta" \
283
+ "window=firstmate:fm-worker" "worktree=$home/projects/worker" "project=alpha" \
284
+ "harness=codex" "kind=ship" "mode=ship"
285
+ printf 'working: preparing canary\n' > "$home/state/worker.status"
286
+ fakebin=$(make_fakebin "$home")
287
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
288
+ printf '%s' "$out" | jq -e '
289
+ .main_inventory.orphan_in_flight == ["orphan"]
290
+ and (.backlog.records[] | select(.id == "program")
291
+ | .current_role == "program" and .requires_child_metadata == false)
292
+ and (.backlog.records[] | select(.id == "observation")
293
+ | .current_role == "held" and .requires_child_metadata == false)
294
+ and (.backlog.records[] | select(.id == "orphan")
295
+ | .current_role == "worker" and .requires_child_metadata == true)
296
+ and (.backlog.records[] | select(.id == "captain-run")
297
+ | .blocked_by == "review"
298
+ and .blocked_by_ids == ["worker", "review"]
299
+ and .unresolved_blocker_ids == ["worker", "review"]
300
+ and .captain_actionable == false)
301
+ ' >/dev/null || fail "normalized role or plural blocker fields were wrong: $out"
302
+
303
+ cat > "$home/data/backlog.md" <<'EOF'
304
+ ## In flight
305
+ - [ ] program - Aggregate program (repo: alpha) (kind: program)
306
+ - [ ] observation - Held observation (repo: alpha) (kind: scout) (hold: watch production) (hold-kind: external)
307
+
308
+ ## Queued
309
+ - [ ] review - Security review (repo: alpha) (kind: ship)
310
+ - [ ] captain-run - Run canary blocked-by: worker blocked-by: review (repo: alpha) (kind: captain) (hold: captain runs canary) (hold-kind: captain)
311
+
312
+ ## Done
313
+ - [x] worker - Real worker (repo: alpha) (kind: ship) (done 2026-07-22)
314
+ EOF
315
+ rm "$home/state/worker.meta" "$home/state/worker.status"
316
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
317
+ printf '%s' "$out" | jq -e '
318
+ .backlog.records[] | select(.id == "captain-run")
319
+ | .blocked_by == "review"
320
+ and .blocked_by_ids == ["worker", "review"]
321
+ and .unresolved_blocker_ids == ["review"]
322
+ and .captain_actionable == false
323
+ ' >/dev/null || fail "one completed blocker did not leave exactly one unresolved id: $out"
324
+
325
+ cat > "$home/data/backlog.md" <<'EOF'
326
+ ## In flight
327
+ - [ ] program - Aggregate program (repo: alpha) (kind: program)
328
+ - [ ] observation - Held observation (repo: alpha) (kind: scout) (hold: watch production) (hold-kind: external)
329
+
330
+ ## Queued
331
+ - [ ] captain-run - Run canary blocked-by: worker blocked-by: review (repo: alpha) (kind: captain) (hold: captain runs canary) (hold-kind: captain)
332
+
333
+ ## Done
334
+ - [x] worker - Real worker (repo: alpha) (kind: ship) (done 2026-07-22)
335
+ - [x] review - Security review (repo: alpha) (kind: ship) (done 2026-07-22)
336
+ EOF
337
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
338
+ printf '%s' "$out" | jq -e '
339
+ .backlog.records[] | select(.id == "captain-run")
340
+ | .blocked_by == "review"
341
+ and .blocked_by_ids == ["worker", "review"]
342
+ and .unresolved_blocker_ids == []
343
+ and .captain_actionable == true
344
+ ' >/dev/null || fail "completed blockers did not make the captain hold actionable: $out"
345
+
346
+ sed 's/blocked-by: review/blocked-by: missing/' "$home/data/backlog.md" > "$home/data/backlog.next"
347
+ mv "$home/data/backlog.next" "$home/data/backlog.md"
348
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
349
+ printf '%s' "$out" | jq -e '
350
+ .backlog.records[] | select(.id == "captain-run")
351
+ | .blocked_by_ids == ["worker", "missing"]
352
+ and .unresolved_blocker_ids == ["missing"]
353
+ and .captain_actionable == false
354
+ ' >/dev/null || fail "a missing blocker was incorrectly treated as resolved: $out"
355
+ pass "backlog normalization preserves strict roles and resolves every blocker compatibly"
356
+ }
357
+
358
+ test_event_hints_follow_reconciled_current_state() {
359
+ local home fakebin out hint_gen
360
+ home=$(make_home event-hints)
361
+ mkdir -p \
362
+ "$home/projects/active-decision" \
363
+ "$home/projects/active-blocked" \
364
+ "$home/projects/stale-decision" \
365
+ "$home/projects/stale-blocked"
366
+ fm_write_meta "$home/state/active-decision.meta" \
367
+ "window=firstmate:fm-active-decision" \
368
+ "worktree=$home/projects/active-decision" \
369
+ "project=alpha" \
370
+ "harness=claude" \
371
+ "kind=ship" \
372
+ "mode=ship"
373
+ record_claude_idle "$home/state" active-decision
374
+ printf 'needs-decision: choose an API shape\n' > "$home/state/active-decision.status"
375
+ fm_write_meta "$home/state/active-blocked.meta" \
376
+ "window=firstmate:fm-active-blocked" \
377
+ "worktree=$home/projects/active-blocked" \
378
+ "project=alpha" \
379
+ "harness=claude" \
380
+ "kind=ship" \
381
+ "mode=ship"
382
+ record_claude_idle "$home/state" active-blocked
383
+ printf 'blocked: waiting on access\n' > "$home/state/active-blocked.status"
384
+ fm_write_meta "$home/state/stale-decision.meta" \
385
+ "window=firstmate:fm-stale-decision-ship-task" \
386
+ "worktree=$home/projects/stale-decision" \
387
+ "project=alpha" \
388
+ "harness=claude" \
389
+ "kind=ship" \
390
+ "mode=ship"
391
+ hint_gen=$("$ROOT/bin/fm-busy-event.sh" arm "$home/state" stale-decision)
392
+ "$ROOT/bin/fm-busy-event.sh" apply "$home/state" stale-decision busy --gen "$hint_gen" \
393
+ --source claude-hook --event user-prompt-submit
394
+ printf 'needs-decision: already answered\n' > "$home/state/stale-decision.status"
395
+ fm_write_meta "$home/state/stale-blocked.meta" \
396
+ "window=firstmate:fm-stale-blocked-ship-task" \
397
+ "worktree=$home/projects/stale-blocked" \
398
+ "project=alpha" \
399
+ "harness=claude" \
400
+ "kind=ship" \
401
+ "mode=ship"
402
+ hint_gen=$("$ROOT/bin/fm-busy-event.sh" arm "$home/state" stale-blocked)
403
+ "$ROOT/bin/fm-busy-event.sh" apply "$home/state" stale-blocked busy --gen "$hint_gen" \
404
+ --source claude-hook --event user-prompt-submit
405
+ printf 'blocked: old failure\n' > "$home/state/stale-blocked.status"
406
+ fakebin=$(make_fakebin "$home")
407
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
408
+ printf '%s' "$out" | jq -e '
409
+ def task($id): (.tasks[] | select(.id == $id));
410
+ task("active-decision").current_state.state == "parked"
411
+ and task("active-decision").hints.pending_decision == true
412
+ and task("active-blocked").current_state.state == "blocked"
413
+ and task("active-blocked").hints.blocked_event == true
414
+ and task("stale-decision").current_state.state == "working"
415
+ and task("stale-decision").hints.pending_decision == false
416
+ and task("stale-blocked").current_state.state == "working"
417
+ and task("stale-blocked").hints.blocked_event == false
418
+ ' >/dev/null || fail "event hints must follow reconciled current state"
419
+ pass "snapshot event hints follow reconciled current state"
420
+ }
421
+
422
+ test_scout_reports_include_teardown_reports() {
423
+ local home out
424
+ home=$(make_home teardown-reports)
425
+ mkdir -p "$home/data/reported-scout" "$home/data/untracked-scout"
426
+ cat > "$home/data/backlog.md" <<EOF
427
+ ## Done
428
+ - [x] reported-scout - Reported Scout data/reported-scout/report.md (repo: alpha, reported 2026-07-07) (kind: scout)
429
+ EOF
430
+ printf '# Reported Scout\n' > "$home/data/reported-scout/report.md"
431
+ printf '# Untracked Scout\n' > "$home/data/untracked-scout/report.md"
432
+ out=$(FM_HOME="$home" "$SNAPSHOT" --json)
433
+ printf '%s' "$out" | jq -e --arg home "$home" '
434
+ (.tasks | length) == 0
435
+ and .scout_reports == [
436
+ {id:"reported-scout",path:($home + "/data/reported-scout/report.md"),kind:"scout"},
437
+ {id:"untracked-scout",path:($home + "/data/untracked-scout/report.md"),kind:"scout"}
438
+ ]
439
+ ' >/dev/null || fail "durable scout reports should remain visible after meta teardown"
440
+ pass "snapshot includes durable scout reports after teardown"
441
+ }
442
+
443
+ test_backlog_tasks_axi_forms_and_overrides() {
444
+ local home data projects fakebin out view
445
+ home=$(make_home overrides)
446
+ data=$TMP_ROOT/override-data
447
+ projects=$TMP_ROOT/override-projects
448
+ mkdir -p "$data/bold-task" "$projects/bold-worktree"
449
+ cat > "$data/backlog.md" <<EOF
450
+ ## In flight
451
+ - **bold-task** - Bold Task data/bold-task/report.md (repo: alpha, since 2026-07-07) (kind: scout)
452
+ Bold body survives.
453
+
454
+ ## Queued
455
+ - [ ] queued-comma - Queued Comma Task (repo: beta, since 2026-07-08) (kind: ship)
456
+ - [ ] parenthetical-title - Refresh sidebar (mobile) (repo: beta) (kind: ship)
457
+ - [ ] blocked-reason - Blocked Reason (repo: beta) (kind: ship) blocked-by: queued-comma - waits on queued-comma
458
+ - [ ] sample-decision-route - Choose sample route (repo: sample) (kind: captain) (since 2026-07-14) (hold: captain route choice pending) (hold-kind: captain)
459
+ - [ ] dated-route - Deferred sample route (repo: sample) (kind: ship) (hold: captain sent this to later) (hold-kind: captain) (hold-until: 2026-09-01)
460
+ - [ ] captain-gated-work - Captain-gated ship work (repo: sample) (kind: ship) (hold: captain go pending) (hold-kind: captain)
461
+ - [ ] parked-prose - Parked captain call (repo: sample) (kind: ship) (hold: DEFERRED by captain) (hold-kind: captain)
462
+
463
+ ## Done
464
+ - [x] done-comma - Done Comma Task https://github.com/kunchenguid/firstmate/pull/42 (repo: gamma, merged 2026-07-09) (kind: ship)
465
+ - [x] done-bracket-pr - Done Bracket PR - <https://github.com/kunchenguid/firstmate/pull/43> (repo: gamma, merged 2026-07-12) (kind: ship)
466
+ - [x] reported-comma - Reported Scout data/reported-comma/report.md (repo: gamma, reported 2026-07-10) (kind: scout)
467
+ - [x] done-note - Done Note local main (repo: delta, done 2026-07-11) (kind: ship)
468
+ EOF
469
+ printf '# Bold Scout\n' > "$data/bold-task/report.md"
470
+ fm_write_meta "$home/state/bold-task.meta" \
471
+ "window=firstmate:fm-bold-task" \
472
+ "worktree=$projects/bold-worktree" \
473
+ "project=alpha" \
474
+ "harness=claude" \
475
+ "kind=scout" \
476
+ "mode=scout"
477
+ record_claude_idle "$home/state" bold-task
478
+ printf 'done: report ready\n' > "$home/state/bold-task.status"
479
+ fakebin=$(make_fakebin "$home")
480
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" FM_DATA_OVERRIDE="$data" FM_PROJECTS_OVERRIDE="$projects" \
481
+ FM_SNAPSHOT_NOW=2026-07-14T00:00:00Z "$SNAPSHOT" --json)
482
+ printf '%s' "$out" | jq -e --arg data "$data" --arg projects "$projects" '
483
+ .roots.data == $data
484
+ and .roots.projects == $projects
485
+ and .backlog.path == ($data + "/backlog.md")
486
+ ' >/dev/null || fail "snapshot did not respect data/projects overrides"
487
+ printf '%s' "$out" | jq -e --arg data "$data" '
488
+ .backlog.records[] | select(.id == "bold-task")
489
+ | .structured == true
490
+ and .state == "in_flight"
491
+ and .checked == false
492
+ and .repo == "alpha"
493
+ and .since == "2026-07-07"
494
+ and .kind == "scout"
495
+ and .title == "Bold Task"
496
+ and .body_excerpt == "Bold body survives."
497
+ and .report_path == "data/bold-task/report.md"
498
+ ' >/dev/null || fail "bold in-flight backlog row did not parse"
499
+ printf '%s' "$out" | jq -e '
500
+ .backlog.records[] | select(.id == "queued-comma")
501
+ | .repo == "beta" and .since == "2026-07-08"
502
+ ' >/dev/null || fail "queued comma metadata did not split"
503
+ printf '%s' "$out" | jq -e '
504
+ .backlog.records[] | select(.id == "parenthetical-title")
505
+ | .title == "Refresh sidebar (mobile)" and .repo == "beta"
506
+ ' >/dev/null || fail "title parenthetical was stripped with metadata"
507
+ printf '%s' "$out" | jq -e '
508
+ .backlog.records[] | select(.id == "blocked-reason")
509
+ | .title == "Blocked Reason"
510
+ and .repo == "beta"
511
+ and .blocked_by == "queued-comma"
512
+ and .blocked_reason == "waits on queued-comma"
513
+ ' >/dev/null || fail "blocked suffix did not parse into title and reason"
514
+ printf '%s' "$out" | jq -e '
515
+ .backlog.records[] | select(.id == "sample-decision-route")
516
+ | .title == "Choose sample route"
517
+ and .repo == "sample"
518
+ and .kind == "captain"
519
+ and .hold_reason == "captain route choice pending"
520
+ and .hold_kind == "captain"
521
+ and .captain_actionable == true
522
+ ' >/dev/null || fail "tasks-axi captain-hold metadata did not parse"
523
+ printf '%s' "$out" | jq -e '
524
+ .backlog.records[] | select(.id == "dated-route")
525
+ | .title == "Deferred sample route"
526
+ and .hold_until == "2026-09-01"
527
+ and .captain_actionable == false
528
+ and .deferred_marker == false
529
+ ' >/dev/null || fail "a dated captain hold did not defer or strip its hold-until from the title"
530
+ printf '%s' "$out" | jq -e '
531
+ .backlog.records[] | select(.id == "captain-gated-work")
532
+ | .kind == "ship" and .captain_actionable == true and .deferred_marker == false
533
+ ' >/dev/null || fail "captain actionability must not depend on the row kind"
534
+ printf '%s' "$out" | jq -e '
535
+ .backlog.records[] | select(.id == "parked-prose")
536
+ | .captain_actionable == true and .deferred_marker == true
537
+ ' >/dev/null || fail "a prose-deferred captain hold did not carry the presentation marker"
538
+ printf '%s' "$out" | jq -e '
539
+ .backlog.records[] | select(.id == "done-comma")
540
+ | .repo == "gamma"
541
+ and .merged == "2026-07-09"
542
+ and .completion == {verb:"merged",date:"2026-07-09"}
543
+ ' >/dev/null || fail "done comma metadata did not split"
544
+ printf '%s' "$out" | jq -e '
545
+ .backlog.records[] | select(.id == "done-bracket-pr")
546
+ | .repo == "gamma"
547
+ and .title == "Done Bracket PR"
548
+ and .pr_url == "https://github.com/kunchenguid/firstmate/pull/43"
549
+ and .links == ["https://github.com/kunchenguid/firstmate/pull/43"]
550
+ and .completion == {verb:"merged",date:"2026-07-12"}
551
+ ' >/dev/null || fail "bracketed PR artifact did not parse"
552
+ printf '%s' "$out" | jq -e '
553
+ .backlog.records[] | select(.id == "reported-comma")
554
+ | .repo == "gamma"
555
+ and .title == "Reported Scout"
556
+ and .reported == "2026-07-10"
557
+ and .completion == {verb:"reported",date:"2026-07-10"}
558
+ ' >/dev/null || fail "reported closure metadata did not parse"
559
+ printf '%s' "$out" | jq -e '
560
+ .backlog.records[] | select(.id == "done-note")
561
+ | .repo == "delta"
562
+ and .title == "Done Note"
563
+ and .local_note == "local main"
564
+ and .done == "2026-07-11"
565
+ and .completion == {verb:"done",date:"2026-07-11"}
566
+ ' >/dev/null || fail "done closure metadata did not parse"
567
+ printf '%s' "$out" | jq -e --arg data "$data" '
568
+ .tasks[] | select(.id == "bold-task")
569
+ | .backlog.id == "bold-task"
570
+ and .paths.report.path == ($data + "/bold-task/report.md")
571
+ and .paths.report.present == true
572
+ ' >/dev/null || fail "bold task did not join to override-backed backlog and report"
573
+ view=$(PATH="$fakebin:$PATH" FM_HOME="$home" FM_DATA_OVERRIDE="$data" FM_PROJECTS_OVERRIDE="$projects" "$VIEW")
574
+ assert_contains "$view" "| bold-task | done / status-log | scout | alpha | tmux | present | $data/bold-task/report.md" \
575
+ "view should render bold in-flight row from snapshot"
576
+ assert_contains "$view" "| blocked-reason | Blocked Reason | beta | ship | queued-comma - waits on queued-comma | - |" \
577
+ "view should render blocked reason without title metadata"
578
+ assert_contains "$view" "| done-bracket-pr | Done Bracket PR | gamma | ship | - | https://github.com/kunchenguid/firstmate/pull/43 |" \
579
+ "view should render bracketed PR artifact outside the title"
580
+ assert_contains "$view" "| done-note | Done Note | delta | ship | - | local main |" \
581
+ "view should render local-only done artifact outside the title"
582
+ pass "snapshot parses tasks-axi rows and respects operational overrides"
583
+ }
584
+
585
+ test_view_renders_snapshot() {
586
+ local home fakebin view
587
+ home=$(make_home view)
588
+ write_fixture "$home"
589
+ fakebin=$(make_fakebin "$home")
590
+ view=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$VIEW")
591
+ assert_contains "$view" "| ship-task | working / pane | ship | alpha | tmux | present | https://github.com/kunchenguid/firstmate/pull/9" \
592
+ "view should render ship row from snapshot"
593
+ assert_contains "$view" "| queued-task | Queued Task | alpha | ship | ship-task | -" \
594
+ "view should render queued backlog row"
595
+ assert_contains "$view" "| done-task | Done Task | alpha | ship | - | https://github.com/kunchenguid/firstmate/pull/7 |" \
596
+ "view should render done backlog row"
597
+ assert_contains "$view" "bin/fm-send.sh fm-secondmate-task" \
598
+ "view should show secondmate send guidance"
599
+ assert_contains "$view" "| secondmate-task | working / status-log | secondmate | $home/secondmate-home | tmux | present / alive |" \
600
+ "view should show secondmate endpoint agent liveness"
601
+ assert_not_contains "$view" "fm-peek.sh fm-secondmate-task" \
602
+ "view must not tell firstmate to routinely peek secondmates"
603
+ pass "fleet view renders the snapshot without secondmate peek guidance"
604
+ }
605
+
606
+ test_view_renders_dead_secondmate_agent_status() {
607
+ local home fakebin view
608
+ home=$(make_home dead-secondmate)
609
+ fm_write_meta "$home/state/dead-secondmate.meta" \
610
+ "window=firstmate:fm-dead-secondmate" \
611
+ "project=$home/secondmate-home" \
612
+ "harness=codex" \
613
+ "kind=secondmate" \
614
+ "mode=secondmate" \
615
+ "home=$home/secondmate-home" \
616
+ "projects=alpha, beta"
617
+ printf 'working: watching delegated scope\n' > "$home/state/dead-secondmate.status"
618
+ fakebin=$(make_fakebin "$home")
619
+ view=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$VIEW")
620
+ assert_contains "$view" "| dead-secondmate | unknown / none | secondmate | $home/secondmate-home | tmux | present / dead |" \
621
+ "view should distinguish a present secondmate endpoint from a dead agent"
622
+ assert_contains "$view" "| dead-secondmate | unknown / none | secondmate | $home/secondmate-home | tmux | present / dead | - | $home/secondmate-home (absent) |" \
623
+ "view should show a recorded missing secondmate home path"
624
+ pass "fleet view renders secondmate agent liveness"
625
+ }
626
+
627
+ # A still-open decision must survive a LATER, UNRELATED terminal event on the same
628
+ # append-only stream. This is the fmdev masking bug: last-event-wins read the trailing
629
+ # `done` and reported pending_decision=false while a needs-decision was still open. The
630
+ # durable keyed fold (fm-classify-lib.sh) keeps it open until an explicit resolution.
631
+ test_open_decision_survives_later_unrelated_event() {
632
+ local home fakebin out
633
+ home=$(make_home masking)
634
+ mkdir -p "$home/secondmate-home"
635
+ fm_write_meta "$home/state/masked-decision.meta" \
636
+ "window=firstmate:fm-masked-decision" \
637
+ "worktree=$home/secondmate-home" \
638
+ "project=$home/secondmate-home" \
639
+ "harness=codex" \
640
+ "kind=secondmate" \
641
+ "mode=secondmate" \
642
+ "home=$home/secondmate-home" \
643
+ "projects=alpha"
644
+ # needs-decision opened, then two LATER unrelated events (no resolution).
645
+ printf 'needs-decision [key=race]: fix the reconcile-before-subscribe race\n' > "$home/state/masked-decision.status"
646
+ printf 'working: implementing an unrelated subsystem\n' >> "$home/state/masked-decision.status"
647
+ printf 'done: an unrelated subtask finished\n' >> "$home/state/masked-decision.status"
648
+ fakebin=$(make_fakebin "$home")
649
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
650
+ printf '%s' "$out" | jq -e '
651
+ .tasks[] | select(.id == "masked-decision")
652
+ | .hints.pending_decision == true
653
+ and (.hints.open_decisions | length) == 1
654
+ and .hints.open_decisions[0].key == "race"
655
+ and .hints.open_decisions[0].verb == "needs-decision"
656
+ ' >/dev/null || fail "later unrelated done must not mask an open needs-decision: $out"
657
+ pass "durable fold keeps an open decision past a later unrelated event"
658
+ }
659
+
660
+ test_secondmate_open_decision_survives_live_endpoint() {
661
+ local home fakebin out
662
+ home=$(make_home active-secondmate)
663
+ mkdir -p "$home/secondmate-home"
664
+ fm_write_meta "$home/state/active-secondmate.meta" \
665
+ "window=firstmate:fm-active-secondmate" \
666
+ "worktree=$home/secondmate-home" \
667
+ "project=$home/secondmate-home" \
668
+ "harness=codex" \
669
+ "kind=secondmate" \
670
+ "mode=secondmate" \
671
+ "home=$home/secondmate-home" \
672
+ "projects=alpha"
673
+ printf 'needs-decision [key=race]: choose ordering\n' > "$home/state/active-secondmate.status"
674
+ fakebin=$(make_fakebin "$home")
675
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
676
+ printf '%s' "$out" | jq -e '
677
+ .tasks[] | select(.id == "active-secondmate")
678
+ | .endpoint.agent_alive == "alive"
679
+ and .hints.pending_decision == true
680
+ and (.hints.open_decisions | length) == 1
681
+ ' >/dev/null || fail "a live secondmate endpoint must not clear an unrelated keyed decision: $out"
682
+ pass "a live secondmate endpoint preserves unrelated open decisions"
683
+ }
684
+
685
+ # An open decision clears ONLY on an explicit resolution referencing its key, never
686
+ # on an unrelated terminal line.
687
+ test_open_decision_transfers_to_captain_hold() {
688
+ local home fakebin out
689
+ home=$(make_home captain-held-transfer)
690
+ mkdir -p "$home/secondmate-home"
691
+ fm_write_meta "$home/state/transferred-decision.meta" \
692
+ "window=firstmate:fm-transferred-decision" \
693
+ "worktree=$home/secondmate-home" \
694
+ "project=$home/secondmate-home" \
695
+ "harness=codex" \
696
+ "kind=secondmate" \
697
+ "mode=secondmate" \
698
+ "home=$home/secondmate-home" \
699
+ "projects=sample"
700
+ printf 'needs-decision [key=route]: choose a sample route\n' > "$home/state/transferred-decision.status"
701
+ printf 'captain-held [key=route]: tracked by transferred-decision-route\n' >> "$home/state/transferred-decision.status"
702
+ fakebin=$(make_fakebin "$home")
703
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
704
+ printf '%s' "$out" | jq -e '
705
+ .tasks[] | select(.id == "transferred-decision")
706
+ | .hints.pending_decision == false
707
+ and (.hints.open_decisions | length) == 0
708
+ ' >/dev/null || fail "captain-held transfer must close only the duplicate status copy: $out"
709
+ pass "durable captain-held transfer closes the duplicate live status decision"
710
+ }
711
+
712
+ test_open_decision_clears_on_keyed_resolution() {
713
+ local home fakebin out
714
+ home=$(make_home resolution)
715
+ mkdir -p "$home/secondmate-home"
716
+ fm_write_meta "$home/state/resolved-decision.meta" \
717
+ "window=firstmate:fm-resolved-decision" \
718
+ "worktree=$home/secondmate-home" \
719
+ "project=$home/secondmate-home" \
720
+ "harness=codex" \
721
+ "kind=secondmate" \
722
+ "mode=secondmate" \
723
+ "home=$home/secondmate-home" \
724
+ "projects=alpha"
725
+ printf 'needs-decision [key=race]: fix the reconcile-before-subscribe race\n' > "$home/state/resolved-decision.status"
726
+ printf 'done: an unrelated subtask finished\n' >> "$home/state/resolved-decision.status"
727
+ printf 'resolved [key=race]: captain chose subscribe-then-reconcile\n' >> "$home/state/resolved-decision.status"
728
+ fakebin=$(make_fakebin "$home")
729
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
730
+ printf '%s' "$out" | jq -e '
731
+ .tasks[] | select(.id == "resolved-decision")
732
+ | .hints.pending_decision == false
733
+ and (.hints.open_decisions | length) == 0
734
+ ' >/dev/null || fail "keyed resolution must clear the open decision: $out"
735
+ pass "durable fold clears a decision only on a keyed resolution"
736
+ }
737
+
738
+ # A COMPLETED scout report must never be read as a pending decision. A scout that
739
+ # raised a needs-decision and then finished (done) - its report delivered, its
740
+ # decision either answered or captured in the report for the captain - must surface
741
+ # only as a report POINTER, not a reopened pending decision, even when the report
742
+ # body and the stale status line contain decision-like prose. This is the Lavish-103
743
+ # defect: a terminal single-owner task's stale, never-keyed-resolved needs-decision
744
+ # must not linger as pending. Decisions come purely from the keyed fold reconciled
745
+ # against the crew lifecycle; report prose never opens or reopens a decision.
746
+ test_completed_scout_report_is_pointer_not_pending() {
747
+ local home fakebin out
748
+ home=$(make_home completed-scout)
749
+ mkdir -p "$home/projects/scout-wt" "$home/data/lavish-103"
750
+ fm_write_meta "$home/state/lavish-103.meta" \
751
+ "window=firstmate:fm-lavish-103" \
752
+ "worktree=$home/projects/scout-wt" \
753
+ "project=firstmate" \
754
+ "harness=claude" \
755
+ "kind=scout" \
756
+ "mode=scout"
757
+ record_claude_idle "$home/state" lavish-103
758
+ # Stale needs-decision, then the scout finished (done). No keyed resolution.
759
+ printf 'needs-decision: adopt approach A or B for Lavish issue 103\n' > "$home/state/lavish-103.status"
760
+ printf 'done: report ready at data/lavish-103/report.md\n' >> "$home/state/lavish-103.status"
761
+ # Completed report whose PROSE reads like the decision.
762
+ printf '# Lavish 103\nThe open question is whether to adopt approach A or B.\nThis needs a captain decision. Recommendation: A.\n' > "$home/data/lavish-103/report.md"
763
+ fakebin=$(make_fakebin "$home")
764
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
765
+ printf '%s' "$out" | jq -e '
766
+ .tasks[] | select(.id == "lavish-103")
767
+ | .current_state.state == "done"
768
+ and .hints.pending_decision == false
769
+ and (.hints.open_decisions | length) == 0
770
+ and .hints.scout_report_present == true
771
+ ' >/dev/null || fail "a completed scout report must be a pointer, not a pending decision: $out"
772
+ pass "a completed scout's stale decision surfaces as a report pointer, not pending"
773
+ }
774
+
775
+ # The complementary safety property: a scout still PARKED at a decision (its last
776
+ # event is the needs-decision, it has not finished) DOES stay pending. The terminal
777
+ # clear must not over-fire on a live, undecided scout.
778
+ test_parked_scout_decision_stays_pending() {
779
+ local home fakebin out
780
+ home=$(make_home parked-scout)
781
+ mkdir -p "$home/projects/scout-wt2"
782
+ fm_write_meta "$home/state/parked-scout.meta" \
783
+ "window=firstmate:fm-parked-scout" \
784
+ "worktree=$home/projects/scout-wt2" \
785
+ "project=firstmate" \
786
+ "harness=claude" \
787
+ "kind=scout" \
788
+ "mode=scout"
789
+ record_claude_idle "$home/state" parked-scout
790
+ printf 'needs-decision [key=q1]: adopt approach A or B\n' > "$home/state/parked-scout.status"
791
+ fakebin=$(make_fakebin "$home")
792
+ out=$(PATH="$fakebin:$PATH" FM_HOME="$home" "$SNAPSHOT" --json)
793
+ printf '%s' "$out" | jq -e '
794
+ .tasks[] | select(.id == "parked-scout")
795
+ | .hints.pending_decision == true
796
+ and (.hints.open_decisions | length) == 1
797
+ and .hints.open_decisions[0].key == "q1"
798
+ ' >/dev/null || fail "a scout still parked at a decision must stay pending: $out"
799
+ pass "a scout still parked at a decision stays pending (terminal clear does not over-fire)"
800
+ }
801
+
802
+ test_empty_fleet_json
803
+ test_fixture_snapshot_json
804
+ test_main_inventory_orphan_and_unstructured_disclosure
805
+ test_normalized_roles_and_plural_blocker_readiness
806
+ test_event_hints_follow_reconciled_current_state
807
+ test_open_decision_survives_later_unrelated_event
808
+ test_secondmate_open_decision_survives_live_endpoint
809
+ test_open_decision_transfers_to_captain_hold
810
+ test_open_decision_clears_on_keyed_resolution
811
+ test_completed_scout_report_is_pointer_not_pending
812
+ test_parked_scout_decision_stays_pending
813
+ test_scout_reports_include_teardown_reports
814
+ test_backlog_tasks_axi_forms_and_overrides
815
+ test_view_renders_snapshot
816
+ test_view_renders_dead_secondmate_agent_status