@zerwiz/ymir 0.1.4 → 0.1.7

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 (865) 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/README.md +74 -0
  27. package/.agents/backend/backends/cmux.sh +649 -0
  28. package/.agents/backend/backends/herdr-eventwait.py +157 -0
  29. package/.agents/backend/backends/herdr-workspace-move.py +114 -0
  30. package/.agents/backend/backends/herdr.sh +3386 -0
  31. package/.agents/backend/backends/orca.sh +290 -0
  32. package/.agents/backend/backends/tmux.sh +357 -0
  33. package/.agents/backend/backends/zellij.sh +700 -0
  34. package/.agents/backend/fm-afk-launch.sh +654 -0
  35. package/.agents/backend/fm-afk-return.sh +241 -0
  36. package/.agents/backend/fm-afk-start.sh +172 -0
  37. package/.agents/backend/fm-arm-command-policy.mjs +960 -0
  38. package/.agents/backend/fm-arm-pretool-check.sh +200 -0
  39. package/.agents/backend/fm-backend-hometag-lib.sh +52 -0
  40. package/.agents/backend/fm-backend.sh +981 -0
  41. package/.agents/backend/fm-backlog-handoff.sh +909 -0
  42. package/.agents/backend/fm-backlog-receive.sh +187 -0
  43. package/.agents/backend/fm-backlog-transition-lib.sh +779 -0
  44. package/.agents/backend/fm-bearings-board.sh +204 -0
  45. package/.agents/backend/fm-bearings-snapshot.sh +546 -0
  46. package/.agents/backend/fm-bootstrap.sh +1568 -0
  47. package/.agents/backend/fm-branch-outcome.sh +203 -0
  48. package/.agents/backend/fm-branch-prompt.sh +101 -0
  49. package/.agents/backend/fm-brief.sh +452 -0
  50. package/.agents/backend/fm-busy-event.sh +234 -0
  51. package/.agents/backend/fm-busy-lib.sh +986 -0
  52. package/.agents/backend/fm-captain-hold.sh +1001 -0
  53. package/.agents/backend/fm-cd-command-policy.mjs +153 -0
  54. package/.agents/backend/fm-cd-pretool-check.sh +190 -0
  55. package/.agents/backend/fm-check-lib.sh +74 -0
  56. package/.agents/backend/fm-check-register.sh +42 -0
  57. package/.agents/backend/fm-check-unregister.sh +52 -0
  58. package/.agents/backend/fm-classify-lib.sh +1770 -0
  59. package/.agents/backend/fm-claude-stop-autoarm.sh +334 -0
  60. package/.agents/backend/fm-composer-lib.sh +1416 -0
  61. package/.agents/backend/fm-config-inherit-lib.sh +1202 -0
  62. package/.agents/backend/fm-config-push.sh +254 -0
  63. package/.agents/backend/fm-control-lib.sh +251 -0
  64. package/.agents/backend/fm-control.sh +878 -0
  65. package/.agents/backend/fm-crew-state.sh +625 -0
  66. package/.agents/backend/fm-cursor-lib.sh +243 -0
  67. package/.agents/backend/fm-decision-hold.sh +232 -0
  68. package/.agents/backend/fm-doc-audience-check.sh +269 -0
  69. package/.agents/backend/fm-dod-lib.sh +67 -0
  70. package/.agents/backend/fm-ensure-agents-md.sh +253 -0
  71. package/.agents/backend/fm-extension-launch-barrier.mjs +129 -0
  72. package/.agents/backend/fm-extension.mjs +2577 -0
  73. package/.agents/backend/fm-extension.sh +16 -0
  74. package/.agents/backend/fm-ff-lib.sh +420 -0
  75. package/.agents/backend/fm-fleet-snapshot.sh +1463 -0
  76. package/.agents/backend/fm-fleet-sync.sh +458 -0
  77. package/.agents/backend/fm-fleet-view.sh +96 -0
  78. package/.agents/backend/fm-gate-refuse-lib.sh +102 -0
  79. package/.agents/backend/fm-guard.sh +242 -0
  80. package/.agents/backend/fm-harness.sh +195 -0
  81. package/.agents/backend/fm-herdr-ci-cleanup.sh +115 -0
  82. package/.agents/backend/fm-herdr-lab.sh +346 -0
  83. package/.agents/backend/fm-herdr-session-cleanup.sh +337 -0
  84. package/.agents/backend/fm-home-seed.sh +984 -0
  85. package/.agents/backend/fm-home-summary-refresh.sh +255 -0
  86. package/.agents/backend/fm-hook-host-lib.sh +36 -0
  87. package/.agents/backend/fm-inactive-reconcile.sh +531 -0
  88. package/.agents/backend/fm-inbox.sh +399 -0
  89. package/.agents/backend/fm-install-actionlint.sh +84 -0
  90. package/.agents/backend/fm-install-herdr.sh +96 -0
  91. package/.agents/backend/fm-install-shellcheck.sh +84 -0
  92. package/.agents/backend/fm-install-treehouse.sh +95 -0
  93. package/.agents/backend/fm-kimi-turnend-hook.sh +276 -0
  94. package/.agents/backend/fm-lease-lib.sh +218 -0
  95. package/.agents/backend/fm-lease.sh +189 -0
  96. package/.agents/backend/fm-line-cap-lib.sh +51 -0
  97. package/.agents/backend/fm-lint-workflows.sh +137 -0
  98. package/.agents/backend/fm-lint.sh +591 -0
  99. package/.agents/backend/fm-lock-lib.sh +104 -0
  100. package/.agents/backend/fm-lock.sh +107 -0
  101. package/.agents/backend/fm-marker-lib.sh +12 -0
  102. package/.agents/backend/fm-merge-local.sh +74 -0
  103. package/.agents/backend/fm-merge-outcome-lib.sh +138 -0
  104. package/.agents/backend/fm-nm-run-lib.sh +124 -0
  105. package/.agents/backend/fm-on.sh +125 -0
  106. package/.agents/backend/fm-operational-input.sh +253 -0
  107. package/.agents/backend/fm-peek.sh +46 -0
  108. package/.agents/backend/fm-pending-reply-lib.sh +1409 -0
  109. package/.agents/backend/fm-pr-check.sh +135 -0
  110. package/.agents/backend/fm-pr-lib.sh +1016 -0
  111. package/.agents/backend/fm-pr-merge.sh +707 -0
  112. package/.agents/backend/fm-pr-poll.sh +110 -0
  113. package/.agents/backend/fm-primary-scope-lib.sh +33 -0
  114. package/.agents/backend/fm-procevent-extension-capture.pl +259 -0
  115. package/.agents/backend/fm-procevent-lavish.sh +628 -0
  116. package/.agents/backend/fm-procevent-lib.sh +892 -0
  117. package/.agents/backend/fm-procevent-quota.sh +290 -0
  118. package/.agents/backend/fm-procevent-remote-reply.sh +577 -0
  119. package/.agents/backend/fm-procevent-when.sh +504 -0
  120. package/.agents/backend/fm-procevent.sh +1466 -0
  121. package/.agents/backend/fm-project-mode.sh +92 -0
  122. package/.agents/backend/fm-project-origin-lib.sh +180 -0
  123. package/.agents/backend/fm-promote.sh +282 -0
  124. package/.agents/backend/fm-public-followup-emit.sh +260 -0
  125. package/.agents/backend/fm-public-followup-lib.sh +398 -0
  126. package/.agents/backend/fm-public-followup.sh +1330 -0
  127. package/.agents/backend/fm-push-transition-lib.sh +168 -0
  128. package/.agents/backend/fm-quota-axi-lib.sh +93 -0
  129. package/.agents/backend/fm-quota-choose.sh +384 -0
  130. package/.agents/backend/fm-remote-delta-read.sh +189 -0
  131. package/.agents/backend/fm-remote-doctor.sh +800 -0
  132. package/.agents/backend/fm-remote-entrypoint.sh +193 -0
  133. package/.agents/backend/fm-remote-file.sh +234 -0
  134. package/.agents/backend/fm-remote-home-provision.sh +259 -0
  135. package/.agents/backend/fm-remote-home-seed.sh +259 -0
  136. package/.agents/backend/fm-remote-inherit-push.sh +90 -0
  137. package/.agents/backend/fm-remote-inherit.sh +179 -0
  138. package/.agents/backend/fm-remote-job-lib.sh +1241 -0
  139. package/.agents/backend/fm-remote-job-reap-orphans.sh +137 -0
  140. package/.agents/backend/fm-remote-job-worker.sh +1124 -0
  141. package/.agents/backend/fm-remote-readiness-lib.sh +44 -0
  142. package/.agents/backend/fm-remote-secondmate-control.sh +340 -0
  143. package/.agents/backend/fm-review-diff.sh +158 -0
  144. package/.agents/backend/fm-secondmate-charter-lib.sh +44 -0
  145. package/.agents/backend/fm-secondmate-nudge-lib.sh +68 -0
  146. package/.agents/backend/fm-secondmate-parent-lib.sh +70 -0
  147. package/.agents/backend/fm-secondmate-reconcile.sh +371 -0
  148. package/.agents/backend/fm-secondmate-registry-lib.sh +311 -0
  149. package/.agents/backend/fm-secondmate-report.sh +88 -0
  150. package/.agents/backend/fm-send.sh +1059 -0
  151. package/.agents/backend/fm-session-lock-lib.sh +176 -0
  152. package/.agents/backend/fm-session-start.sh +970 -0
  153. package/.agents/backend/fm-sessionstart-cursor.sh +40 -0
  154. package/.agents/backend/fm-sessionstart-nudge.sh +45 -0
  155. package/.agents/backend/fm-sessionstart-run.sh +145 -0
  156. package/.agents/backend/fm-spawn.sh +3153 -0
  157. package/.agents/backend/fm-startup-memory-budget-lib.sh +224 -0
  158. package/.agents/backend/fm-startup-memory-budget.sh +94 -0
  159. package/.agents/backend/fm-startup-network.sh +642 -0
  160. package/.agents/backend/fm-stow-cascade.sh +251 -0
  161. package/.agents/backend/fm-subagent-pretool-check.sh +207 -0
  162. package/.agents/backend/fm-supervise-daemon.sh +1732 -0
  163. package/.agents/backend/fm-supervision-instructions.sh +215 -0
  164. package/.agents/backend/fm-supervision-lib.sh +90 -0
  165. package/.agents/backend/fm-supervisor-target-lib.sh +78 -0
  166. package/.agents/backend/fm-tangle-lib.sh +53 -0
  167. package/.agents/backend/fm-task-inbox-lib.sh +402 -0
  168. package/.agents/backend/fm-tasks-axi-lib.sh +123 -0
  169. package/.agents/backend/fm-teardown.sh +2922 -0
  170. package/.agents/backend/fm-test-isolation-proof.sh +588 -0
  171. package/.agents/backend/fm-test-run.sh +2191 -0
  172. package/.agents/backend/fm-timeout-lib.sh +141 -0
  173. package/.agents/backend/fm-timing-lib.sh +179 -0
  174. package/.agents/backend/fm-tmux-lib.sh +291 -0
  175. package/.agents/backend/fm-tool-update-check.sh +898 -0
  176. package/.agents/backend/fm-trace-context-lib.sh +227 -0
  177. package/.agents/backend/fm-transition-lib.sh +103 -0
  178. package/.agents/backend/fm-turnend-guard-cursor.sh +391 -0
  179. package/.agents/backend/fm-turnend-guard-grok.sh +90 -0
  180. package/.agents/backend/fm-turnend-guard.sh +432 -0
  181. package/.agents/backend/fm-update.sh +110 -0
  182. package/.agents/backend/fm-vendor-auth-probe.sh +190 -0
  183. package/.agents/backend/fm-voice-client.py +1373 -0
  184. package/.agents/backend/fm-voice-relay.py +1256 -0
  185. package/.agents/backend/fm-wake-drain.sh +592 -0
  186. package/.agents/backend/fm-wake-grant.sh +127 -0
  187. package/.agents/backend/fm-wake-lib.sh +1849 -0
  188. package/.agents/backend/fm-watch-arm.sh +602 -0
  189. package/.agents/backend/fm-watch-checkpoint.sh +109 -0
  190. package/.agents/backend/fm-watch.sh +1962 -0
  191. package/.agents/backend/fm-x-dismiss.sh +116 -0
  192. package/.agents/backend/fm-x-followup.sh +286 -0
  193. package/.agents/backend/fm-x-lib.sh +1000 -0
  194. package/.agents/backend/fm-x-link.sh +234 -0
  195. package/.agents/backend/fm-x-poll.sh +185 -0
  196. package/.agents/backend/fm-x-reply.sh +385 -0
  197. package/.agents/backend/fm_voice_frame.py +166 -0
  198. package/.agents/backend/fm_voice_records.py +574 -0
  199. package/.agents/backend/model-bridge.py +360 -0
  200. package/.agents/backend/opencode-go-bridge.py +30 -0
  201. package/.agents/bus/README.md +12 -0
  202. package/.agents/bus/messages.json +1 -0
  203. package/.agents/config/agents.machine.example.yaml +16 -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 +11 -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/filebrowser/.filebrowser.json +6 -0
  211. package/.agents/filebrowser/README.md +11 -0
  212. package/.agents/gateway/README.md +12 -0
  213. package/.agents/github/README.md +15 -0
  214. package/.agents/github/webhooks/.gitkeep +0 -0
  215. package/.agents/github/workflows/.gitkeep +0 -0
  216. package/.agents/harness/opencode/plugins/lib/rodd-operational-input.js +37 -0
  217. package/.agents/harness/opencode/plugins/package.json +4 -0
  218. package/.agents/harness/opencode/plugins/saga-sessionstart.js +77 -0
  219. package/.agents/harness/opencode/plugins/syn-cd-check.js +61 -0
  220. package/.agents/harness/opencode/plugins/syn-pretool-check.js +68 -0
  221. package/.agents/harness/opencode/plugins/syn-turnend-guard.js +105 -0
  222. package/.agents/harness/opencode/plugins/syn-watch-arm.js +521 -0
  223. package/.agents/memory/README.md +46 -0
  224. package/.agents/memory/runes_audit.md +5 -0
  225. package/.agents/migrations/0001-hodd-layout.sh +38 -0
  226. package/.agents/migrations/0002-a2a-mcp.sh +27 -0
  227. package/.agents/migrations/0003-private-data-separation.sh +121 -0
  228. package/.agents/migrations/0004-hoard-and-realms.sh +104 -0
  229. package/.agents/migrations/0005-roots-out-of-tree.sh +158 -0
  230. package/.agents/sandbox/Dockerfile.utgard +19 -0
  231. package/.agents/sandbox/README.md +14 -0
  232. package/.agents/sandbox/utgard.config.json +14 -0
  233. package/.agents/skills/README.md +59 -0
  234. package/.agents/skills/bragi-marketing/README.md +3 -0
  235. package/.agents/skills/bragi-marketing/SKILL.md +82 -0
  236. package/.agents/skills/eindri-homes/README.md +3 -0
  237. package/.agents/skills/eindri-homes/SKILL.md +291 -0
  238. package/.agents/skills/eindri-homes/assets/control-plane.md +122 -0
  239. package/.agents/skills/eindri-homes/assets/dispatch.md +80 -0
  240. package/.agents/skills/frigg-consent/README.md +3 -0
  241. package/.agents/skills/frigg-consent/SKILL.md +56 -0
  242. package/.agents/skills/galdr-ymirsystem/README.md +3 -0
  243. package/.agents/skills/galdr-ymirsystem/SKILL.md +159 -0
  244. package/.agents/skills/galdr-ymirsystem/assets/README.md +74 -0
  245. package/.agents/skills/galdr-ymirsystem/assets/brokk-distro-runtime.md +390 -0
  246. package/.agents/skills/galdr-ymirsystem/assets/build-method.md +113 -0
  247. package/.agents/skills/galdr-ymirsystem/assets/build-tool-categories.md +178 -0
  248. package/.agents/skills/galdr-ymirsystem/assets/eindri-orchestration.md +518 -0
  249. package/.agents/skills/galdr-ymirsystem/assets/eindri-profiles.md +136 -0
  250. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +736 -0
  251. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/claude-code.md +197 -0
  252. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/codex.md +191 -0
  253. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/cursor.md +193 -0
  254. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/opencode.md +262 -0
  255. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/pi.md +295 -0
  256. package/.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md +539 -0
  257. package/.agents/skills/galdr-ymirsystem/assets/installation.md +763 -0
  258. package/.agents/skills/galdr-ymirsystem/assets/local-models/HOST-DATA.example.md +72 -0
  259. package/.agents/skills/galdr-ymirsystem/assets/local-models.md +274 -0
  260. package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +163 -0
  261. package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +415 -0
  262. package/.agents/skills/galdr-ymirsystem/assets/norse-naming.md +325 -0
  263. package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +133 -0
  264. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/einherjar-spawn.schema.json +81 -0
  265. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/herdr-profile.toml +75 -0
  266. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml +101 -0
  267. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/supervision-tree.yml +163 -0
  268. package/.agents/skills/galdr-ymirsystem/assets/pi-boot-guide.md +58 -0
  269. package/.agents/skills/galdr-ymirsystem/assets/porting-upstream-to-norse.md +301 -0
  270. package/.agents/skills/galdr-ymirsystem/assets/principles.md +385 -0
  271. package/.agents/skills/galdr-ymirsystem/assets/reference-adoption.md +99 -0
  272. package/.agents/skills/galdr-ymirsystem/assets/registry.md +379 -0
  273. package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +463 -0
  274. package/.agents/skills/galdr-ymirsystem/assets/runtime-components.md +553 -0
  275. package/.agents/skills/galdr-ymirsystem/assets/smidja.md +180 -0
  276. package/.agents/skills/galdr-ymirsystem/schemas/toon-schemas.md +190 -0
  277. package/.agents/skills/galdr-ymirsystem/scripts/README.md +45 -0
  278. package/.agents/skills/galdr-ymirsystem/scripts/bench-one.sh +248 -0
  279. package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +503 -0
  280. package/.agents/skills/galdr-ymirsystem/scripts/gpu-sample.sh +43 -0
  281. package/.agents/skills/galdr-ymirsystem/scripts/stop-all.sh +34 -0
  282. package/.agents/skills/galdr-ymirsystem/scripts/toon-check.py +188 -0
  283. package/.agents/skills/gjallarhorn-relay/README.md +3 -0
  284. package/.agents/skills/gjallarhorn-relay/SKILL.md +283 -0
  285. package/.agents/skills/groa-update/SKILL.md +90 -0
  286. package/.agents/skills/hamr-adapters/README.md +3 -0
  287. package/.agents/skills/hamr-adapters/SKILL.md +123 -0
  288. package/.agents/skills/hamr-adapters/references/common/control-and-recovery.md +37 -0
  289. package/.agents/skills/hamr-adapters/references/common/dispatch.md +32 -0
  290. package/.agents/skills/hamr-adapters/references/common/model-and-effort.md +42 -0
  291. package/.agents/skills/hamr-adapters/references/common/primary-hooks.md +40 -0
  292. package/.agents/skills/hamr-adapters/references/harness/claude.md +55 -0
  293. package/.agents/skills/hamr-adapters/references/harness/codex.md +43 -0
  294. package/.agents/skills/hamr-adapters/references/harness/cursor.md +75 -0
  295. package/.agents/skills/hamr-adapters/references/harness/grok.md +69 -0
  296. package/.agents/skills/hamr-adapters/references/harness/kimi.md +51 -0
  297. package/.agents/skills/hamr-adapters/references/harness/muse.md +70 -0
  298. package/.agents/skills/hamr-adapters/references/harness/opencode.md +42 -0
  299. package/.agents/skills/hamr-adapters/references/harness/pi.md +56 -0
  300. package/.agents/skills/herdr-panes/README.md +3 -0
  301. package/.agents/skills/herdr-panes/SKILL.md +92 -0
  302. package/.agents/skills/herdr-panes/assets/herdr-backend.md +346 -0
  303. package/.agents/skills/herdr-panes/assets/tmux-backend.md +115 -0
  304. package/.agents/skills/hnoss-design/DESIGN.md +19 -0
  305. package/.agents/skills/hnoss-design/README.md +3 -0
  306. package/.agents/skills/hnoss-design/SKILL.md +83 -0
  307. package/.agents/skills/hvild-afk/README.md +3 -0
  308. package/.agents/skills/hvild-afk/SKILL.md +241 -0
  309. package/.agents/skills/jord-projects/README.md +3 -0
  310. package/.agents/skills/jord-projects/SKILL.md +92 -0
  311. package/.agents/skills/lifecycle/SKILL.md +56 -0
  312. package/.agents/skills/lifecycle/smoke_test.sh +57 -0
  313. package/.agents/skills/lifecycle/start.sh +21 -0
  314. package/.agents/skills/lifecycle/status.sh +35 -0
  315. package/.agents/skills/lifecycle/stop.sh +16 -0
  316. package/.agents/skills/muninn-stow/README.md +3 -0
  317. package/.agents/skills/muninn-stow/SKILL.md +309 -0
  318. package/.agents/skills/no-mistakes/SKILL.md +379 -0
  319. package/.agents/skills/nornir-schedule/README.md +3 -0
  320. package/.agents/skills/nornir-schedule/SKILL.md +25 -0
  321. package/.agents/skills/nornir-schedule/assets/events.md +137 -0
  322. package/.agents/skills/nornir-schedule/assets/quota.md +131 -0
  323. package/.agents/skills/nsr-compliance/README.md +3 -0
  324. package/.agents/skills/nsr-compliance/SKILL.md +29 -0
  325. package/.agents/skills/nsr-compliance/assets/nsr/README.md +40 -0
  326. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/README.md +15 -0
  327. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/git-workflow.md +18 -0
  328. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/security.md +22 -0
  329. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/tech-stack.md +8 -0
  330. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/SKILL.md +71 -0
  331. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/config/core_four.yaml +16 -0
  332. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_danger.sh +102 -0
  333. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_wiring.sh +69 -0
  334. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/validate_code.sh +29 -0
  335. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/verify_docs.py +66 -0
  336. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/generate.sh +109 -0
  337. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/result_envelope.json +14 -0
  338. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/task_envelope.json +20 -0
  339. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/runner.py +303 -0
  340. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/telemetry/logger.py +112 -0
  341. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/README.md +18 -0
  342. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/config/README.md +10 -0
  343. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/README.md +12 -0
  344. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_env.sh +23 -0
  345. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_paths.sh +20 -0
  346. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_platform.sh +23 -0
  347. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/README.md +11 -0
  348. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/envelopes/README.md +10 -0
  349. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/README.md +10 -0
  350. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/install.sh +125 -0
  351. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/telemetry/README.md +11 -0
  352. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/README.md +20 -0
  353. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/README.md +36 -0
  354. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/SKILL-template.md +14 -0
  355. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/README.md +25 -0
  356. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/SKILL.md +13 -0
  357. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/create_branch.sh +6 -0
  358. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/safe_commit.sh +9 -0
  359. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/sync_upstream.sh +6 -0
  360. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/README.md +27 -0
  361. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/SKILL.md +15 -0
  362. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/smoke_test.sh +12 -0
  363. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/start.sh +19 -0
  364. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/status.sh +12 -0
  365. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/stop.sh +15 -0
  366. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/README.md +18 -0
  367. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/README.md +10 -0
  368. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/core_four.yaml +13 -0
  369. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/README.md +12 -0
  370. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_danger.sh +102 -0
  371. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_env.sh +23 -0
  372. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_paths.sh +20 -0
  373. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_platform.sh +23 -0
  374. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_wiring.sh +69 -0
  375. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/README.md +11 -0
  376. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/README.md +10 -0
  377. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/result_envelope.json +14 -0
  378. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/task_envelope.json +20 -0
  379. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/runner.py +303 -0
  380. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/README.md +10 -0
  381. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/install.sh +125 -0
  382. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/README.md +11 -0
  383. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/logger.py +112 -0
  384. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/README.md +14 -0
  385. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/api.md +17 -0
  386. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/compliance-wiring.md +155 -0
  387. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/frontend.md +15 -0
  388. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/README.md +11 -0
  389. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/README.md +23 -0
  390. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/README.md +16 -0
  391. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/template-README.md +11 -0
  392. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/deploy.sh +49 -0
  393. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/README.md +12 -0
  394. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/development.env.example +17 -0
  395. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/production.env.example +17 -0
  396. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/staging.env.example +17 -0
  397. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/README.md +11 -0
  398. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/template.env.example +8 -0
  399. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/README.md +26 -0
  400. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/agent.md +7 -0
  401. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/developers/dev-1.md +20 -0
  402. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/linux.md +9 -0
  403. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/macos.md +10 -0
  404. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/shared.md +19 -0
  405. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/windows.md +14 -0
  406. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/README.md +25 -0
  407. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/_template.md +41 -0
  408. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/hosting-1.md +41 -0
  409. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/README.md +21 -0
  410. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/README.md +15 -0
  411. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/deployment.md +19 -0
  412. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/disaster-recovery.md +15 -0
  413. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/ops-tasks.md +14 -0
  414. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/features/README.md +16 -0
  415. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/project-skills.md +146 -0
  416. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/README.md +11 -0
  417. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/software-compliance-research.md +269 -0
  418. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/working-with-agents.md +260 -0
  419. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/AGENTS.md +38 -0
  420. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/ARCHITECTURE.md +36 -0
  421. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/BEST_PRACTICES.md +27 -0
  422. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/CI_CD.md +23 -0
  423. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/FEATURES.md +15 -0
  424. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/README.md +22 -0
  425. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/RULES.md +37 -0
  426. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/STRUCTURE.md +45 -0
  427. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/TECH_STACK.md +28 -0
  428. package/.agents/skills/nsr-compliance/assets/nsr/scaffold-spec.md +63 -0
  429. package/.agents/skills/nsr-compliance/assets/nsr/scripts/scaffold.sh +103 -0
  430. package/.agents/skills/nsr-compliance/assets/nsr/scripts/validate.sh +52 -0
  431. package/.agents/skills/nsr-compliance/assets/nsrcompliance/SKILL.md +71 -0
  432. package/.agents/skills/nsr-compliance/assets/nsrcompliance/config/core_four.yaml +16 -0
  433. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_danger.sh +102 -0
  434. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_wiring.sh +69 -0
  435. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/validate_code.sh +29 -0
  436. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/verify_docs.py +66 -0
  437. package/.agents/skills/nsr-compliance/assets/nsrcompliance/generate.sh +109 -0
  438. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/result_envelope.json +14 -0
  439. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/task_envelope.json +20 -0
  440. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/runner.py +303 -0
  441. package/.agents/skills/nsr-compliance/assets/nsrcompliance/telemetry/logger.py +112 -0
  442. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/README.md +18 -0
  443. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/config/README.md +10 -0
  444. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/README.md +12 -0
  445. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_env.sh +23 -0
  446. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_paths.sh +20 -0
  447. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_platform.sh +23 -0
  448. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/README.md +11 -0
  449. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/envelopes/README.md +10 -0
  450. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/README.md +10 -0
  451. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/install.sh +125 -0
  452. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/telemetry/README.md +11 -0
  453. package/.agents/skills/pr-ops/README.md +3 -0
  454. package/.agents/skills/pr-ops/SKILL.md +109 -0
  455. package/.agents/skills/ratatoskr-a2a/README.md +3 -0
  456. package/.agents/skills/ratatoskr-a2a/SKILL.md +148 -0
  457. package/.agents/skills/rules-check-drift/SKILL.md +81 -0
  458. package/.agents/skills/saga-bearings/README.md +3 -0
  459. package/.agents/skills/saga-bearings/SKILL.md +26 -0
  460. package/.agents/skills/saga-bearings/assets/bearings.md +161 -0
  461. package/.agents/skills/saga-bearings/assets/board-template.html +731 -0
  462. package/.agents/skills/saga-bearings/assets/recap.md +56 -0
  463. package/.agents/skills/syn-recovery/README.md +3 -0
  464. package/.agents/skills/syn-recovery/SKILL.md +54 -0
  465. package/.agents/skills/tyr-check/README.md +3 -0
  466. package/.agents/skills/tyr-check/SKILL.md +218 -0
  467. package/.agents/skills/urdh-hold/README.md +3 -0
  468. package/.agents/skills/urdh-hold/SKILL.md +25 -0
  469. package/.agents/skills/urdh-hold/assets/decisions.md +15 -0
  470. package/.agents/skills/urdh-hold/assets/hold.md +54 -0
  471. package/.agents/skills/vor-diagnostics/README.md +3 -0
  472. package/.agents/skills/vor-diagnostics/SKILL.md +68 -0
  473. package/.agents/skills/ymir-host/README.md +3 -0
  474. package/.agents/skills/ymir-host/SKILL.md +35 -0
  475. package/.agents/skills/ymir-host/assets/desktop.md +36 -0
  476. package/.agents/skills/ymir-host/assets/install.md +69 -0
  477. package/.agents/skills/ymir-host/assets/omarchy.md +297 -0
  478. package/.agents/skills/ymir-host/assets/runbooks.md +15 -0
  479. package/.agents/skills/ymir-host/assets/thjazi.md +220 -0
  480. package/.agents/skills/ymir-host/assets/update.md +64 -0
  481. package/.agents/tests/assets/board-render-harness.mjs +117 -0
  482. package/.agents/tests/cmux-test-safety.sh +51 -0
  483. package/.agents/tests/fixtures.sh +291 -0
  484. package/.agents/tests/fm-afk-inject-e2e.test.sh +428 -0
  485. package/.agents/tests/fm-afk-inject-herdr-e2e.test.sh +536 -0
  486. package/.agents/tests/fm-afk-launch.test.sh +961 -0
  487. package/.agents/tests/fm-afk-pi-herdr-return-e2e.test.sh +297 -0
  488. package/.agents/tests/fm-afk-return.test.sh +283 -0
  489. package/.agents/tests/fm-arm-pretool-check.test.sh +482 -0
  490. package/.agents/tests/fm-ask-user-authority.test.sh +42 -0
  491. package/.agents/tests/fm-backend-autodetect-smoke.test.sh +176 -0
  492. package/.agents/tests/fm-backend-cmux-smoke.test.sh +188 -0
  493. package/.agents/tests/fm-backend-cmux.test.sh +1166 -0
  494. package/.agents/tests/fm-backend-herdr-eventwait-smoke.test.sh +136 -0
  495. package/.agents/tests/fm-backend-herdr-eventwait.test.py +106 -0
  496. package/.agents/tests/fm-backend-herdr-focus-flash-e2e.test.sh +409 -0
  497. package/.agents/tests/fm-backend-herdr-launcher-workspace-e2e.test.sh +437 -0
  498. package/.agents/tests/fm-backend-herdr-presentation-e2e.test.sh +1424 -0
  499. package/.agents/tests/fm-backend-herdr-prune-safety-e2e.test.sh +180 -0
  500. package/.agents/tests/fm-backend-herdr-respawn-idem-e2e.test.sh +182 -0
  501. package/.agents/tests/fm-backend-herdr-smoke.test.sh +355 -0
  502. package/.agents/tests/fm-backend-herdr-workspace-per-home-e2e.test.sh +251 -0
  503. package/.agents/tests/fm-backend-herdr.test.sh +4606 -0
  504. package/.agents/tests/fm-backend-orca.test.sh +1357 -0
  505. package/.agents/tests/fm-backend-tmux-smoke.test.sh +173 -0
  506. package/.agents/tests/fm-backend-zellij-smoke.test.sh +205 -0
  507. package/.agents/tests/fm-backend-zellij.test.sh +1360 -0
  508. package/.agents/tests/fm-backend.test.sh +1142 -0
  509. package/.agents/tests/fm-backlog-atomicity.test.sh +2302 -0
  510. package/.agents/tests/fm-backlog-handoff.test.sh +1360 -0
  511. package/.agents/tests/fm-bearings-board-render.test.sh +135 -0
  512. package/.agents/tests/fm-bearings-board.test.sh +414 -0
  513. package/.agents/tests/fm-bearings-snapshot.test.sh +1990 -0
  514. package/.agents/tests/fm-bootstrap-network-parallel.test.sh +316 -0
  515. package/.agents/tests/fm-bootstrap.test.sh +1178 -0
  516. package/.agents/tests/fm-branch-supervision.test.sh +552 -0
  517. package/.agents/tests/fm-brief.test.sh +785 -0
  518. package/.agents/tests/fm-busy-adapter-wiring.test.sh +324 -0
  519. package/.agents/tests/fm-busy-state.test.sh +465 -0
  520. package/.agents/tests/fm-calm-pi-extension.test.sh +3979 -0
  521. package/.agents/tests/fm-captain-hold-lifecycle.test.sh +1187 -0
  522. package/.agents/tests/fm-cd-pretool-check.test.sh +400 -0
  523. package/.agents/tests/fm-check-unregister.test.sh +198 -0
  524. package/.agents/tests/fm-classify-corr-token.test.sh +543 -0
  525. package/.agents/tests/fm-classify-decision-key.test.sh +340 -0
  526. package/.agents/tests/fm-claude-stop-autoarm-live-e2e.test.sh +164 -0
  527. package/.agents/tests/fm-claude-stop-autoarm.test.sh +1190 -0
  528. package/.agents/tests/fm-cmux-claude-composer-live-e2e.test.sh +110 -0
  529. package/.agents/tests/fm-codex-continuity-live-e2e.test.sh +55 -0
  530. package/.agents/tests/fm-composer-ghost.test.sh +716 -0
  531. package/.agents/tests/fm-composer-lib.test.sh +666 -0
  532. package/.agents/tests/fm-composer-matrix-live-e2e.test.sh +220 -0
  533. package/.agents/tests/fm-control-herdr-smoke.test.sh +149 -0
  534. package/.agents/tests/fm-control-relaunch.test.sh +1530 -0
  535. package/.agents/tests/fm-control.test.sh +910 -0
  536. package/.agents/tests/fm-crew-state.test.sh +1610 -0
  537. package/.agents/tests/fm-cursor-harness.test.sh +404 -0
  538. package/.agents/tests/fm-cursor-primary-live-e2e.test.sh +217 -0
  539. package/.agents/tests/fm-cursor-primary.test.sh +708 -0
  540. package/.agents/tests/fm-daemon.test.sh +2740 -0
  541. package/.agents/tests/fm-documentation-audiences.test.sh +141 -0
  542. package/.agents/tests/fm-ensure-agents-md.test.sh +371 -0
  543. package/.agents/tests/fm-extension-binding.test.sh +2187 -0
  544. package/.agents/tests/fm-fleet-snapshot-view.test.sh +816 -0
  545. package/.agents/tests/fm-fleet-sync.test.sh +721 -0
  546. package/.agents/tests/fm-gate-refuse.test.sh +356 -0
  547. package/.agents/tests/fm-gitignore-config.test.sh +89 -0
  548. package/.agents/tests/fm-gotmp.test.sh +230 -0
  549. package/.agents/tests/fm-grok-continuity-live-e2e.test.sh +112 -0
  550. package/.agents/tests/fm-grok-harness.test.sh +117 -0
  551. package/.agents/tests/fm-grok-stop-live-e2e.test.sh +219 -0
  552. package/.agents/tests/fm-guard-stale-banner.test.sh +709 -0
  553. package/.agents/tests/fm-harness-adapter-instructions-live-e2e.test.sh +134 -0
  554. package/.agents/tests/fm-harness-adapter-references.test.sh +30 -0
  555. package/.agents/tests/fm-harness-liveness-drift-live-e2e.test.sh +151 -0
  556. package/.agents/tests/fm-herdr-lab.test.sh +243 -0
  557. package/.agents/tests/fm-herdr-session-cleanup-e2e.test.sh +146 -0
  558. package/.agents/tests/fm-herdr-session-cleanup.test.sh +329 -0
  559. package/.agents/tests/fm-herdr-submit-confirm-live-e2e.test.sh +125 -0
  560. package/.agents/tests/fm-herdr-version-floor-live-e2e.test.sh +144 -0
  561. package/.agents/tests/fm-home-summary-refresh.test.sh +971 -0
  562. package/.agents/tests/fm-inactive-reconcile.test.sh +485 -0
  563. package/.agents/tests/fm-kimi-harness.test.sh +687 -0
  564. package/.agents/tests/fm-lint-workflows.test.sh +532 -0
  565. package/.agents/tests/fm-lint.test.sh +1023 -0
  566. package/.agents/tests/fm-muse-harness.test.sh +932 -0
  567. package/.agents/tests/fm-muse-signals-live-e2e.test.sh +205 -0
  568. package/.agents/tests/fm-no-mistakes-required.test.sh +72 -0
  569. package/.agents/tests/fm-on.test.sh +507 -0
  570. package/.agents/tests/fm-opencode-primary-live-e2e.test.sh +357 -0
  571. package/.agents/tests/fm-operational-input.test.sh +160 -0
  572. package/.agents/tests/fm-peek-remote.test.sh +110 -0
  573. package/.agents/tests/fm-pending-reply.test.sh +1288 -0
  574. package/.agents/tests/fm-pi-branch-extension.test.sh +3182 -0
  575. package/.agents/tests/fm-pi-branch-live-e2e.test.sh +527 -0
  576. package/.agents/tests/fm-pi-primary-live-e2e.test.sh +345 -0
  577. package/.agents/tests/fm-pi-primary-types.test.sh +68 -0
  578. package/.agents/tests/fm-pi-watch-extension.test.sh +2843 -0
  579. package/.agents/tests/fm-pr-check-security.test.sh +2140 -0
  580. package/.agents/tests/fm-pr-merge.test.sh +2135 -0
  581. package/.agents/tests/fm-procevent-quota.test.sh +225 -0
  582. package/.agents/tests/fm-procevent-when.test.sh +406 -0
  583. package/.agents/tests/fm-procevent.test.sh +1745 -0
  584. package/.agents/tests/fm-project-origin.test.sh +110 -0
  585. package/.agents/tests/fm-public-followup.test.sh +2272 -0
  586. package/.agents/tests/fm-quota-array-dispatch-live-e2e.test.sh +526 -0
  587. package/.agents/tests/fm-quota-choose.test.sh +626 -0
  588. package/.agents/tests/fm-remote-backlog-handoff.test.sh +453 -0
  589. package/.agents/tests/fm-remote-doctor.test.sh +625 -0
  590. package/.agents/tests/fm-remote-entrypoint.test.sh +59 -0
  591. package/.agents/tests/fm-remote-job-orphan-reap.test.sh +205 -0
  592. package/.agents/tests/fm-remote-job.test.sh +768 -0
  593. package/.agents/tests/fm-remote-reply.test.sh +520 -0
  594. package/.agents/tests/fm-remote-secondmate-lifecycle-e2e.test.sh +1256 -0
  595. package/.agents/tests/fm-remote-secondmate-parent-binding.test.sh +326 -0
  596. package/.agents/tests/fm-remote-secondmate-trace-context.test.sh +310 -0
  597. package/.agents/tests/fm-remote-transport-lanes.test.sh +431 -0
  598. package/.agents/tests/fm-review-diff.test.sh +176 -0
  599. package/.agents/tests/fm-secondmate-harness.test.sh +2600 -0
  600. package/.agents/tests/fm-secondmate-lifecycle-e2e.test.sh +259 -0
  601. package/.agents/tests/fm-secondmate-liveness.test.sh +559 -0
  602. package/.agents/tests/fm-secondmate-reconcile.test.sh +732 -0
  603. package/.agents/tests/fm-secondmate-safety.test.sh +2972 -0
  604. package/.agents/tests/fm-secondmate-sync.test.sh +913 -0
  605. package/.agents/tests/fm-send-inbox-doorbell-live-e2e.test.sh +206 -0
  606. package/.agents/tests/fm-send-inbox.test.sh +352 -0
  607. package/.agents/tests/fm-send-popup-settle.test.sh +167 -0
  608. package/.agents/tests/fm-send-remote-delivery.test.sh +796 -0
  609. package/.agents/tests/fm-send-resolve-key.test.sh +551 -0
  610. package/.agents/tests/fm-send-secondmate-marker-herdr-e2e.test.sh +187 -0
  611. package/.agents/tests/fm-send-secondmate-marker.test.sh +278 -0
  612. package/.agents/tests/fm-send-settle.test.sh +147 -0
  613. package/.agents/tests/fm-send-strict.test.sh +241 -0
  614. package/.agents/tests/fm-session-lock-ancestry.test.sh +365 -0
  615. package/.agents/tests/fm-session-start.test.sh +2515 -0
  616. package/.agents/tests/fm-sessionstart-hook-live-e2e.test.sh +631 -0
  617. package/.agents/tests/fm-sessionstart-instruction-refresh-live-e2e.test.sh +230 -0
  618. package/.agents/tests/fm-sessionstart-nudge.test.sh +1039 -0
  619. package/.agents/tests/fm-shared-captain-inheritance.test.sh +404 -0
  620. package/.agents/tests/fm-spawn-batch.test.sh +148 -0
  621. package/.agents/tests/fm-spawn-dispatch-profile.test.sh +827 -0
  622. package/.agents/tests/fm-spawn-pool-base-freshen.test.sh +440 -0
  623. package/.agents/tests/fm-spawn-worktree-settle.test.sh +147 -0
  624. package/.agents/tests/fm-startup-memory-budget.test.sh +333 -0
  625. package/.agents/tests/fm-startup-network.test.sh +712 -0
  626. package/.agents/tests/fm-stow-cascade.test.sh +370 -0
  627. package/.agents/tests/fm-subagent-pretool-check.test.sh +291 -0
  628. package/.agents/tests/fm-supervision-events.test.sh +156 -0
  629. package/.agents/tests/fm-supervision-instructions.test.sh +189 -0
  630. package/.agents/tests/fm-tangle-guard.test.sh +277 -0
  631. package/.agents/tests/fm-task-delivery.test.sh +420 -0
  632. package/.agents/tests/fm-task-inbox.test.sh +513 -0
  633. package/.agents/tests/fm-teardown-endpoint-safety.test.sh +374 -0
  634. package/.agents/tests/fm-teardown.test.sh +2665 -0
  635. package/.agents/tests/fm-test-fixture-cleanup.test.sh +172 -0
  636. package/.agents/tests/fm-test-fixtures.test.sh +132 -0
  637. package/.agents/tests/fm-test-isolation-proof.test.sh +278 -0
  638. package/.agents/tests/fm-test-run.test.sh +1196 -0
  639. package/.agents/tests/fm-tmux-agent-liveness.test.sh +354 -0
  640. package/.agents/tests/fm-tmux-submit-busy.test.sh +340 -0
  641. package/.agents/tests/fm-tool-update-check.test.sh +1044 -0
  642. package/.agents/tests/fm-trace-context-lib.test.sh +253 -0
  643. package/.agents/tests/fm-trace-context-spawn.test.sh +581 -0
  644. package/.agents/tests/fm-transition-lib.test.sh +54 -0
  645. package/.agents/tests/fm-turnend-guard.test.sh +1822 -0
  646. package/.agents/tests/fm-update.test.sh +304 -0
  647. package/.agents/tests/fm-vendor-auth-probe.test.sh +395 -0
  648. package/.agents/tests/fm-voice-relay.test.sh +4741 -0
  649. package/.agents/tests/fm-wake-daemon-lifecycle-e2e.test.sh +171 -0
  650. package/.agents/tests/fm-wake-drain-open-decisions-cursor.test.sh +356 -0
  651. package/.agents/tests/fm-wake-drain-open-decisions.test.sh +226 -0
  652. package/.agents/tests/fm-wake-drain-unread-status.test.sh +379 -0
  653. package/.agents/tests/fm-wake-queue.test.sh +1224 -0
  654. package/.agents/tests/fm-watch-arm.test.sh +821 -0
  655. package/.agents/tests/fm-watch-checkpoint.test.sh +87 -0
  656. package/.agents/tests/fm-watch-recovery-loop.test.sh +223 -0
  657. package/.agents/tests/fm-watch-triage.test.sh +3889 -0
  658. package/.agents/tests/fm-watcher-lock.test.sh +1133 -0
  659. package/.agents/tests/fm-x-mode.test.sh +3042 -0
  660. package/.agents/tests/gleipnir-guard-pretool-check.test.sh +51 -0
  661. package/.agents/tests/gleipnir-machine-lock.test.sh +130 -0
  662. package/.agents/tests/herdr-test-safety.sh +42 -0
  663. package/.agents/tests/lib.sh +315 -0
  664. package/.agents/tests/remote-herdr-fixture.sh +125 -0
  665. package/.agents/tests/secondmate-helpers.sh +193 -0
  666. package/.agents/tests/smoke.test.sh +93 -0
  667. package/.agents/tests/wake-helpers.sh +338 -0
  668. package/.agents/tests/zellij-test-safety.sh +60 -0
  669. package/.agents/tools/README.md +10 -0
  670. package/.agents/tools/bin/tasks-cli +267 -0
  671. package/.agents/tools/tasks-cli.ts +216 -0
  672. package/AGENTS.md +498 -0
  673. package/CHANGELOG.md +1913 -0
  674. package/LICENSE +1 -1
  675. package/NOTICE +63 -0
  676. package/README.md +114 -60
  677. package/RULES/01-domains.md +51 -0
  678. package/RULES/02-agents.md +78 -0
  679. package/RULES/03-houses.md +61 -0
  680. package/RULES/04-hoard.md +97 -0
  681. package/RULES/05-platforms.md +67 -0
  682. package/RULES/06-append-only.md +108 -0
  683. package/RULES/07-config.md +101 -0
  684. package/RULES/08-delivery-gate.md +75 -0
  685. package/RULES/09-electron.md +58 -0
  686. package/RULES/README.md +22 -0
  687. package/bin/README.md +107 -0
  688. package/bin/a2a-mcp.sh +133 -0
  689. package/bin/a2a-serve.py +103 -0
  690. package/bin/a2a-serve.sh +8 -0
  691. package/bin/a2a-talk.sh +50 -0
  692. package/bin/a2abridge-ensure.sh +108 -0
  693. package/bin/agent-run.sh +43 -0
  694. package/bin/agents-config.sh +256 -0
  695. package/bin/apodex-smoke-test.sh +105 -0
  696. package/bin/bifrost-bridge.sh +131 -0
  697. package/bin/bifrost-ingress.sh +77 -0
  698. package/bin/bootstrap-macos.sh +112 -0
  699. package/bin/bootstrap-windows.ps1 +112 -0
  700. package/bin/branch-guard.sh +64 -0
  701. package/bin/brokk +73 -0
  702. package/bin/brokk-classify-lib.sh +1770 -0
  703. package/bin/brokk-lease-lib.sh +222 -0
  704. package/bin/brokk-lease.sh +193 -0
  705. package/bin/brokk-lint.sh +65 -0
  706. package/bin/brokk-send.sh +51 -0
  707. package/bin/brokk-update.sh +9 -0
  708. package/bin/brokk-wake-grant.sh +127 -0
  709. package/bin/brokk-wake-lib.sh +1849 -0
  710. package/bin/changelog-assemble.sh +154 -0
  711. package/bin/changelog-guard.sh +197 -0
  712. package/bin/crash-sense.sh +173 -0
  713. package/bin/design-check.sh +80 -0
  714. package/bin/design-icon.sh +153 -0
  715. package/bin/desktop-place.sh +224 -0
  716. package/bin/docs-guard.sh +39 -0
  717. package/bin/editor-place.sh +225 -0
  718. package/bin/eindri-acclaim.sh +47 -0
  719. package/bin/eindri-control.sh +28 -0
  720. package/bin/eindri-role.sh +83 -0
  721. package/bin/eindri-seat.sh +83 -0
  722. package/bin/eindri-seen.sh +54 -0
  723. package/bin/eindri-send.sh +15 -0
  724. package/bin/eindri-start.sh +98 -0
  725. package/bin/eindri-watch.sh +57 -0
  726. package/bin/einherjar-spawn.sh +576 -0
  727. package/bin/eir-doctor.sh +158 -0
  728. package/bin/erindi-brief.sh +271 -0
  729. package/bin/feature-inventory.sh +73 -0
  730. package/bin/fleet-apply.sh +81 -0
  731. package/bin/github-deploy.sh +94 -0
  732. package/bin/gjallarhorn-expose.sh +136 -0
  733. package/bin/gjallarhorn-notify.sh +71 -0
  734. package/bin/gjallarhorn-purge.sh +67 -0
  735. package/bin/gjallarhorn-tunnel.sh +85 -0
  736. package/bin/gleipnir-lock-lib.sh +284 -0
  737. package/bin/groa-update.sh +130 -0
  738. package/bin/hall-snapshot.sh +111 -0
  739. package/bin/hamr-harness.sh +246 -0
  740. package/bin/heimdall-ssh-keys.sh +374 -0
  741. package/bin/herdr-agents.py +44 -0
  742. package/bin/herdr-ensure.sh +104 -0
  743. package/bin/herdr-run.sh +452 -0
  744. package/bin/hermes-ensure.sh +88 -0
  745. package/bin/hlidskjalf-agents.sh +172 -0
  746. package/bin/hlidskjalf-usage.sh +196 -0
  747. package/bin/hoard-guard.sh +135 -0
  748. package/bin/hoard-lib.sh +105 -0
  749. package/bin/hodd.sh +102 -0
  750. package/bin/host-sense.sh +199 -0
  751. package/bin/huginn-research-worker.sh +121 -0
  752. package/bin/local-model-lock.sh +70 -0
  753. package/bin/mimir-bridge.py +259 -0
  754. package/bin/mimir-bridge.sh +100 -0
  755. package/bin/mimir-ingest.sh +131 -0
  756. package/bin/mimir-reflect.sh +27 -0
  757. package/bin/mimir.sh +113 -0
  758. package/bin/mjollnir-webhook.sh +72 -0
  759. package/bin/mjollnir.sh +104 -0
  760. package/bin/model-hardware.sh +96 -0
  761. package/bin/model-resolve.sh +160 -0
  762. package/bin/models-detect.sh +178 -0
  763. package/bin/nornir-cron-start.sh +162 -0
  764. package/bin/nornir-job-daily-briefing.sh +191 -0
  765. package/bin/nornir-job-git-sync.sh +152 -0
  766. package/bin/nornir-job-hall-snapshot.sh +28 -0
  767. package/bin/nornir-job-memory-housekeeping.sh +114 -0
  768. package/bin/nornir-job-nsr-compliance.sh +54 -0
  769. package/bin/nornir-job-observer.sh +166 -0
  770. package/bin/nornir-job-skillopt-sleep.sh +76 -0
  771. package/bin/npm-publish.sh +136 -0
  772. package/bin/omarchy-hook-install.sh +60 -0
  773. package/bin/omarchy-install.sh +161 -0
  774. package/bin/omarchy-plugins.sh +187 -0
  775. package/bin/omarchy-sense.sh +162 -0
  776. package/bin/perm-guard.sh +30 -0
  777. package/bin/pi-agent.sh +68 -0
  778. package/bin/pi-ensure.sh +77 -0
  779. package/bin/pi-local.sh +37 -0
  780. package/bin/pi-model-agnostic.sh +71 -0
  781. package/bin/pi-seat.sh +63 -0
  782. package/bin/prereq-ensure.sh +166 -0
  783. package/bin/private-guard.sh +58 -0
  784. package/bin/project-git.sh +69 -0
  785. package/bin/public-guard.sh +71 -0
  786. package/bin/ratatoskr.sh +49 -0
  787. package/bin/realm-lib.sh +32 -0
  788. package/bin/repo-scrub.sh +62 -0
  789. package/bin/rodd-operational-input.sh +250 -0
  790. package/bin/runes-append.sh +198 -0
  791. package/bin/saga-session-start.sh +172 -0
  792. package/bin/saga-sessionstart-run.sh +79 -0
  793. package/bin/saga-wake-drain.sh +41 -0
  794. package/bin/secret-guard.sh +63 -0
  795. package/bin/sessrumnir-ensure.sh +100 -0
  796. package/bin/sessrumnir-sync.sh +237 -0
  797. package/bin/sessrumnir.sh +104 -0
  798. package/bin/skillopt-setup.sh +76 -0
  799. package/bin/skuld-branch-outcome.sh +203 -0
  800. package/bin/skuld-branch-prompt.sh +101 -0
  801. package/bin/smidja-bootstrap.sh +94 -0
  802. package/bin/smidja-observe.sh +86 -0
  803. package/bin/syn-arm-pretool-check.sh +57 -0
  804. package/bin/syn-asset-pretool-check.sh +89 -0
  805. package/bin/syn-cd-pretool-check.sh +28 -0
  806. package/bin/syn-guard-pretool-check.sh +83 -0
  807. package/bin/syn-spawn-pretool-check.sh +58 -0
  808. package/bin/syn-turnend-guard.sh +36 -0
  809. package/bin/syn-watch-arm.sh +99 -0
  810. package/bin/tailscale-sync.sh +203 -0
  811. package/bin/telegram-bot.sh +82 -0
  812. package/bin/toolchain.sh +74 -0
  813. package/bin/ui-truth-check.sh +75 -0
  814. package/bin/utgard.sh +111 -0
  815. package/bin/valhalla.sh +115 -0
  816. package/bin/valknut-load.sh +298 -0
  817. package/bin/vor-crew-state.sh +124 -0
  818. package/bin/wedge-notify.sh +60 -0
  819. package/bin/workspace-provision.sh +80 -0
  820. package/bin/workspace-rag.sh +163 -0
  821. package/bin/wyrd-db.sh +47 -0
  822. package/bin/yggdrasil.sh +152 -0
  823. package/bin/ymir-edit.sh +145 -0
  824. package/bin/ymir-install.sh +806 -0
  825. package/bin/ymir-invite.sh +93 -0
  826. package/bin/ymir-isolation.sh +88 -0
  827. package/bin/ymir-migrate.sh +61 -0
  828. package/bin/ymir-plan.sh +356 -0
  829. package/bin/ymir-platform.sh +348 -0
  830. package/bin/ymir-say.sh +110 -0
  831. package/bin/ymir-setup-auth.sh +119 -0
  832. package/bin/ymir-validate.sh +193 -0
  833. package/bin/ymir.js +74 -16
  834. package/docs/Architecture.md +339 -0
  835. package/docs/design.md +351 -0
  836. package/docs/installations/README.md +63 -0
  837. package/docs/installations/ymir-home.md +93 -0
  838. package/docs/integration.md +105 -0
  839. package/docs/lore.md +1060 -0
  840. package/docs/research/agent-harnesses.md +290 -0
  841. package/docs/runbooks/README.md +19 -0
  842. package/docs/runbooks/a2a.md +91 -0
  843. package/docs/runbooks/agent-permissions.md +99 -0
  844. package/docs/runbooks/agents.md +57 -0
  845. package/docs/runbooks/models.md +69 -0
  846. package/docs/runbooks/realm-onboarding.md +60 -0
  847. package/docs/runbooks/secrets-and-hoard.md +60 -0
  848. package/docs/runbooks/updates-and-migrations.md +110 -0
  849. package/docs/runbooks/worktrees-isolation.md +72 -0
  850. package/docs/session-start.md +105 -0
  851. package/docs/skillopt-integration.md +321 -0
  852. package/docs/sync-system.md +66 -0
  853. package/docs/workspaces.md +104 -0
  854. package/docs/ymir-rut.md +260 -0
  855. package/package.json +54 -14
  856. package/packaging/build.sh +74 -0
  857. package/packaging/macos/Ymir Installer.command +43 -0
  858. package/packaging/windows/ymir-setup.nsi +74 -0
  859. package/scripts/README.md +22 -0
  860. package/scripts/electron.sh +269 -0
  861. package/scripts/lower.sh +34 -0
  862. package/scripts/raise.sh +42 -0
  863. package/scripts/start.sh +217 -0
  864. package/scripts/stop.sh +113 -0
  865. package/install.sh +0 -35
