@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,785 @@
1
+ #!/usr/bin/env bash
2
+ # Behavior tests for bin/fm-brief.sh.
3
+ #
4
+ # Regression coverage for the heredoc-in-command-substitution parse bug (issues
5
+ # #166, #958, #1069). Building a variable with `VAR=$(cat <<EOF ... EOF)` is
6
+ # unsafe on Bash 3.2 (macOS /bin/bash): the lexer scans for the matching `)` of
7
+ # the command substitution textually and tracks quote state through the heredoc
8
+ # body, so a single apostrophe, unbalanced quote, or unbalanced paren anywhere
9
+ # in that body breaks parsing of the *entire rest of the script* - `bash -n`
10
+ # fails, not just the generated brief. The DOD and Herdr-section builders now
11
+ # use `IFS= read -r -d '' VAR <<EOF || true` instead, which removes the `$(...)`
12
+ # wrapper and eliminates the whole defect class regardless of future prose.
13
+ # test_no_heredoc_in_command_substitution guards that structure directly.
14
+ # Ambient `bash -n` here is Bash 5 and cannot see the bug, so the real
15
+ # cross-version enforcement lives in the macos-stock-bash CI job.
16
+ set -u
17
+
18
+ # shellcheck source=tests/lib.sh
19
+ . "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
20
+
21
+ TMP_ROOT=$(fm_test_tmproot fm-brief)
22
+ BRIEF_HOME="$TMP_ROOT/home"
23
+ mkdir -p "$BRIEF_HOME/data"
24
+
25
+ # The script itself must always parse under the ambient bash. That is Bash 5 in
26
+ # CI and locally, where the issue #958/#1069 parser bug does not fire, so this
27
+ # is a weak guard on its own; test_no_heredoc_in_command_substitution and the
28
+ # macos-stock-bash CI job carry the real cross-version enforcement.
29
+ test_script_parses() {
30
+ local out rc
31
+ out=$(bash -n "$ROOT/bin/fm-brief.sh" 2>&1); rc=$?
32
+ expect_code 0 "$rc" "bash -n bin/fm-brief.sh must parse cleanly (got: $out)"
33
+ [ -z "$out" ] || fail "bash -n bin/fm-brief.sh emitted unexpected output: $out"
34
+ pass "fm-brief.sh: bash -n succeeds"
35
+ }
36
+
37
+ # Structural class guard (issues #166, #958, #1069): never build a variable by
38
+ # wrapping a heredoc in a command substitution (`VAR=$(cat <<EOF ... EOF)`).
39
+ # That construct is what breaks Bash 3.2 parsing, and pinning one historical
40
+ # apostrophe phrase (as the old test did) missed the #945 reintroduction. This
41
+ # guards the *shape* directly against the whole file, so any future DOD or
42
+ # section builder that reintroduces the class fails here regardless of prose.
43
+ test_no_heredoc_in_command_substitution() {
44
+ local unsafe safe
45
+ unsafe="$TMP_ROOT/heredoc-in-substitution.sh"
46
+ safe="$TMP_ROOT/plain-heredoc.sh"
47
+ # shellcheck disable=SC2016 # Literal shell fixtures must remain unexpanded.
48
+ printf '%s\n' 'value=$(' ' cat <<EOF' 'body' 'EOF' ')' > "$unsafe"
49
+ # shellcheck disable=SC2016 # Literal shell fixtures must remain unexpanded.
50
+ printf '%s\n' 'cat <<EOF' '$(' ' cat <<INNER' 'INNER' ')' 'EOF' > "$safe"
51
+ if no_heredoc_in_command_substitution "$unsafe"; then
52
+ fail "structural guard accepted a multiline heredoc nested in a command substitution"
53
+ fi
54
+ no_heredoc_in_command_substitution "$safe" \
55
+ || fail "structural guard treated heredoc body prose as shell structure"
56
+ no_heredoc_in_command_substitution "$ROOT/bin/fm-brief.sh" \
57
+ || fail "fm-brief.sh wraps a heredoc in a command substitution (breaks Bash 3.2 parsing)"
58
+ pass "fm-brief.sh: no heredoc is nested inside a command substitution (Bash 3.2 parse-safe)"
59
+ }
60
+
61
+ no_heredoc_in_command_substitution() {
62
+ perl - "$1" <<'PERL'
63
+ use strict;
64
+ use warnings;
65
+
66
+ my $path = shift;
67
+ open my $source, '<', $path or die "$path: $!\n";
68
+ my @frames;
69
+ my @heredocs;
70
+ my $quote = '';
71
+ my $line_number = 0;
72
+
73
+ while (my $line = <$source>) {
74
+ $line_number++;
75
+ if (@heredocs) {
76
+ my $candidate = $line;
77
+ $candidate =~ s/\r?\n\z//;
78
+ $candidate =~ s/^\t+// if $heredocs[0]{strip_tabs};
79
+ shift @heredocs if $candidate eq $heredocs[0]{delimiter};
80
+ next;
81
+ }
82
+
83
+ my $length = length $line;
84
+ for (my $i = 0; $i < $length; $i++) {
85
+ my $char = substr($line, $i, 1);
86
+ if ($quote eq "'") {
87
+ $quote = '' if $char eq "'";
88
+ next;
89
+ }
90
+ if ($char eq '\\') {
91
+ $i++;
92
+ next;
93
+ }
94
+ if ($quote eq '"' && $char eq '"') {
95
+ $quote = '';
96
+ next;
97
+ }
98
+ if ($char eq "'" && $quote eq '') {
99
+ $quote = "'";
100
+ next;
101
+ }
102
+ if ($char eq '"' && $quote eq '') {
103
+ $quote = '"';
104
+ next;
105
+ }
106
+ if ($char eq '#' && $quote eq '' && ($i == 0 || substr($line, $i - 1, 1) =~ /[\s;|&()]/)) {
107
+ last;
108
+ }
109
+ if ($char eq '$' && substr($line, $i + 1, 1) eq '(') {
110
+ push @frames, { depth => 1, quote => $quote };
111
+ $quote = '';
112
+ $i++;
113
+ next;
114
+ }
115
+ if (@frames && $quote eq '' && $char eq '(') {
116
+ $frames[-1]{depth}++;
117
+ next;
118
+ }
119
+ if (@frames && $quote eq '' && $char eq ')') {
120
+ $frames[-1]{depth}--;
121
+ if ($frames[-1]{depth} == 0) {
122
+ my $frame = pop @frames;
123
+ $quote = $frame->{quote};
124
+ }
125
+ next;
126
+ }
127
+ next unless $quote eq '' && $char eq '<' && substr($line, $i + 1, 1) eq '<';
128
+ if (@frames) {
129
+ print STDERR "$path:$line_number\n";
130
+ exit 1;
131
+ }
132
+
133
+ my $j = $i + 2;
134
+ my $strip_tabs = substr($line, $j, 1) eq '-';
135
+ $j++ if $strip_tabs;
136
+ $j++ while substr($line, $j, 1) =~ /[ \t]/;
137
+ my $delimiter = '';
138
+ my $delimiter_quote = '';
139
+ for (; $j < $length; $j++) {
140
+ my $token = substr($line, $j, 1);
141
+ if ($delimiter_quote) {
142
+ if ($token eq $delimiter_quote) {
143
+ $delimiter_quote = '';
144
+ } elsif ($token eq '\\' && $delimiter_quote eq '"') {
145
+ $j++;
146
+ $delimiter .= substr($line, $j, 1);
147
+ } else {
148
+ $delimiter .= $token;
149
+ }
150
+ next;
151
+ }
152
+ if ($token eq "'" || $token eq '"') {
153
+ $delimiter_quote = $token;
154
+ next;
155
+ }
156
+ if ($token eq '\\') {
157
+ $j++;
158
+ $delimiter .= substr($line, $j, 1);
159
+ next;
160
+ }
161
+ last if $token =~ /[\s;|&()<>]/;
162
+ $delimiter .= $token;
163
+ }
164
+ push @heredocs, { delimiter => $delimiter, strip_tabs => $strip_tabs };
165
+ $i = $j - 1;
166
+ }
167
+ }
168
+
169
+ exit 0;
170
+ PERL
171
+ }
172
+
173
+ test_help_includes_entire_header() {
174
+ local help
175
+ help=$("$ROOT/bin/fm-brief.sh" --help)
176
+ assert_contains "$help" "Refuses to overwrite an existing brief." "fm-brief.sh --help omitted its header terminator"
177
+ pass "fm-brief.sh: --help renders the complete header"
178
+ }
179
+
180
+ # Registry with one project per delivery mode. fm-brief.sh no longer reads it -
181
+ # the ship mode arrives as an explicit flag - so this fixture exists to prove the
182
+ # scaffold ignores the registered posture (test_ship_mode_is_explicit_not_registry).
183
+ write_registry() {
184
+ local home=$1
185
+ mkdir -p "$home/data"
186
+ cat > "$home/data/projects.md" <<'EOF'
187
+ - direct-proj [direct-PR] - fixture for direct-PR mode (added 2026-07-01)
188
+ - local-proj [local-only] - fixture for local-only mode (added 2026-07-01)
189
+ EOF
190
+ }
191
+
192
+ # fm-brief.sh must exit 0 and produce a brief with no unreplaced shell
193
+ # metacharacter corruption for every ship delivery mode. This also guards
194
+ # against any *new* unescaped apostrophe or unbalanced quote later added to
195
+ # one of these DOD blocks, since a broken heredoc corrupts or empties the
196
+ # generated brief content, not just the script's own syntax.
197
+ test_ship_modes_generate_clean_briefs() {
198
+ local home id mode brief status
199
+ home="$TMP_ROOT/ship-home"
200
+ write_registry "$home"
201
+
202
+ for id_mode in "brief-nomistakes-a1:no-mistakes" "brief-directpr-a2:direct-PR" "brief-localonly-a3:local-only"; do
203
+ id=${id_mode%%:*}
204
+ mode=${id_mode##*:}
205
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" some-proj --mode "$mode" >/dev/null 2>&1; status=$?
206
+ expect_code 0 "$status" "fm-brief.sh $id --mode $mode should exit 0"
207
+ brief="$home/data/$id/brief.md"
208
+ assert_present "$brief" "$id: brief was not scaffolded"
209
+ assert_grep "# Definition of done" "$brief" "$id: brief missing Definition of done section"
210
+ grep -qx "Delivery contract: mode=$mode" "$brief" \
211
+ || fail "$id: brief did not record its machine-readable delivery contract line"
212
+ assert_grep "{TASK}" "$brief" "$id: brief missing the {TASK} placeholder"
213
+ assert_grep "mid-task \`working:\` line (including setup complete) is nonterminal" "$brief" \
214
+ "$id: brief missing nonterminal working:/setup-complete gate protection"
215
+ assert_no_grep "EOF" "$brief" "$id: brief leaked a heredoc EOF marker (unterminated heredoc)"
216
+ done
217
+ pass "fm-brief.sh: no-mistakes/direct-PR/local-only briefs generate cleanly"
218
+ }
219
+
220
+ # A ship task's delivery mode is firstmate's per-task decision, so a missing or
221
+ # unusable value must stop the scaffold instead of silently defaulting. The
222
+ # no-mistakes-prod-only row is the conditional registry policy: it is never a task
223
+ # mode, and its refusal must say to classify the task's surface first.
224
+ test_ship_mode_is_required_and_closed_set() {
225
+ local home id out status label flag expect
226
+ home="$TMP_ROOT/mode-required-home"
227
+ mkdir -p "$home/data"
228
+ id=0
229
+ while IFS='|' read -r label flag expect; do
230
+ [ -n "$label" ] || continue
231
+ id=$((id + 1))
232
+ # shellcheck disable=SC2086 # flag is an intentional word-split arg list (may be empty)
233
+ out=$(FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "brief-required-$id" some-proj $flag 2>&1)
234
+ status=$?
235
+ [ "$status" -ne 0 ] || fail "$label: expected a non-zero exit"
236
+ assert_contains "$out" "$expect" "$label: refusal did not explain the contract"
237
+ assert_absent "$home/data/brief-required-$id/brief.md" "$label: refused scaffold still wrote a brief"
238
+ done <<'ROWS'
239
+ missing --mode||ship briefs require --mode
240
+ empty --mode value|--mode|requires a value
241
+ unknown mode value|--mode nope|must be one of no-mistakes, direct-PR, local-only
242
+ conditional policy is not a task mode|--mode no-mistakes-prod-only|classify this task's surface
243
+ ROWS
244
+ pass "fm-brief.sh: ship --mode is required and closed-set validated"
245
+ }
246
+
247
+ # The registry is the captain's standing posture, not this task's answer: the
248
+ # scaffold must follow the explicit flag even when the project is registered
249
+ # with a different mode, and must not consult the registry at all.
250
+ test_ship_mode_is_explicit_not_registry() {
251
+ local home brief
252
+ home="$TMP_ROOT/explicit-over-registry-home"
253
+ write_registry "$home"
254
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" brief-explicit-a5 direct-proj --mode no-mistakes >/dev/null 2>&1 \
255
+ || fail "explicit no-mistakes brief on a direct-PR project should scaffold"
256
+ brief="$home/data/brief-explicit-a5/brief.md"
257
+ grep -qx "Delivery contract: mode=no-mistakes" "$brief" \
258
+ || fail "registered direct-PR posture overrode the explicit --mode"
259
+ assert_grep "Firstmate will then instruct you to run /no-mistakes" "$brief" \
260
+ "explicit no-mistakes brief did not render the pipeline definition of done"
261
+
262
+ # An unregistered project is not a blocker either, because nothing is looked up.
263
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" brief-explicit-a6 never-registered --mode local-only >/dev/null 2>&1 \
264
+ || fail "unregistered project should still scaffold from the explicit mode"
265
+ grep -qx "Delivery contract: mode=local-only" "$home/data/brief-explicit-a6/brief.md" \
266
+ || fail "unregistered project did not honour the explicit --mode"
267
+ pass "fm-brief.sh: the explicit ship mode wins over the registered posture"
268
+ }
269
+
270
+ # yolo is firstmate's merge authority and never reaches the worker, and a scout
271
+ # or charter carries no delivery contract. Each must refuse rather than accept and
272
+ # discard the flag, which would look recorded but change nothing.
273
+ test_delivery_flags_are_refused_where_they_do_not_apply() {
274
+ local home out status label args expect
275
+ home="$TMP_ROOT/refused-flags-home"
276
+ mkdir -p "$home/data"
277
+ while IFS='|' read -r label args expect; do
278
+ [ -n "$label" ] || continue
279
+ # shellcheck disable=SC2086 # args is an intentional word-split arg list
280
+ out=$(FM_HOME="$home" "$ROOT/bin/fm-brief.sh" $args 2>&1)
281
+ status=$?
282
+ [ "$status" -ne 0 ] || fail "$label: expected a non-zero exit"
283
+ assert_contains "$out" "$expect" "$label: refusal did not explain why"
284
+ done <<'ROWS'
285
+ yolo on a ship brief|brief-refused-b1 some-proj --mode direct-PR --yolo on|--yolo is not a brief input
286
+ yolo=value form on a ship brief|brief-refused-b2 some-proj --mode direct-PR --yolo=off|--yolo is not a brief input
287
+ mode on a scout brief|brief-refused-b3 some-proj --scout --mode direct-PR|--mode applies only to ship briefs
288
+ mode on a secondmate charter|brief-refused-b4 --secondmate --no-projects --mode no-mistakes|--mode applies only to ship briefs
289
+ ROWS
290
+ pass "fm-brief.sh: --yolo and scout/secondmate --mode are refused, never silently dropped"
291
+ }
292
+
293
+ test_faster_paths_use_configured_authority_without_stacked_review() {
294
+ local home id brief
295
+ home="$TMP_ROOT/configured-authority-home"
296
+ write_registry "$home"
297
+ id="brief-direct-authority-a4"
298
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" direct-proj --mode direct-PR >/dev/null 2>&1
299
+ brief="$home/data/$id/brief.md"
300
+ assert_grep "The configured merge authority decides whether to merge the PR; firstmate relays the outcome." "$brief" \
301
+ "direct-PR brief lost configured merge authority"
302
+ assert_no_grep "The captain reviews and merges the PR" "$brief" \
303
+ "direct-PR brief hard-coded captain-only authority"
304
+ id="brief-local-authority-a4"
305
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" local-proj --mode local-only >/dev/null 2>&1
306
+ brief="$home/data/$id/brief.md"
307
+ assert_grep "The configured merge authority approves the ready branch, then firstmate merges it into local \`main\` through the guarded fast-forward path." "$brief" \
308
+ "local-only brief lost configured merge authority and guarded landing"
309
+ assert_no_grep "The captain approves the ready branch" "$brief" \
310
+ "local-only brief hard-coded captain-only authority"
311
+ assert_no_grep "Firstmate then reviews your branch diff" "$brief" \
312
+ "local-only brief retained a personal review stacked on the selected delivery path"
313
+ assert_no_grep "make \`--intent\` preserve all relevant content from this brief" "$home/data/$id/brief.md" \
314
+ "local-only brief must not include the no-mistakes --intent contract"
315
+ id="brief-direct-intent-a4"
316
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" direct-proj --mode direct-PR >/dev/null 2>&1
317
+ assert_no_grep "make \`--intent\` preserve all relevant content from this brief" "$home/data/$id/brief.md" \
318
+ "direct-PR brief must not include the no-mistakes --intent contract"
319
+ pass "fm-brief.sh: faster paths use configured authority without stacked review"
320
+ }
321
+
322
+ # Pin the specific line the bug lived on: the no-mistakes DOD's no-mistakes
323
+ # reference must render as plain prose with no dangling apostrophe artifact.
324
+ test_no_mistakes_dod_wording() {
325
+ local home id brief
326
+ home="$TMP_ROOT/wording-home"
327
+ mkdir -p "$home/data"
328
+ id="brief-wording-b1"
329
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" some-proj --mode no-mistakes >/dev/null 2>&1
330
+ brief="$home/data/$id/brief.md"
331
+ assert_present "$brief" "brief was not scaffolded"
332
+ assert_grep "no-mistakes itself provides for the mechanics" "$brief" \
333
+ "no-mistakes DOD lost its guidance-reference sentence"
334
+ # shellcheck disable=SC2016 # single quotes are deliberate: the backticks must stay literal
335
+ assert_grep '`no-mistakes axi run --help`' "$brief" \
336
+ "no-mistakes DOD must render literal backticks around the help command"
337
+ # shellcheck disable=SC2016 # single quotes are deliberate: the backticks must stay literal
338
+ assert_grep '`help`' "$brief" \
339
+ "no-mistakes DOD must render literal backticks around help"
340
+ assert_grep "make \`--intent\` preserve all relevant content from this brief" "$brief" \
341
+ "no-mistakes DOD must require --intent to retain the accepted task contract"
342
+ assert_grep "carrying only each requirement's current accepted form" "$brief" \
343
+ "no-mistakes DOD must replace superseded requirements with their current accepted form"
344
+ assert_grep "retain direct requirements instead of substituting a diff summary" "$brief" \
345
+ "no-mistakes DOD must keep direct requirements and exclude generic scaffold boilerplate from --intent"
346
+ assert_grep "exclude generic operational, status, delivery, and other scaffold boilerplate unless it is task-specific" "$brief" \
347
+ "no-mistakes DOD must exclude non-task-specific scaffold boilerplate from --intent"
348
+ # Apostrophe prose in the DOD is structurally safe (no `$(...)` wrapper around
349
+ # the heredoc), so it renders verbatim instead of being reworded or escaped
350
+ # away. test_no_heredoc_in_command_substitution guards the structure that makes
351
+ # it safe.
352
+ assert_grep "carrying only each requirement's current accepted form" "$brief" \
353
+ "no-mistakes DOD lost the apostrophe prose that the structural fix makes parse-safe"
354
+
355
+ # The --yes ban is a fleet-wide prohibition, not a preference, and it must not
356
+ # claim an enforcement the tool does not provide: this is instruction only.
357
+ assert_grep "NEVER pass \`--yes\` (or \`-y\`) to \`no-mistakes axi run\` or \`no-mistakes axi respond\`. It is banned fleet-wide." "$brief" \
358
+ "no-mistakes DOD must state the --yes ban as a prohibition"
359
+ assert_grep "answering your own ask-user finding is a hard rule violation" "$brief" \
360
+ "no-mistakes DOD must say why --yes is banned"
361
+ assert_no_grep "Avoid \`--yes\`" "$brief" \
362
+ "no-mistakes DOD still states the --yes ban as a preference"
363
+ assert_no_grep "no-mistakes refuses" "$brief" \
364
+ "no-mistakes DOD must not claim the tool itself refuses --yes"
365
+ pass "fm-brief.sh: no-mistakes DOD keeps its apostrophe prose and bans --yes outright"
366
+ }
367
+
368
+ test_ship_project_memory_wording() {
369
+ local home id brief
370
+ home="$TMP_ROOT/project-memory-home"
371
+ mkdir -p "$home/data"
372
+ id="brief-memory-c1"
373
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" some-proj --mode no-mistakes >/dev/null 2>&1
374
+ brief="$home/data/$id/brief.md"
375
+ assert_present "$brief" "brief was not scaffolded"
376
+ assert_grep "Record only project knowledge useful to almost every future session." "$brief" \
377
+ "project-memory contract lost the durable-knowledge bar"
378
+ assert_grep "prefer a pointer to the authoritative file, command, or doc over copying the detail" "$brief" \
379
+ "project-memory contract lost pointer-over-copy guidance"
380
+ assert_grep "lacks \`## Maintaining this file\`, add that short self-governance section" "$brief" \
381
+ "project-memory contract lost the self-governance add-in-same-pass rule"
382
+ pass "fm-brief.sh: ship project-memory wording carries the AGENTS.md authoring bar"
383
+ }
384
+
385
+ test_herdr_lab_contract_is_explicit_and_complete() {
386
+ local home id brief
387
+ home="$TMP_ROOT/herdr-lab-home"
388
+ mkdir -p "$home/data"
389
+ id="brief-herdr-lab-d1"
390
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" firstmate --mode no-mistakes --herdr-lab >/dev/null 2>&1
391
+ brief="$home/data/$id/brief.md"
392
+ assert_present "$brief" "Herdr lab brief was not scaffolded"
393
+ assert_grep "# Herdr isolation - HARD SAFETY CONTRACT" "$brief" \
394
+ "Herdr lab brief missing its hard safety contract"
395
+ assert_grep "HERDR_LAB_HELPER='$ROOT/bin/fm-herdr-lab.sh'" "$brief" \
396
+ "Herdr lab brief must bind the absolute Firstmate helper path"
397
+ assert_grep "HERDR_LAB_SESSION=\$(\"\$HERDR_LAB_HELPER\" name $id)" "$brief" \
398
+ "Herdr lab brief missing helper-owned session naming"
399
+ assert_grep "\"\$HERDR_LAB_HELPER\" provision \"\$HERDR_LAB_SESSION\"" "$brief" \
400
+ "Herdr lab brief missing helper-owned provisioning"
401
+ assert_grep "\"\$HERDR_LAB_HELPER\" teardown \"\$HERDR_LAB_SESSION\"" "$brief" \
402
+ "Herdr lab brief missing helper-owned teardown"
403
+ assert_grep "required trailing \`--session \"\$HERDR_LAB_SESSION\"\`" "$brief" \
404
+ "Herdr lab brief missing the per-call trailing session contract"
405
+ assert_grep "direct \`herdr server stop\`" "$brief" \
406
+ "Herdr lab brief missing the forbidden server-global command list"
407
+ assert_grep "records the live default session before provisioning" "$brief" \
408
+ "Herdr lab brief missing the before tripwire"
409
+ assert_grep "verifies the identical fleet state after teardown" "$brief" \
410
+ "Herdr lab brief missing the after tripwire"
411
+ assert_no_grep "Herdr lifecycle declaration - NOT ENABLED" "$brief" \
412
+ "Herdr lab brief retained the unguarded declaration"
413
+ pass "fm-brief.sh: --herdr-lab emits the complete hard safety contract"
414
+ }
415
+
416
+ test_herdr_lab_contract_quotes_foreign_firstmate_path() {
417
+ local home id brief foreign_root helper
418
+ home="$TMP_ROOT/herdr-lab-foreign-home"
419
+ foreign_root="$TMP_ROOT/firstmate helper's root"
420
+ mkdir -p "$home/data"
421
+ id="brief-herdr-lab-foreign-d2"
422
+ helper=$(printf '%s' "$foreign_root/bin/fm-herdr-lab.sh" | sed "s/'/'\\\\''/g")
423
+ helper="'$helper'"
424
+ FM_HOME="$home" FM_ROOT_OVERRIDE="$foreign_root" "$ROOT/bin/fm-brief.sh" "$id" foreign --scout --herdr-lab >/dev/null 2>&1
425
+ brief="$home/data/$id/brief.md"
426
+ assert_grep "HERDR_LAB_HELPER=$helper" "$brief" \
427
+ "Herdr lab brief must shell-quote an absolute Firstmate helper path"
428
+ assert_no_grep "bin/fm-herdr-lab.sh name $id" "$brief" \
429
+ "Herdr lab brief must not invoke a worktree-relative helper"
430
+ pass "fm-brief.sh: --herdr-lab uses its quoted Firstmate-owned helper path"
431
+ }
432
+
433
+ test_herdr_lab_omission_is_loud_for_ship_and_scout() {
434
+ local home id brief
435
+ home="$TMP_ROOT/herdr-gate-home"
436
+ mkdir -p "$home/data"
437
+ for kind in ship scout; do
438
+ id="brief-herdr-gate-$kind"
439
+ if [ "$kind" = scout ]; then
440
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" firstmate --scout >/dev/null 2>&1
441
+ else
442
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" firstmate --mode no-mistakes >/dev/null 2>&1
443
+ fi
444
+ brief="$home/data/$id/brief.md"
445
+ assert_grep "# Herdr lifecycle declaration - NOT ENABLED" "$brief" \
446
+ "$kind brief silently omitted the Herdr declaration"
447
+ assert_grep "regenerate the brief with \`--herdr-lab\` before dispatch" "$brief" \
448
+ "$kind brief missing the fail-visible regeneration instruction"
449
+ done
450
+ pass "fm-brief.sh: ship and scout scaffolds make omitted Herdr intent fail-visible"
451
+ }
452
+
453
+ # Regression (issue #2575): AGENTS.md section 11 and this script's own help tell
454
+ # firstmate to replace EVERY `{TASK}` placeholder. The unguarded Herdr gate used
455
+ # to quote `{TASK}` in its own prose, so that documented global replace spliced
456
+ # the whole task body into the middle of the gate's sentence - silently
457
+ # destroying the one contract that exists precisely because the scaffold cannot
458
+ # see the task text. The placeholder must exist only at the genuine fill site,
459
+ # so the documented fill leaves the gate intact and the body appears once.
460
+ test_documented_global_replace_leaves_the_herdr_gate_intact() {
461
+ local home id brief kind count content filled body
462
+ home="$TMP_ROOT/task-fill-site-home"
463
+ mkdir -p "$home/data"
464
+ body='Restart the herdr session, then profile it'
465
+ for kind in ship scout; do
466
+ id="brief-fill-site-$kind"
467
+ if [ "$kind" = scout ]; then
468
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" firstmate --scout >/dev/null 2>&1
469
+ else
470
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" firstmate --mode no-mistakes >/dev/null 2>&1
471
+ fi
472
+ brief="$home/data/$id/brief.md"
473
+ assert_present "$brief" "$kind brief was not scaffolded"
474
+ count=$(grep -c -F '{TASK}' "$brief")
475
+ [ "$count" = 1 ] \
476
+ || fail "$kind brief must carry exactly one {TASK} fill site, found $count"
477
+ content=$(cat "$brief")
478
+ filled=${content//'{TASK}'/$body}
479
+ count=$(printf '%s\n' "$filled" | grep -c -F "$body")
480
+ [ "$count" = 1 ] \
481
+ || fail "$kind brief: the documented global {TASK} replace duplicated the task body $count times"
482
+ printf '%s\n' "$filled" | grep -qF 'this scaffold cannot inspect the task text' \
483
+ || fail "$kind brief: the Herdr safety gate did not survive the documented global replace"
484
+ done
485
+ pass "fm-brief.sh: the documented {TASK} fill cannot corrupt the Herdr safety gate"
486
+ }
487
+
488
+ test_secondmate_no_projects_charter() {
489
+ local home brief status
490
+ home="$TMP_ROOT/no-projects-home"
491
+ mkdir -p "$home/data"
492
+
493
+ # The deliberate --no-projects signal scaffolds a valid project-less charter for
494
+ # a domain whose subject is the firstmate repo itself (no clones needed).
495
+ FM_HOME="$home" FM_SECONDMATE_CHARTER='firstmate self-development' \
496
+ FM_SECONDMATE_SCOPE='firstmate repo work' \
497
+ "$ROOT/bin/fm-brief.sh" fdev --secondmate --no-projects >/dev/null 2>&1; status=$?
498
+ expect_code 0 "$status" "--no-projects secondmate brief should exit 0"
499
+ brief="$home/data/fdev/brief.md"
500
+ assert_present "$brief" "project-less charter was not scaffolded"
501
+ assert_grep "# Project clones" "$brief" "project-less charter dropped the Project clones heading"
502
+ assert_grep "None. This is a project-less domain" "$brief" \
503
+ "project-less charter did not render a sensible no-clones note"
504
+ assert_grep "its crews take pooled worktrees of that repo" "$brief" \
505
+ "project-less charter operating model lost the pooled-worktree note"
506
+ assert_no_grep "The projects above are local clones" "$brief" \
507
+ "project-less charter kept the with-projects operating-model line"
508
+ assert_grep 'working [key=<work-slug>]' "$brief" \
509
+ "secondmate charter did not key material routed-work phases"
510
+ assert_grep 'resolved [key=<work-slug>]' "$brief" \
511
+ "secondmate charter did not close a quietly ended routed-work phase"
512
+ assert_grep 'use the same key on its later' "$brief" \
513
+ "secondmate charter did not supersede working phases with later states"
514
+ if grep -nE '^-[[:space:]]*$' "$brief" >/dev/null; then
515
+ fail "project-less charter left a stray empty project bullet"
516
+ fi
517
+
518
+ # Accidental omission (no projects, no signal) still fails loudly, writing nothing.
519
+ FM_HOME="$home" FM_SECONDMATE_CHARTER='x' "$ROOT/bin/fm-brief.sh" oops --secondmate >/dev/null 2>&1; status=$?
520
+ expect_code 1 "$status" "secondmate brief with no projects and no --no-projects must fail"
521
+ assert_absent "$home/data/oops/brief.md" "loud-failure secondmate brief still wrote a file"
522
+
523
+ # --no-projects is mutually exclusive with a project list.
524
+ FM_HOME="$home" FM_SECONDMATE_CHARTER='x' "$ROOT/bin/fm-brief.sh" oops2 --secondmate --no-projects alpha >/dev/null 2>&1; status=$?
525
+ expect_code 1 "$status" "--no-projects combined with a project list must fail"
526
+
527
+ # --no-projects applies only to secondmate charters, never a ship/scout brief.
528
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" oops3 somerepo --no-projects >/dev/null 2>&1; status=$?
529
+ expect_code 1 "$status" "--no-projects on a ship brief must fail"
530
+
531
+ pass "fm-brief.sh: --no-projects scaffolds a project-less charter and guards misuse"
532
+ }
533
+
534
+ test_secondmate_marked_request_reporting_contract() {
535
+ local home brief
536
+ home="$TMP_ROOT/marked-request-reporting-home"
537
+ mkdir -p "$home/data"
538
+ FM_HOME="$home" FM_CLASSIFY_PAUSED_VERB=paused \
539
+ FM_SECONDMATE_CHARTER='Handle routed domain work.' \
540
+ "$ROOT/bin/fm-brief.sh" marked-request-reporting --secondmate --no-projects >/dev/null 2>&1
541
+ brief="$home/data/marked-request-reporting/brief.md"
542
+
543
+ assert_grep 'A marked request requires one correlated answer after the work' "$brief" \
544
+ "secondmate charter did not require the correlated answer after the work"
545
+ assert_grep 'does not require a separate receipt or start acknowledgement' "$brief" \
546
+ "secondmate charter did not reject a separate receipt/start acknowledgement"
547
+ assert_grep "Never append \`working:\` merely to acknowledge receipt or announce that a marked request has started." "$brief" \
548
+ "secondmate charter did not forbid a generic working acknowledgement"
549
+ assert_no_grep "Give every routed-work phase a stable key: open it with \`working" "$brief" \
550
+ "secondmate charter retained the unconditional working opener"
551
+ assert_grep 'When a routed-work phase has a supervisor-actionable material change worth reporting under the rule above' "$brief" \
552
+ "secondmate charter did not limit keyed phases to reportable material changes"
553
+ assert_grep "If its first reportable event is \`working [key=<work-slug>]: {material phase}\`" "$brief" \
554
+ "secondmate charter lost keyed working syntax for a reportable material phase"
555
+ assert_grep "use the same key on its later \`paused\`, \`done\`, \`failed\`, \`needs-decision\`, or \`blocked\` event" "$brief" \
556
+ "secondmate charter lost same-key closure for a reportable material phase"
557
+ assert_grep 'resolved [key=<work-slug>]' "$brief" \
558
+ "secondmate charter lost resolved closure for a keyed material phase"
559
+
560
+ assert_grep 'include that exact token in your parent status reply' "$brief" \
561
+ "secondmate charter lost correlated parent results"
562
+ assert_grep 'For a terse result, a status line is the whole answer.' "$brief" \
563
+ "secondmate charter lost terse result reporting"
564
+ assert_grep 'append a status line that points to that doc' "$brief" \
565
+ "secondmate charter lost detailed document pointers"
566
+ assert_grep 'Report only true captain-relevant outcomes or a declared external wait' "$brief" \
567
+ "secondmate charter lost declared external waits"
568
+ assert_grep 'a captain decision, a real blocker, a failure, work ready for review, or work you landed' "$brief" \
569
+ "secondmate charter lost decisions, blockers, failures, ready outcomes, or landed work"
570
+ # Under standing merge authority nothing is ever "ready for review", so the
571
+ # landed merge is the trigger a charter without this line silently omits.
572
+ assert_grep 'a merge you performed yourself under standing merge authority and one the captain merged on the forge' "$brief" \
573
+ "secondmate charter did not name a landed merge as a reporting trigger"
574
+ assert_grep 'States: working, needs-decision, blocked, paused, done, failed.' "$brief" \
575
+ "secondmate charter changed the preserved status vocabulary"
576
+ pass "fm-brief.sh: marked requests avoid generic acknowledgements and preserve material reporting"
577
+ }
578
+
579
+ test_secondmate_directory_paths_are_absolute_and_output_is_stable() {
580
+ local root home data_override state_override brief baseline err status
581
+ root="$TMP_ROOT/relative-directory-inputs"
582
+ mkdir -p "$root"
583
+ root=$(cd "$root" && pwd -P)
584
+ home="$root/home"
585
+ data_override="$root/data-override"
586
+ state_override="$root/state-override"
587
+ mkdir -p "$home/data" "$home/state" "$data_override" "$state_override" \
588
+ "$root/cdpath/home/data" "$root/cdpath/home/state" \
589
+ "$root/cdpath/data-override" "$root/cdpath/state-override"
590
+
591
+ brief="$home/data/relative-home/brief.md"
592
+ FM_HOME="$home" FM_SECONDMATE_CHARTER=x \
593
+ "$ROOT/bin/fm-brief.sh" relative-home --secondmate --no-projects >/dev/null 2>&1
594
+ baseline="$root/absolute-home-charter"
595
+ cp "$brief" "$baseline"
596
+ rm -f "$brief"
597
+ (
598
+ cd "$root" || exit 1
599
+ CDPATH="$root/cdpath" FM_HOME=home FM_SECONDMATE_CHARTER=x \
600
+ "$ROOT/bin/fm-brief.sh" relative-home --secondmate --no-projects >/dev/null 2>&1
601
+ )
602
+ cmp -s "$baseline" "$brief" \
603
+ || fail "relative FM_HOME changed charter bytes compared with the same absolute home"
604
+ assert_grep ">> '$home/state/relative-home.status'" "$brief" \
605
+ "relative FM_HOME did not render an absolute secondmate status path"
606
+
607
+ brief="$home/data/relative-state/brief.md"
608
+ FM_HOME="$home" FM_STATE_OVERRIDE="$state_override" FM_SECONDMATE_CHARTER=x \
609
+ "$ROOT/bin/fm-brief.sh" relative-state --secondmate --no-projects >/dev/null 2>&1
610
+ baseline="$root/absolute-state-charter"
611
+ cp "$brief" "$baseline"
612
+ rm -f "$brief"
613
+ (
614
+ cd "$root" || exit 1
615
+ CDPATH="$root/cdpath" FM_HOME="$home" FM_STATE_OVERRIDE=state-override FM_SECONDMATE_CHARTER=x \
616
+ "$ROOT/bin/fm-brief.sh" relative-state --secondmate --no-projects >/dev/null 2>&1
617
+ )
618
+ cmp -s "$baseline" "$brief" \
619
+ || fail "relative FM_STATE_OVERRIDE changed charter bytes compared with the same absolute state directory"
620
+ assert_grep ">> '$state_override/relative-state.status'" "$brief" \
621
+ "relative FM_STATE_OVERRIDE did not render an absolute secondmate status path"
622
+
623
+ brief="$data_override/relative-data/brief.md"
624
+ FM_HOME="$home" FM_DATA_OVERRIDE="$data_override" FM_SECONDMATE_CHARTER=x \
625
+ "$ROOT/bin/fm-brief.sh" relative-data --secondmate --no-projects >/dev/null 2>&1
626
+ baseline="$root/absolute-data-charter"
627
+ cp "$brief" "$baseline"
628
+ rm -f "$brief"
629
+ (
630
+ cd "$root" || exit 1
631
+ CDPATH="$root/cdpath" FM_HOME="$home" FM_DATA_OVERRIDE=data-override FM_SECONDMATE_CHARTER=x \
632
+ "$ROOT/bin/fm-brief.sh" relative-data --secondmate --no-projects >/dev/null 2>&1
633
+ )
634
+ cmp -s "$baseline" "$brief" \
635
+ || fail "relative FM_DATA_OVERRIDE changed charter bytes compared with the same absolute data directory"
636
+ assert_grep ">> '$home/state/relative-data.status'" "$brief" \
637
+ "relative FM_DATA_OVERRIDE changed the absolute default status path"
638
+
639
+ err="$root/unresolved.err"
640
+ (
641
+ cd "$root" || exit 1
642
+ FM_HOME=missing-home FM_SECONDMATE_CHARTER=x \
643
+ "$ROOT/bin/fm-brief.sh" unresolved-home --secondmate --no-projects >/dev/null 2>"$err"
644
+ ); status=$?
645
+ expect_code 1 "$status" "an unresolved relative FM_HOME must fail"
646
+ assert_grep "FM_HOME directory cannot be resolved: missing-home" "$err" \
647
+ "unresolved relative FM_HOME did not fail loudly"
648
+
649
+ (
650
+ cd "$root" || exit 1
651
+ FM_HOME="$home" FM_STATE_OVERRIDE=missing-state FM_SECONDMATE_CHARTER=x \
652
+ "$ROOT/bin/fm-brief.sh" unresolved-state --secondmate --no-projects >/dev/null 2>"$err"
653
+ ); status=$?
654
+ expect_code 1 "$status" "an unresolved relative FM_STATE_OVERRIDE must fail"
655
+ assert_grep "FM_STATE_OVERRIDE directory cannot be resolved: missing-state" "$err" \
656
+ "unresolved relative FM_STATE_OVERRIDE did not fail loudly"
657
+
658
+ (
659
+ cd "$root" || exit 1
660
+ FM_HOME="$home" FM_DATA_OVERRIDE=missing-data FM_SECONDMATE_CHARTER=x \
661
+ "$ROOT/bin/fm-brief.sh" unresolved-data --secondmate --no-projects >/dev/null 2>"$err"
662
+ ); status=$?
663
+ expect_code 1 "$status" "an unresolved relative FM_DATA_OVERRIDE must fail"
664
+ assert_grep "FM_DATA_OVERRIDE directory cannot be resolved: missing-data" "$err" \
665
+ "unresolved relative FM_DATA_OVERRIDE did not fail loudly"
666
+
667
+ pass "fm-brief.sh: relative directory inputs ignore CDPATH, render stable absolute charter paths, or fail loudly"
668
+ }
669
+
670
+ test_herdr_lab_contract_applies_to_scouts_but_not_secondmates() {
671
+ local home brief status=0
672
+ home="$TMP_ROOT/herdr-kind-home"
673
+ mkdir -p "$home/data"
674
+ FM_HOME="$home" "$ROOT/bin/fm-brief.sh" herdr-scout firstmate --scout --herdr-lab >/dev/null 2>&1
675
+ brief="$home/data/herdr-scout/brief.md"
676
+ assert_grep "# Herdr isolation - HARD SAFETY CONTRACT" "$brief" \
677
+ "scout --herdr-lab brief missing the contract"
678
+
679
+ FM_HOME="$home" FM_SECONDMATE_CHARTER=ops "$ROOT/bin/fm-brief.sh" herdr-secondmate --secondmate firstmate --herdr-lab >/dev/null 2>&1 || status=$?
680
+ expect_code 1 "$status" "secondmate --herdr-lab must be rejected"
681
+ assert_absent "$home/data/herdr-secondmate/brief.md" \
682
+ "rejected secondmate --herdr-lab still wrote a brief"
683
+ pass "fm-brief.sh: Herdr lab contract covers scouts and rejects secondmate misuse"
684
+ }
685
+
686
+ test_pause_verb_override_renders_all_brief_scaffolds() {
687
+ local home kind id brief
688
+ home="$TMP_ROOT/pause-verb-home"
689
+ mkdir -p "$home/data"
690
+
691
+ for kind in ship scout secondmate; do
692
+ id="brief-pause-verb-$kind"
693
+ case "$kind" in
694
+ ship)
695
+ FM_HOME="$home" FM_CLASSIFY_PAUSED_VERB=awaiting \
696
+ "$ROOT/bin/fm-brief.sh" "$id" firstmate --mode no-mistakes >/dev/null 2>&1
697
+ ;;
698
+ scout)
699
+ FM_HOME="$home" FM_CLASSIFY_PAUSED_VERB=awaiting \
700
+ "$ROOT/bin/fm-brief.sh" "$id" firstmate --scout >/dev/null 2>&1
701
+ ;;
702
+ secondmate)
703
+ FM_HOME="$home" FM_CLASSIFY_PAUSED_VERB=awaiting \
704
+ "$ROOT/bin/fm-brief.sh" "$id" --secondmate --no-projects >/dev/null 2>&1
705
+ ;;
706
+ esac
707
+ brief="$home/data/$id/brief.md"
708
+ assert_grep "States: working, needs-decision, blocked, awaiting, done, failed." "$brief" \
709
+ "$kind brief did not render the configured pause verb in its states list"
710
+ # shellcheck disable=SC2016 # Literal backticks and braces must remain unexpanded.
711
+ assert_grep 'Use `awaiting: {why}`' "$brief" \
712
+ "$kind brief did not instruct the configured pause status"
713
+ # shellcheck disable=SC2016 # Literal backticks and braces must remain unexpanded.
714
+ assert_no_grep '`paused: {why}`' "$brief" \
715
+ "$kind brief still instructs the default paused status"
716
+ assert_grep 'a blocker or wait clears' "$brief" \
717
+ "$kind brief did not require durable resolution when a blocker clears"
718
+ assert_grep 'even when the answer is what started that work' "$brief" \
719
+ "$kind brief did not warn that an answer-started done/working never closes a decision"
720
+ done
721
+ pass "fm-brief.sh: custom pause verb renders in every scaffold"
722
+ }
723
+
724
+ test_scout_and_secondmate_load_decision_hold_policy() {
725
+ local home scout charter
726
+ home="$TMP_ROOT/decision-policy-home"
727
+ mkdir -p "$home/data"
728
+ FM_HOME="$home" FM_ROOT_OVERRIDE="$ROOT" \
729
+ "$ROOT/bin/fm-brief.sh" sample-investigation sample --scout >/dev/null 2>&1
730
+ scout="$home/data/sample-investigation/brief.md"
731
+ assert_grep "$ROOT/.agents/skills/captain-hold-lifecycle/SKILL.md" "$scout" \
732
+ "scout brief did not load the captain-call policy before done"
733
+ assert_grep "pass its shared completion gate for the report and any visual review" "$scout" \
734
+ "scout brief did not cross-reference visual-review completion"
735
+ FM_HOME="$home" FM_ROOT_OVERRIDE="$ROOT" FM_SECONDMATE_CHARTER='sample reviews' \
736
+ "$ROOT/bin/fm-brief.sh" sample-mate --secondmate --no-projects >/dev/null 2>&1
737
+ charter="$home/data/sample-mate/brief.md"
738
+ assert_grep "load \`captain-hold-lifecycle\`" "$charter" \
739
+ "secondmate charter did not load the shared captain-call policy for detailed investigations"
740
+ pass "fm-brief.sh: investigation and visual-review completions load the shared decision policy"
741
+ }
742
+
743
+ # Scout and secondmate paths still scaffold well-formed briefs.
744
+ test_scout_and_secondmate_scaffold() {
745
+ local brief
746
+ FM_HOME="$BRIEF_HOME" "$ROOT/bin/fm-brief.sh" brief-scout-q6 alpha --scout >/dev/null 2>&1 \
747
+ || fail "fm-brief.sh scout scaffold exited non-zero"
748
+ brief="$BRIEF_HOME/data/brief-scout-q6/brief.md"
749
+ assert_present "$brief" "scout brief was not scaffolded"
750
+ assert_grep "SCOUT task" "$brief" "scout brief must declare itself a scout task"
751
+ assert_grep "report.md" "$brief" "scout brief must point at the report deliverable"
752
+ assert_grep "you may host the Lavish review loop yourself" "$brief" \
753
+ "scout brief must mention the option to host a Lavish review loop"
754
+
755
+ FM_SECONDMATE_CHARTER='Supervise the alpha domain.' \
756
+ FM_HOME="$BRIEF_HOME" "$ROOT/bin/fm-brief.sh" brief-sm-q6 --secondmate alpha >/dev/null 2>&1 \
757
+ || fail "fm-brief.sh secondmate scaffold exited non-zero"
758
+ brief="$BRIEF_HOME/data/brief-sm-q6/brief.md"
759
+ assert_present "$brief" "secondmate charter was not scaffolded"
760
+ assert_grep "persistent second mate" "$brief" \
761
+ "secondmate charter must declare its role"
762
+ pass "fm-brief: scout and secondmate code paths still scaffold well-formed briefs"
763
+ }
764
+
765
+ test_script_parses
766
+ test_no_heredoc_in_command_substitution
767
+ test_help_includes_entire_header
768
+ test_ship_modes_generate_clean_briefs
769
+ test_ship_mode_is_required_and_closed_set
770
+ test_ship_mode_is_explicit_not_registry
771
+ test_delivery_flags_are_refused_where_they_do_not_apply
772
+ test_faster_paths_use_configured_authority_without_stacked_review
773
+ test_no_mistakes_dod_wording
774
+ test_ship_project_memory_wording
775
+ test_herdr_lab_contract_is_explicit_and_complete
776
+ test_herdr_lab_contract_quotes_foreign_firstmate_path
777
+ test_herdr_lab_omission_is_loud_for_ship_and_scout
778
+ test_documented_global_replace_leaves_the_herdr_gate_intact
779
+ test_herdr_lab_contract_applies_to_scouts_but_not_secondmates
780
+ test_secondmate_no_projects_charter
781
+ test_secondmate_marked_request_reporting_contract
782
+ test_secondmate_directory_paths_are_absolute_and_output_is_stable
783
+ test_pause_verb_override_renders_all_brief_scaffolds
784
+ test_scout_and_secondmate_load_decision_hold_policy
785
+ test_scout_and_secondmate_scaffold