@@ -0,0 +1,878 @@
1
+ #!/usr/bin/env bash
2
+ # fm-control.sh - the CONTROL PLANE for a firstmate-owned agent: allowlisted
3
+ # lifecycle verbs addressed to an exact task id.
4
+ #
5
+ # Usage: fm-control.sh <task-id> interrupt
6
+ # fm-control.sh <task-id> exit
7
+ # fm-control.sh <task-id> relaunch [--harness <name>] [--model <name>]
8
+ # [--effort <level>]
9
+ # (--note <text> | --note-file <path>)
10
+ #
11
+ # Why this exists, and how it differs from fm-send.sh. bin/fm-send.sh is the
12
+ # DATA plane: conversational text for the agent to read, always routing-marked
13
+ # for a kind=secondmate target so the reply returns through the status path.
14
+ # That marking is right for a message and wrong for a lifecycle command - a
15
+ # marked "/quit" arrives as ordinary chat the agent reasons ABOUT instead of
16
+ # executing. This script is the control plane: semantic process control with a
17
+ # closed verb list, per-harness mechanics owned by an executable adapter
18
+ # (bin/fm-control-lib.sh) rather than improvised in agent prose, and a verified
19
+ # postcondition for every action. There is deliberately NO arbitrary-text and
20
+ # NO generic raw-key entry point here; fm-send remains the only way to send an
21
+ # agent something to read.
22
+ #
23
+ # interrupt Deliver the harness's verified interrupt sequence. The agent
24
+ # keeps running. Postcondition: delivery succeeded, the endpoint
25
+ # still exists, and the agent is still alive where the backend can
26
+ # classify that. Cancellation is confirmed only from an adapter-
27
+ # owned acknowledgement and otherwise reported unconfirmed. Busy
28
+ # state is never rewritten as proof of the action.
29
+ # exit Stop the agent, preserving its terminal endpoint, worktree, and
30
+ # every uncommitted change. Interrupts first when the task reads
31
+ # busy, then submits the harness's exit command. Postcondition:
32
+ # the backend's recovery-grade classifier reports the agent gone.
33
+ # Already-stopped is success (idempotent).
34
+ # relaunch Transactionally replace the running agent with a new one, in the
35
+ # SAME endpoint and SAME worktree, on the same or a newly chosen
36
+ # harness/model/effort - so switching harness is one ordinary use
37
+ # of this verb. With no explicit axis, a secondmate re-resolves its
38
+ # durable config/secondmate-harness pin (harness plus its optional
39
+ # model and effort tokens) exactly as any other respawn does, while
40
+ # a ship or scout keeps the exact adapter already recorded for it.
41
+ # A prefixed raw-command basename cannot reconstruct its launch
42
+ # command, so relaunch requires an explicit --harness for it.
43
+ # --note is required for a ship or scout, whose replacement
44
+ # inherits the local copy but none of the conversation; a
45
+ # secondmate reconciles its own home's records at startup, so its
46
+ # standing charter is never rewritten.
47
+ # Records a durable checkpoint and that note, exits the old agent,
48
+ # then delegates the launch to its single owner,
49
+ # bin/fm-spawn.sh --relaunch. A failure before publication keeps
50
+ # the prior durable record in place and reports the concrete
51
+ # state; it never leaves a half-transitioned task claiming to be
52
+ # running.
53
+ #
54
+ # Teardown and discard are NOT verbs here and never will be. `exit` stops an
55
+ # agent and preserves everything else; removing a worktree, killing an
56
+ # endpoint, or discarding work stays with bin/fm-teardown.sh, which owns the
57
+ # landed-work test.
58
+ #
59
+ # `resume` is not a verb: it is not deterministic across the verified adapters
60
+ # (bin/fm-control-lib.sh's header owns that reasoning). `relaunch` covers the
61
+ # same need for every adapter because the brief on disk, not a harness-private
62
+ # session, is the durable instruction.
63
+ #
64
+ # Targeting is EXACT: only a bare task id with a state/<id>.meta record in
65
+ # THIS home is accepted, and the record must pass the shared endpoint-identity
66
+ # validation (bin/fm-backend.sh's fm_backend_validate_task_endpoint). A legacy
67
+ # fm-<id> label, an explicit session:window endpoint, and a bare window name
68
+ # are all refused - a lifecycle command delivered to the wrong endpoint is far
69
+ # worse than a loud refusal.
70
+ #
71
+ # A remotely placed secondmate is refused by name: its agent runs on another
72
+ # host, so no postcondition this plane verifies could be read for it here.
73
+ #
74
+ # Fail-closed boundaries:
75
+ # - An unverified harness, or a harness whose control mechanics are unknown,
76
+ # is refused rather than guessed at.
77
+ # - A backend that cannot deliver the harness's interrupt key is refused
78
+ # (Orca's terminal API has no Escape).
79
+ # - `exit` and `relaunch` require a backend with a recovery-grade agent-state
80
+ # classifier (tmux, herdr), because without one the "the agent stopped"
81
+ # postcondition cannot be proven. zellij, orca, and cmux are refused rather
82
+ # than reported as successful blind.
83
+ # - An ambiguous or unreadable endpoint state refuses; only a positively
84
+ # classified state acts.
85
+ #
86
+ # Environment knobs (all bounded waits, seconds):
87
+ # FM_CONTROL_POLL poll interval for postcondition waits (0.5)
88
+ # FM_CONTROL_SETTLE_WAIT adapter acknowledgement wait after interrupt (5)
89
+ # FM_CONTROL_EXIT_WAIT alive->dead wait after the exit command (30)
90
+ # FM_CONTROL_LAUNCH_WAIT dead->alive wait after a relaunch (90)
91
+ # FM_CONTROL_EXIT_RETRIES Enter retries for the exit command (3)
92
+ set -eu
93
+
94
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
95
+ FM_ROOT="${FM_ROOT_OVERRIDE:-$(cd "$SCRIPT_DIR/.." && pwd)}"
96
+
97
+ usage() {
98
+ # The whole leading comment block, ending at the first non-comment line.
99
+ sed -n '2,${/^#/!q;p;}' "$0" | sed 's/^# \{0,1\}//'
100
+ }
101
+
102
+ case "${1:-}" in
103
+ -h|--help) usage; exit 0 ;;
104
+ esac
105
+
106
+ # shellcheck source=bin/fm-gate-refuse-lib.sh
107
+ . "$SCRIPT_DIR/fm-gate-refuse-lib.sh"
108
+ # Fail closed before any fleet mutation: a no-mistakes gate agent must never
109
+ # drive a crewmate's lifecycle (see bin/fm-gate-refuse-lib.sh).
110
+ fm_refuse_if_gate_agent
111
+
112
+ if [ -z "${FM_HOME+x}" ] || [ -z "${FM_HOME:-}" ]; then
113
+ echo "error: FM_HOME is not set; fm-control refuses to resolve a task without an explicit firstmate home" >&2
114
+ exit 1
115
+ fi
116
+ [ -d "$FM_HOME" ] || {
117
+ echo "error: FM_HOME '$FM_HOME' is not a directory" >&2
118
+ exit 1
119
+ }
120
+ STATE="${FM_STATE_OVERRIDE:-$FM_HOME/state}"
121
+ DATA="${FM_DATA_OVERRIDE:-$FM_HOME/data}"
122
+ [ -d "$STATE" ] || {
123
+ echo "error: state dir '$STATE' is missing; fm-control cannot resolve tasks for FM_HOME '$FM_HOME'" >&2
124
+ exit 1
125
+ }
126
+
127
+ # shellcheck source=bin/fm-backend.sh
128
+ . "$SCRIPT_DIR/fm-backend.sh"
129
+ # shellcheck source=bin/fm-busy-lib.sh
130
+ . "$SCRIPT_DIR/fm-busy-lib.sh"
131
+ # shellcheck source=bin/fm-control-lib.sh
132
+ . "$SCRIPT_DIR/fm-control-lib.sh"
133
+ # shellcheck source=bin/fm-pr-lib.sh
134
+ . "$SCRIPT_DIR/fm-pr-lib.sh"
135
+ # shellcheck source=bin/fm-wake-lib.sh
136
+ . "$SCRIPT_DIR/fm-wake-lib.sh"
137
+
138
+ POLL=${FM_CONTROL_POLL:-0.5}
139
+ SETTLE_WAIT=${FM_CONTROL_SETTLE_WAIT:-5}
140
+ EXIT_WAIT=${FM_CONTROL_EXIT_WAIT:-30}
141
+ LAUNCH_WAIT=${FM_CONTROL_LAUNCH_WAIT:-90}
142
+ EXIT_RETRIES=${FM_CONTROL_EXIT_RETRIES:-3}
143
+
144
+ die() { # <message>
145
+ echo "error: $1" >&2
146
+ exit 1
147
+ }
148
+
149
+ CONTROL_LOCK=
150
+ CONTROL_LOCK_HELD=0
151
+ RELAUNCH_ACTIVE=0
152
+ RELAUNCH_PHASE=start
153
+
154
+ control_cleanup() {
155
+ local status=$?
156
+ if [ "$RELAUNCH_ACTIVE" = 1 ] \
157
+ && declare -F relaunch_rollback >/dev/null 2>&1; then
158
+ relaunch_rollback || true
159
+ fi
160
+ if [ "$CONTROL_LOCK_HELD" = 1 ]; then
161
+ CONTROL_LOCK_HELD=0
162
+ fm_lock_release "$CONTROL_LOCK" || true
163
+ fi
164
+ if declare -F fm_lease_guard_release >/dev/null 2>&1; then
165
+ fm_lease_guard_release || true
166
+ fi
167
+ return "$status"
168
+ }
169
+
170
+ # --- argument parsing -------------------------------------------------------
171
+
172
+ RAW_ID=${1:-}
173
+ VERB=${2:-}
174
+ [ -n "$RAW_ID" ] && [ -n "$VERB" ] || { usage >&2; exit 2; }
175
+ shift 2
176
+
177
+ if ! fm_control_verb_allowed "$VERB"; then
178
+ {
179
+ if [ "$VERB" = resume ]; then
180
+ echo "error: 'resume' is not a control verb: resuming an exited agent is not deterministic across the verified adapters (codex and grok need a session id printed at exit, opencode continues the most recent session for the cwd, and claude, pi, pi-signed, and kimi have no verified pane-resume contract). Use 'relaunch', which carries the brief plus a progress note into a fresh agent on any adapter."
181
+ else
182
+ echo "error: '$VERB' is not a control verb"
183
+ fi
184
+ echo "allowed verbs:"
185
+ fm_control_verbs | sed 's/^/ /'
186
+ } >&2
187
+ exit 2
188
+ fi
189
+
190
+ NEW_HARNESS=
191
+ NEW_MODEL=
192
+ NEW_EFFORT=
193
+ HARNESS_SET=0
194
+ MODEL_SET=0
195
+ EFFORT_SET=0
196
+ NOTE=
197
+ NOTE_SET=0
198
+ control_want_value=
199
+ for control_arg in "$@"; do
200
+ if [ -n "$control_want_value" ]; then
201
+ case "$control_arg" in
202
+ --*) die "--$control_want_value requires a value" ;;
203
+ esac
204
+ case "$control_want_value" in
205
+ harness) NEW_HARNESS=$control_arg; HARNESS_SET=1 ;;
206
+ model) NEW_MODEL=$control_arg; MODEL_SET=1 ;;
207
+ effort) NEW_EFFORT=$control_arg; EFFORT_SET=1 ;;
208
+ note) NOTE=$control_arg; NOTE_SET=1 ;;
209
+ note_file)
210
+ [ -f "$control_arg" ] || die "--note-file '$control_arg' is not a readable file"
211
+ NOTE=$(cat "$control_arg")
212
+ NOTE_SET=1
213
+ ;;
214
+ esac
215
+ control_want_value=
216
+ continue
217
+ fi
218
+ case "$control_arg" in
219
+ --harness) control_want_value=harness ;;
220
+ --harness=*) NEW_HARNESS=${control_arg#--harness=}; HARNESS_SET=1 ;;
221
+ --model) control_want_value=model ;;
222
+ --model=*) NEW_MODEL=${control_arg#--model=}; MODEL_SET=1 ;;
223
+ --effort) control_want_value=effort ;;
224
+ --effort=*) NEW_EFFORT=${control_arg#--effort=}; EFFORT_SET=1 ;;
225
+ --note) control_want_value=note ;;
226
+ --note=*) NOTE=${control_arg#--note=}; NOTE_SET=1 ;;
227
+ --note-file) control_want_value=note_file ;;
228
+ --note-file=*)
229
+ [ -f "${control_arg#--note-file=}" ] || die "--note-file '${control_arg#--note-file=}' is not a readable file"
230
+ NOTE=$(cat "${control_arg#--note-file=}")
231
+ NOTE_SET=1
232
+ ;;
233
+ *) die "unexpected argument '$control_arg'" ;;
234
+ esac
235
+ done
236
+ if [ -n "$control_want_value" ]; then
237
+ [ "$control_want_value" = note_file ] && die "--note-file requires a value"
238
+ die "--$control_want_value requires a value"
239
+ fi
240
+
241
+ if [ "$VERB" != relaunch ]; then
242
+ [ "$HARNESS_SET" = 0 ] && [ "$MODEL_SET" = 0 ] && [ "$EFFORT_SET" = 0 ] && [ "$NOTE_SET" = 0 ] \
243
+ || die "--harness, --model, --effort, and --note apply to 'relaunch' only"
244
+ fi
245
+ [ "$HARNESS_SET" = 0 ] || [ -n "$NEW_HARNESS" ] || die "--harness requires a non-empty value"
246
+ [ "$MODEL_SET" = 0 ] || [ -n "$NEW_MODEL" ] || die "--model requires a non-empty value"
247
+ [ "$EFFORT_SET" = 0 ] || [ -n "$NEW_EFFORT" ] || die "--effort requires a non-empty value"
248
+ case "$NEW_EFFORT" in
249
+ ''|low|medium|high|xhigh|max) ;;
250
+ *) die "--effort must be one of low, medium, high, xhigh, max" ;;
251
+ esac
252
+
253
+ # --- exact task-id resolution ----------------------------------------------
254
+
255
+ case "$RAW_ID" in
256
+ *:*) die "'$RAW_ID' is an explicit backend endpoint; fm-control accepts an exact task id only, so a lifecycle command can never land on an endpoint this home does not own" ;;
257
+ esac
258
+ if ! fm_task_id_creation_valid "$RAW_ID"; then
259
+ die "'$RAW_ID' is not a valid task id"
260
+ fi
261
+ ID=$RAW_ID
262
+ # Supervision lease guard: lifecycle control is overlap territory between the
263
+ # two Pi supervision actors; refuse while the OTHER actor holds this task's
264
+ # live lease (contract: bin/fm-lease-lib.sh; no-op in homes without leases).
265
+ # shellcheck source=bin/fm-lease-lib.sh
266
+ . "$SCRIPT_DIR/fm-lease-lib.sh"
267
+ fm_lease_guard "$ID" "lifecycle control (fm-control)"
268
+ CONTROL_LOCK="$STATE/.control-$ID.lock"
269
+ trap control_cleanup EXIT
270
+ fm_lock_try_acquire "$CONTROL_LOCK" \
271
+ || die "another lifecycle action is already running for task $ID"
272
+ CONTROL_LOCK_HELD=1
273
+ META="$STATE/$ID.meta"
274
+ if [ ! -f "$META" ]; then
275
+ case "$RAW_ID" in
276
+ fm-*)
277
+ if [ -f "$STATE/${RAW_ID#fm-}.meta" ]; then
278
+ die "'$RAW_ID' is a window label, not a task id; pass the exact task id '${RAW_ID#fm-}'"
279
+ fi
280
+ ;;
281
+ esac
282
+ die "no task '$ID' in $STATE (fm-control resolves an exact task id only)"
283
+ fi
284
+
285
+ # A remotely placed secondmate records its endpoint on ANOTHER host, so every
286
+ # postcondition this plane verifies - the agent-state classification, the busy
287
+ # verdict, the endpoint's existence - would be read here for an endpoint that
288
+ # does not live here. Endpoint validation already refuses such a record, since
289
+ # `window=remote:<id>` can never match a local backend's required shape, so
290
+ # nothing can be delivered to a wrong endpoint either way. What that refusal
291
+ # cannot say is WHY, and "malformed metadata" is the wrong thing to tell an
292
+ # operator about a correctly configured remote route. Name the placement
293
+ # instead, using the same `remote_host` signal bin/fm-send.sh routes on.
294
+ if [ -n "$(fm_meta_get "$META" remote_host)" ]; then
295
+ die "task $ID is a remotely placed secondmate on $(fm_meta_get "$META" remote_host); its agent runs outside this home, so no lifecycle action here could verify that it interrupted, stopped, or came back. Drive its lifecycle on that host, and reconcile it through the secondmate recovery path rather than this plane"
296
+ fi
297
+
298
+ fm_backend_validate_task_endpoint "$META" "$ID" || exit 1
299
+ BACKEND=$FM_BACKEND_VALIDATED_BACKEND
300
+ T=$FM_BACKEND_VALIDATED_TARGET
301
+ LABEL="fm-$ID"
302
+ RECORDED_HARNESS=$(fm_meta_get "$META" harness)
303
+ KIND=$(fm_meta_get "$META" kind)
304
+ WT=$(fm_meta_get "$META" worktree)
305
+ [ -n "$KIND" ] || KIND=ship
306
+
307
+ HARNESS=$(fm_control_harness_family "$RECORDED_HARNESS") \
308
+ || die "task $ID records harness '${RECORDED_HARNESS:-none}', which has no verified control mechanics; fm-control refuses to guess an interrupt key or exit command"
309
+ fm_control_harness_supported "$HARNESS" \
310
+ || die "task $ID records harness '${RECORDED_HARNESS:-none}', which has no verified control mechanics; fm-control refuses to guess an interrupt key or exit command"
311
+
312
+ fm_backend_validate "$BACKEND" || exit 1
313
+
314
+ # --- shared helpers ---------------------------------------------------------
315
+
316
+ agent_state() {
317
+ fm_backend_agent_state "$BACKEND" "$T"
318
+ }
319
+
320
+ busy_verdict() {
321
+ fm_busy_classify_meta "$META" "$ID" "$STATE"
322
+ }
323
+
324
+ # wait_agent_state <wanted...> <timeout>: poll until agent_state prints one of
325
+ # the wanted values. Prints the final observed state; returns 0 on a match.
326
+ wait_agent_state() { # <timeout> <wanted>...
327
+ local timeout=$1 state want elapsed=0
328
+ shift
329
+ while :; do
330
+ state=$(agent_state)
331
+ for want in "$@"; do
332
+ if [ "$state" = "$want" ]; then
333
+ printf '%s' "$state"
334
+ return 0
335
+ fi
336
+ done
337
+ awk -v e="$elapsed" -v t="$timeout" 'BEGIN{exit !(e < t)}' || break
338
+ sleep "$POLL"
339
+ elapsed=$(awk -v e="$elapsed" -v p="$POLL" 'BEGIN{printf "%.3f", e + p}')
340
+ done
341
+ printf '%s' "$state"
342
+ return 1
343
+ }
344
+
345
+ require_state_verified_backend() { # <verb>
346
+ fm_control_backend_state_verified "$BACKEND" && return 0
347
+ die "task $ID runs on the $BACKEND backend, which has no recovery-grade agent-state classifier, so '$1' cannot prove the agent actually stopped; refusing rather than reporting an unproven transition as done"
348
+ }
349
+
350
+ # send_interrupt_keys: deliver the harness's interrupt key the verified number
351
+ # of times, then the composer-clear key when the adapter needs one. Refuses
352
+ # before sending anything when the backend cannot deliver either key, because
353
+ # an interrupt that cancels the turn but leaves the restored prompt in the
354
+ # composer would make the next submitted line concatenate onto it.
355
+ send_interrupt_keys() {
356
+ local key repeat clear i=0
357
+ key=$(fm_control_interrupt_key "$HARNESS")
358
+ repeat=$(fm_control_interrupt_repeat "$HARNESS")
359
+ clear=$(fm_control_interrupt_clear_key "$HARNESS")
360
+ fm_control_backend_supports_key "$BACKEND" "$key" \
361
+ || die "harness $HARNESS interrupts with $key, which the $BACKEND backend cannot deliver; refusing to send a different key"
362
+ [ -z "$clear" ] || fm_control_backend_supports_key "$BACKEND" "$clear" \
363
+ || die "harness $HARNESS needs $clear to clear its composer after an interrupt, which the $BACKEND backend cannot deliver; refusing to leave the cancelled prompt where the next submitted line would concatenate onto it"
364
+ while [ "$i" -lt "$repeat" ]; do
365
+ fm_backend_send_key "$BACKEND" "$T" "$key" "$LABEL" \
366
+ || die "interrupt key $key was not delivered to task $ID on $BACKEND"
367
+ i=$((i + 1))
368
+ [ "$i" -ge "$repeat" ] || sleep 0.2
369
+ done
370
+ [ -z "$clear" ] || fm_backend_send_key "$BACKEND" "$T" "$clear" "$LABEL" \
371
+ || die "interrupt key $key reached task $ID, but $clear did not, so its composer still holds the cancelled prompt; clear it before the next lifecycle action"
372
+ }
373
+
374
+ prepare_interrupt_ack() {
375
+ INTERRUPT_ACK_SOURCE=$(fm_control_interrupt_ack_source "$HARNESS")
376
+ INTERRUPT_ACK_LOG=
377
+ INTERRUPT_ACK_RUN=
378
+ case "$INTERRUPT_ACK_SOURCE" in
379
+ muse-session-terminal)
380
+ INTERRUPT_ACK_LOG=$(fm_busy_muse_session_log "$STATE" "$ID" 2>/dev/null || true)
381
+ [ -n "$INTERRUPT_ACK_LOG" ] || return 0
382
+ INTERRUPT_ACK_RUN=$(fm_busy_muse_active_run_id "$INTERRUPT_ACK_LOG" 2>/dev/null || true)
383
+ ;;
384
+ esac
385
+ }
386
+
387
+ interrupt_cancel_claim() {
388
+ local elapsed=0 terminal=
389
+ case "$INTERRUPT_ACK_SOURCE:$INTERRUPT_ACK_RUN" in
390
+ muse-session-terminal:?*) ;;
391
+ *) printf 'unconfirmed'; return 0 ;;
392
+ esac
393
+ while :; do
394
+ terminal=$(fm_busy_muse_run_terminal "$INTERRUPT_ACK_LOG" "$INTERRUPT_ACK_RUN" 2>/dev/null || true)
395
+ case "$terminal" in
396
+ cancelled) printf 'confirmed'; return 0 ;;
397
+ ?*) printf 'unconfirmed'; return 0 ;;
398
+ esac
399
+ awk -v e="$elapsed" -v t="$SETTLE_WAIT" 'BEGIN{exit !(e < t)}' || break
400
+ sleep "$POLL"
401
+ elapsed=$(awk -v e="$elapsed" -v p="$POLL" 'BEGIN{printf "%.3f", e + p}')
402
+ done
403
+ printf 'unconfirmed'
404
+ }
405
+
406
+ # deliver_interrupt: deliver and observe the strongest adapter-owned
407
+ # cancellation claim available after delivery.
408
+ deliver_interrupt() {
409
+ local cancel
410
+ prepare_interrupt_ack
411
+ send_interrupt_keys
412
+ cancel=$(interrupt_cancel_claim)
413
+ printf '%s' "$cancel"
414
+ }
415
+
416
+ verify_interrupt_running() {
417
+ local proof after
418
+ fm_backend_target_exists "$BACKEND" "$T" "$LABEL" \
419
+ || die "task $ID's endpoint disappeared while interrupting it; no further control action is safe"
420
+ proof=endpoint
421
+ if fm_control_backend_state_verified "$BACKEND"; then
422
+ # An interrupt cancels a turn; it must never have stopped the agent. This
423
+ # is the postcondition that separates a landed interrupt from an accident.
424
+ after=$(agent_state)
425
+ [ "$after" = alive ] \
426
+ || die "task $ID's agent is '$after' after its interrupt key; an interrupt must leave the agent running"
427
+ proof=agent-alive
428
+ fi
429
+ printf '%s' "$proof"
430
+ }
431
+
432
+ do_interrupt() {
433
+ local proof cancel
434
+ cancel=$(deliver_interrupt) || return $?
435
+ proof=$(verify_interrupt_running) || return $?
436
+ printf '%s cancel=%s' "$proof" "$cancel"
437
+ }
438
+
439
+ retire_busy_incarnation() {
440
+ if [ -f "$STATE/$ID.busy-gen" ]; then
441
+ "$SCRIPT_DIR/fm-busy-event.sh" retire "$STATE" "$ID" --current-gen >/dev/null 2>&1 || true
442
+ fi
443
+ }
444
+
445
+ # do_exit: stop the running agent, preserving endpoint and worktree. Prints
446
+ # `already-stopped` or `stopped`.
447
+ do_exit() {
448
+ local state cmd verdict cancel interrupt_result=not-needed
449
+ require_state_verified_backend exit
450
+ state=$(agent_state)
451
+ case "$state" in
452
+ dead)
453
+ printf 'already-stopped'
454
+ return 0
455
+ ;;
456
+ alive) ;;
457
+ missing) die "task $ID's recorded endpoint is gone, so there is no agent to stop; reconcile the task before any further control action" ;;
458
+ *) die "task $ID's endpoint reads '$state' rather than a positively classified state; refusing to send a lifecycle command into an unattributed endpoint" ;;
459
+ esac
460
+ # A busy agent is interrupted first before the exit command is submitted.
461
+ case "$(busy_verdict)" in
462
+ busy*)
463
+ cancel=$(deliver_interrupt) || return $?
464
+ state=$(agent_state)
465
+ case "$state" in
466
+ dead)
467
+ retire_busy_incarnation
468
+ printf 'stopped'
469
+ return 0
470
+ ;;
471
+ alive) interrupt_result="delivered verified=agent-alive cancel=$cancel" ;;
472
+ missing) die "task $ID's recorded endpoint disappeared after interrupt delivery, so exit cannot prove whether the agent stopped" ;;
473
+ *) die "task $ID's endpoint reads '$state' after interrupt delivery rather than a positively classified state; exit cannot prove whether the agent stopped" ;;
474
+ esac
475
+ ;;
476
+ esac
477
+ cmd=$(fm_control_exit_command "$HARNESS")
478
+ # The submit verdict is NOT the postcondition here: a successful exit command
479
+ # destroys the composer the verdict is read from, so a post-exit read can
480
+ # legitimately report anything. Only a hard transport failure aborts; the
481
+ # authoritative proof is the agent-state wait below. The retried Enter still
482
+ # matters, because a slash command opens a completion popup on some TUIs that
483
+ # swallows the first Enter.
484
+ verdict=$(fm_backend_send_text_submit "$BACKEND" "$T" "$cmd" "$EXIT_RETRIES" "$POLL" 1.2 "$LABEL") \
485
+ || die "the exit command could not be sent to task $ID on $BACKEND"
486
+ [ "$verdict" != send-failed ] \
487
+ || die "the exit command could not be sent to task $ID on $BACKEND"
488
+ state=$(wait_agent_state "$EXIT_WAIT" dead) || {
489
+ die "exit-delivered $ID interrupt=$interrupt_result exit-command=delivered agent-state=$state exit=unconfirmed; the agent did not stop within ${EXIT_WAIT}s"
490
+ }
491
+ # The incarnation is over: retire its busy wiring so no stale record or
492
+ # orphaned generation survives the agent that produced it.
493
+ retire_busy_incarnation
494
+ printf 'stopped'
495
+ }
496
+
497
+ # --- transactional relaunch -------------------------------------------------
498
+ #
499
+ # The transaction's durable record is state/<id>.control-relaunch, with the
500
+ # prior metadata and brief preserved beside it. Every failure path runs through
501
+ # relaunch_rollback (an EXIT trap, so a refusal raised deep inside a shared
502
+ # helper is covered too) and leaves either the pre-relaunch durable record or a
503
+ # concrete, named partial state - never a task whose record claims an agent
504
+ # that is not running.
505
+
506
+ JOURNAL="$STATE/$ID.control-relaunch"
507
+ META_PRIOR="$JOURNAL.meta-prior"
508
+ BRIEF_PRIOR="$JOURNAL.brief-prior"
509
+ NOTE_FILE="$JOURNAL.note"
510
+ RELAUNCH_META_PUBLISHED=0
511
+ RELAUNCH_AGENT_CONFIRMED=0
512
+ RELAUNCH_TX=
513
+ RELAUNCH_BRIEF=
514
+ PRIOR_HARNESS=$HARNESS
515
+ PRIOR_RECORDED_HARNESS=$RECORDED_HARNESS
516
+ CONFIG_HARNESS=
517
+ CONFIG_MODEL=
518
+ CONFIG_EFFORT=
519
+ PRIOR_MODEL=
520
+ PRIOR_EFFORT=
521
+ TARGET_HARNESS=$HARNESS
522
+ TARGET_MODEL=
523
+ TARGET_EFFORT=
524
+
525
+ journal_write() { # <phase> [extra-line]...
526
+ local phase=$1
527
+ shift
528
+ if {
529
+ echo "v1"
530
+ echo "task=$ID"
531
+ echo "phase=$phase"
532
+ echo "ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
533
+ echo "backend=$BACKEND"
534
+ echo "endpoint=$T"
535
+ echo "worktree=$WT"
536
+ echo "kind=$KIND"
537
+ echo "from_harness=$PRIOR_RECORDED_HARNESS"
538
+ echo "from_model=$PRIOR_MODEL"
539
+ echo "from_effort=$PRIOR_EFFORT"
540
+ echo "to_harness=$TARGET_HARNESS"
541
+ echo "to_model=$TARGET_MODEL"
542
+ echo "to_effort=$TARGET_EFFORT"
543
+ local line
544
+ for line in "$@"; do
545
+ echo "$line"
546
+ done
547
+ } > "$JOURNAL.tmp" && mv -f "$JOURNAL.tmp" "$JOURNAL"; then
548
+ RELAUNCH_PHASE=$phase
549
+ return 0
550
+ fi
551
+ return 1
552
+ }
553
+
554
+ relaunch_rollback() {
555
+ local state
556
+ [ "$RELAUNCH_ACTIVE" = 1 ] || return 0
557
+ [ "$RELAUNCH_PHASE" != complete ] || return 0
558
+ RELAUNCH_ACTIVE=0
559
+ case "$RELAUNCH_PHASE" in
560
+ checkpoint|noted)
561
+ # The old agent was never touched. Restore the instructions byte-exact so
562
+ # a refused relaunch leaves nothing behind.
563
+ if [ -n "$RELAUNCH_BRIEF" ] && [ -f "$BRIEF_PRIOR" ]; then
564
+ cp -p "$BRIEF_PRIOR" "$RELAUNCH_BRIEF" 2>/dev/null || true
565
+ fi
566
+ journal_write "failed:$RELAUNCH_PHASE" "rollback=instructions-restored" || true
567
+ echo "error: relaunch of $ID was refused before its agent was touched; nothing changed" >&2
568
+ ;;
569
+ stopping)
570
+ state=$(agent_state 2>/dev/null || printf unknown)
571
+ case "$state" in
572
+ alive)
573
+ if [ -n "$RELAUNCH_BRIEF" ] && [ -f "$BRIEF_PRIOR" ]; then
574
+ cp -p "$BRIEF_PRIOR" "$RELAUNCH_BRIEF" 2>/dev/null || true
575
+ fi
576
+ journal_write "failed:$RELAUNCH_PHASE" "rollback=instructions-restored-agent-alive" || true
577
+ echo "error: relaunch of $ID failed while stopping the old agent, which is still running; its original instructions were restored" >&2
578
+ ;;
579
+ dead)
580
+ journal_write "failed:$RELAUNCH_PHASE" "rollback=prior-record-kept-agent-dead" || true
581
+ echo "error: $ID's agent stopped but relaunch did not reach replacement launch; no agent is running, and its work plus progress note are preserved at $WT" >&2
582
+ ;;
583
+ *)
584
+ journal_write "failed:$RELAUNCH_PHASE" "rollback=none-agent-state-$state" || true
585
+ echo "error: relaunch of $ID failed while stopping the old agent and its state is '$state'; the durable record and progress note were retained for recovery" >&2
586
+ ;;
587
+ esac
588
+ ;;
589
+ exited|launching)
590
+ if [ "$RELAUNCH_AGENT_CONFIRMED" = 1 ]; then
591
+ journal_write "failed:$RELAUNCH_PHASE" "rollback=none-new-agent-confirmed" || true
592
+ echo "error: $ID's replacement is running on $TARGET_HARNESS, but transaction completion could not be persisted; its published record was retained for reconciliation" >&2
593
+ elif [ "$RELAUNCH_META_PUBLISHED" = 1 ] \
594
+ || { [ -n "$RELAUNCH_TX" ] \
595
+ && [ "$(fm_meta_get "$META" control_relaunch_tx)" = "$RELAUNCH_TX" ]; }; then
596
+ # The launch owner published the new incarnation's record. Leaving it
597
+ # in place is the honest state: the task is now recorded on the new
598
+ # harness with no agent confirmed, which is exactly what recovery
599
+ # reconciles. Rewriting it back to the old harness would be a second,
600
+ # worse inaccuracy.
601
+ journal_write "failed:$RELAUNCH_PHASE" "rollback=none-new-record-kept" || true
602
+ echo "error: $ID was relaunched on $TARGET_HARNESS but no running agent could be confirmed; its work is preserved at $WT" >&2
603
+ else
604
+ journal_write "failed:$RELAUNCH_PHASE" "rollback=prior-record-kept" || true
605
+ echo "error: $ID's agent was stopped but the replacement did not launch; no agent is running, and its work plus the recorded progress note are preserved at $WT" >&2
606
+ fi
607
+ ;;
608
+ esac
609
+ return 0
610
+ }
611
+
612
+ resolve_relaunch_profile() {
613
+ PRIOR_HARNESS=$HARNESS
614
+ PRIOR_RECORDED_HARNESS=$RECORDED_HARNESS
615
+ PRIOR_MODEL=$(fm_meta_get "$META" model)
616
+ PRIOR_EFFORT=$(fm_meta_get "$META" effort)
617
+ [ -n "$PRIOR_MODEL" ] || PRIOR_MODEL=default
618
+ [ -n "$PRIOR_EFFORT" ] || PRIOR_EFFORT=default
619
+ if [ "$HARNESS_SET" = 0 ] \
620
+ && [ "$PRIOR_RECORDED_HARNESS" != "$PRIOR_HARNESS" ]; then
621
+ die "task $ID records harness '$PRIOR_RECORDED_HARNESS', whose original launch command cannot be reconstructed from its recorded basename; relaunching without --harness would substitute the canonical adapter '$PRIOR_HARNESS' for the command actually running. Pass an explicit --harness to choose the replacement runtime deliberately"
622
+ fi
623
+ CONFIG_HARNESS=
624
+ CONFIG_MODEL=
625
+ CONFIG_EFFORT=
626
+ if [ "$KIND" = secondmate ]; then
627
+ # A secondmate's harness, model, and effort are a durable configured pin
628
+ # that every respawn re-resolves (the secondmate-provisioning contract), so
629
+ # a relaunch with no explicit harness picks up a newly configured one
630
+ # instead of freezing whatever this incarnation happens to run. Crewmates
631
+ # and scouts deliberately do NOT resolve config here: their harness comes
632
+ # from firstmate's own dispatch-profile judgment at intake, and silently
633
+ # re-resolving it would bypass that consultation.
634
+ CONFIG_HARNESS=$("$SCRIPT_DIR/fm-harness.sh" secondmate 2>/dev/null || true)
635
+ CONFIG_MODEL=$("$SCRIPT_DIR/fm-harness.sh" secondmate-model 2>/dev/null || true)
636
+ CONFIG_EFFORT=$("$SCRIPT_DIR/fm-harness.sh" secondmate-effort 2>/dev/null || true)
637
+ case "$CONFIG_EFFORT" in
638
+ ''|low|medium|high|xhigh|max) ;;
639
+ *)
640
+ echo "warning: config/secondmate-harness effort token '$CONFIG_EFFORT' is not one of low, medium, high, xhigh, max; ignoring" >&2
641
+ CONFIG_EFFORT=
642
+ ;;
643
+ esac
644
+ fi
645
+ if [ "$HARNESS_SET" = 1 ]; then
646
+ fm_control_harness_supported "$NEW_HARNESS" \
647
+ || die "'$NEW_HARNESS' is not a verified harness; fm-control refuses to relaunch onto an adapter with no verified control or launch mechanics"
648
+ TARGET_HARNESS=$NEW_HARNESS
649
+ elif [ "$HARNESS_SET" = 0 ] && [ -n "$CONFIG_HARNESS" ]; then
650
+ fm_control_harness_supported "$CONFIG_HARNESS" \
651
+ || die "the configured secondmate harness '$CONFIG_HARNESS' is not verified; fm-control refuses to relaunch onto an adapter with no verified control or launch mechanics"
652
+ TARGET_HARNESS=$CONFIG_HARNESS
653
+ else
654
+ TARGET_HARNESS=$PRIOR_HARNESS
655
+ fi
656
+ # The launch owner refuses an adapter that cannot run this task's kind, but it
657
+ # is only reached after the old agent has been stopped. Asking the same
658
+ # capability table here keeps that refusal on the pre-stop side of the
659
+ # transaction, where nothing has changed yet.
660
+ fm_control_harness_supports_kind "$TARGET_HARNESS" "$KIND" \
661
+ || die "'$TARGET_HARNESS' is not verified to run a $KIND task, so relaunching $ID onto it would stop the running agent for a launch that must be refused; choose an adapter verified for this kind"
662
+ # A model or effort chosen for the previous harness does not transfer to a
663
+ # different one, so an explicit harness change resets both axes unless the
664
+ # caller names them too.
665
+ if [ "$MODEL_SET" = 1 ]; then
666
+ TARGET_MODEL=$NEW_MODEL
667
+ elif [ "$HARNESS_SET" = 0 ] && [ -n "$CONFIG_HARNESS" ]; then
668
+ TARGET_MODEL=${CONFIG_MODEL:-default}
669
+ elif [ "$TARGET_HARNESS" = "$PRIOR_HARNESS" ]; then
670
+ TARGET_MODEL=$PRIOR_MODEL
671
+ else
672
+ TARGET_MODEL=default
673
+ fi
674
+ if [ "$EFFORT_SET" = 1 ]; then
675
+ TARGET_EFFORT=$NEW_EFFORT
676
+ elif [ "$HARNESS_SET" = 0 ] && [ -n "$CONFIG_HARNESS" ]; then
677
+ TARGET_EFFORT=${CONFIG_EFFORT:-default}
678
+ elif [ "$TARGET_HARNESS" = "$PRIOR_HARNESS" ]; then
679
+ TARGET_EFFORT=$PRIOR_EFFORT
680
+ else
681
+ TARGET_EFFORT=default
682
+ fi
683
+ }
684
+
685
+ # safe_checkpoint: prove, before anything is stopped, that the work a relaunch
686
+ # must preserve is actually there and recoverable afterwards. Fills
687
+ # CHECKPOINT_LINES with the journal lines describing what it proved, and
688
+ # refuses outright when any of it cannot be established.
689
+ CHECKPOINT_LINES=()
690
+ safe_checkpoint() {
691
+ local wt_real wt_top wt_top_real head head_ref head_ref_status status_output dirty children marker child_meta
692
+ CHECKPOINT_LINES=()
693
+ [ -n "$WT" ] || die "task $ID has no recorded worktree; refusing to relaunch without a recorded local copy to preserve"
694
+ [ -d "$WT" ] || die "task $ID's recorded worktree $WT is missing; refusing to relaunch and lose track of its work"
695
+ wt_real=$(cd "$WT" 2>/dev/null && pwd -P) || die "task $ID's recorded worktree $WT cannot be resolved"
696
+ wt_top=$(git -C "$WT" rev-parse --show-toplevel 2>/dev/null) \
697
+ || die "task $ID's recorded worktree $WT is not a git worktree; refusing to relaunch without a checkout whose unlanded work can be accounted for"
698
+ wt_top_real=$(cd "$wt_top" 2>/dev/null && pwd -P) || wt_top_real=$wt_top
699
+ [ "$wt_real" = "$wt_top_real" ] \
700
+ || die "task $ID's recorded worktree $WT is not a worktree root (root is $wt_top); refusing to relaunch against an ambiguous checkout"
701
+ if head=$(git -C "$WT" rev-parse --verify HEAD 2>/dev/null); then
702
+ :
703
+ elif head_ref=$(git -C "$WT" symbolic-ref -q HEAD 2>/dev/null); then
704
+ if git -C "$WT" show-ref --verify --quiet "$head_ref" 2>/dev/null; then
705
+ die "task $ID's worktree HEAD exists but cannot be resolved; refusing to relaunch from an unreadable checkout"
706
+ else
707
+ head_ref_status=$?
708
+ [ "$head_ref_status" -eq 1 ] \
709
+ || die "task $ID's worktree HEAD cannot be inspected; refusing to relaunch from an unreadable checkout"
710
+ head=unborn
711
+ fi
712
+ else
713
+ die "task $ID's worktree HEAD cannot be inspected; refusing to relaunch from an unreadable checkout"
714
+ fi
715
+ status_output=$(git -C "$WT" status --porcelain 2>/dev/null) \
716
+ || die "task $ID's worktree status cannot be inspected; refusing to relaunch without accounting for local changes"
717
+ if [ -n "$status_output" ]; then
718
+ dirty=yes
719
+ else
720
+ dirty=no
721
+ fi
722
+ CHECKPOINT_LINES+=("worktree_head=$head" "worktree_dirty=$dirty")
723
+ if [ "$KIND" = secondmate ]; then
724
+ # A secondmate's own crewmates outlive its relaunch: they run in their own
725
+ # endpoints, and the relaunched secondmate reconciles them from its home's
726
+ # durable records at startup. The checkpoint proves those records are
727
+ # readable BEFORE the agent stops, so a relaunch can never strand child
728
+ # work behind an unreadable home.
729
+ marker=$(cat "$WT/.fm-secondmate-home" 2>/dev/null || true)
730
+ [ "$marker" = "$ID" ] \
731
+ || die "task $ID's home $WT is not marked as its own seeded secondmate home (marker: ${marker:-none}); refusing to relaunch"
732
+ [ -d "$WT/state" ] \
733
+ || die "secondmate $ID's home has no readable state directory, so its child work cannot be accounted for; refusing to relaunch"
734
+ find "$WT/state" -mindepth 1 -maxdepth 1 -print >/dev/null 2>&1 \
735
+ || die "secondmate $ID's child records cannot be traversed; refusing to relaunch"
736
+ children=0
737
+ for child_meta in "$WT/state"/*.meta; do
738
+ if [ ! -e "$child_meta" ] && [ ! -L "$child_meta" ]; then
739
+ continue
740
+ fi
741
+ if [ ! -f "$child_meta" ] || [ -L "$child_meta" ] \
742
+ || ! cat "$child_meta" >/dev/null 2>&1; then
743
+ die "secondmate $ID's child record $child_meta is not a readable regular file; refusing to relaunch"
744
+ fi
745
+ children=$((children + 1))
746
+ done
747
+ CHECKPOINT_LINES+=("children=$children")
748
+ fi
749
+ }
750
+
751
+ # record_note: put the required progress note somewhere durable, and - for a
752
+ # ship or scout, whose only record of the interrupted reasoning is the
753
+ # conversation about to be discarded - into the instructions the replacement
754
+ # actually reads. A secondmate's charter is a durable standing document and is
755
+ # never rewritten: a secondmate reconciles its own home's records at startup,
756
+ # so the note stays parent-side audit evidence.
757
+ record_note() {
758
+ local stamp
759
+ [ -n "$NOTE" ] || return 0
760
+ stamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
761
+ printf '%s\n' "$NOTE" > "$NOTE_FILE"
762
+ case "$KIND" in
763
+ ship|scout)
764
+ cp -p "$RELAUNCH_BRIEF" "$BRIEF_PRIOR" \
765
+ || die "could not preserve task $ID's instructions before recording the progress note"
766
+ {
767
+ echo
768
+ echo "## Progress note ($stamp)"
769
+ echo
770
+ echo "This task was relaunched. Continue from here; the local copy and every"
771
+ echo "uncommitted change are exactly as the previous worker left them."
772
+ echo
773
+ echo "First, check your instruction inbox: list $STATE/$ID.inbox/*.msg, act on"
774
+ echo "each message in numeric order, then mv each handled file into"
775
+ echo "$STATE/$ID.inbox/handled/. A steer sent before the relaunch survives there."
776
+ echo
777
+ printf '%s\n' "$NOTE"
778
+ } >> "$RELAUNCH_BRIEF" \
779
+ || die "could not append the progress note to task $ID's instructions"
780
+ ;;
781
+ esac
782
+ }
783
+
784
+ do_relaunch() {
785
+ local exit_result state note_line
786
+ local -a spawn_args
787
+
788
+ require_state_verified_backend relaunch
789
+ resolve_relaunch_profile
790
+
791
+ case "$KIND" in
792
+ ship|scout)
793
+ RELAUNCH_BRIEF="$DATA/$ID/brief.md"
794
+ [ -f "$RELAUNCH_BRIEF" ] \
795
+ || die "task $ID has no instructions at $RELAUNCH_BRIEF; refusing to relaunch a worker with nothing to work from"
796
+ [ "$NOTE_SET" = 1 ] && [ -n "$NOTE" ] \
797
+ || die "relaunch of a $KIND task requires --note (or --note-file): the replacement worker inherits the local copy but none of the conversation, so it must be told what happened"
798
+ ;;
799
+ secondmate)
800
+ # The charter in the secondmate's own home is its instruction source and
801
+ # stays untouched.
802
+ RELAUNCH_BRIEF=
803
+ ;;
804
+ *)
805
+ die "task $ID records kind '$KIND', which has no defined relaunch shape"
806
+ ;;
807
+ esac
808
+
809
+ if [ -n "$NOTE" ]; then
810
+ note_line="note_file=$NOTE_FILE"
811
+ else
812
+ note_line="note=none"
813
+ fi
814
+ safe_checkpoint
815
+ cp -p "$META" "$META_PRIOR" || die "could not preserve task $ID's durable record before relaunching"
816
+ RELAUNCH_ACTIVE=1
817
+ journal_write checkpoint "${CHECKPOINT_LINES[@]}" "$note_line"
818
+
819
+ record_note
820
+ journal_write noted "${CHECKPOINT_LINES[@]}" "$note_line"
821
+
822
+ journal_write stopping "${CHECKPOINT_LINES[@]}" "$note_line"
823
+ exit_result=$(do_exit)
824
+ journal_write exited "${CHECKPOINT_LINES[@]}" "$note_line" "exit_result=$exit_result"
825
+
826
+ # The launch owner (fm-spawn --relaunch) clears the previous incarnation's
827
+ # per-task harness wiring before arming the new one, so nothing to do here.
828
+ RELAUNCH_TX="${BASHPID:-$$}.$(date -u +%Y%m%dT%H%M%SZ).$RANDOM"
829
+ journal_write launching "${CHECKPOINT_LINES[@]}" "$note_line" "relaunch_tx=$RELAUNCH_TX"
830
+ spawn_args=("$ID" --relaunch --harness "$TARGET_HARNESS")
831
+ [ "$TARGET_MODEL" = default ] || spawn_args+=(--model "$TARGET_MODEL")
832
+ [ "$TARGET_EFFORT" = default ] || spawn_args+=(--effort "$TARGET_EFFORT")
833
+ if FM_CONTROL_RELAUNCH_TX="$RELAUNCH_TX" \
834
+ "$SCRIPT_DIR/fm-spawn.sh" "${spawn_args[@]}" >/dev/null; then
835
+ RELAUNCH_META_PUBLISHED=1
836
+ else
837
+ [ "$(fm_meta_get "$META" control_relaunch_tx)" != "$RELAUNCH_TX" ] \
838
+ || RELAUNCH_META_PUBLISHED=1
839
+ die "the replacement agent for $ID could not be launched on $TARGET_HARNESS"
840
+ fi
841
+
842
+ state=$(wait_agent_state "$LAUNCH_WAIT" alive) || {
843
+ die "the replacement agent for $ID did not come up within ${LAUNCH_WAIT}s (endpoint reads '$state')"
844
+ }
845
+ RELAUNCH_AGENT_CONFIRMED=1
846
+
847
+ journal_write complete "${CHECKPOINT_LINES[@]}" "$note_line" "exit_result=$exit_result"
848
+ RELAUNCH_ACTIVE=0
849
+ echo "relaunched $ID harness=$TARGET_HARNESS from=$PRIOR_RECORDED_HARNESS model=$TARGET_MODEL effort=$TARGET_EFFORT backend=$BACKEND endpoint=$T worktree=$WT"
850
+ }
851
+
852
+ # --- verbs ------------------------------------------------------------------
853
+
854
+ case "$VERB" in
855
+ interrupt)
856
+ state=$(agent_state)
857
+ case "$state" in
858
+ alive) ;;
859
+ unverified)
860
+ # No recovery-grade classifier on this backend. Interrupt is
861
+ # non-destructive and its endpoint-existence postcondition is still
862
+ # real, so it proceeds - the printed proof names exactly what was
863
+ # verified rather than implying more.
864
+ ;;
865
+ dead|missing) die "no agent is running at task $ID's recorded endpoint (state: $state); there is nothing to interrupt" ;;
866
+ *) die "task $ID's endpoint reads '$state' rather than a positively classified state; refusing to send a lifecycle key into an unattributed endpoint" ;;
867
+ esac
868
+ proof=$(do_interrupt)
869
+ echo "interrupt-delivered $ID harness=$HARNESS backend=$BACKEND verified=$proof"
870
+ ;;
871
+ exit)
872
+ result=$(do_exit)
873
+ echo "$result $ID harness=$HARNESS backend=$BACKEND endpoint=$T worktree=$WT"
874
+ ;;
875
+ relaunch)
876
+ do_relaunch
877
+ ;;
878
+ esac