@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
package/CHANGELOG.md ADDED
@@ -0,0 +1,1913 @@
1
+
2
+
3
+ ## 2026-09-17 — the house gains an unpublish door
4
+
5
+ - **`bin/npm-publish.sh --unpublish @scope/name@<version>`.** Publishing had a
6
+ door in this house and unpublishing had none, so the act was done by hand on a
7
+ machine whose `~/.npmrc` holds a stale token — the very reason the door exists.
8
+ The new mode resolves the token from the hoard exactly as publishing does,
9
+ demands a spec that names the version (a whole package is not a one-word act),
10
+ supports `--dry-run`, and says plainly that the registry's CDN may serve the
11
+ tarball for a while after the removal.
12
+ - **The window is 72 hours.** npm allows one version back within 72 hours of its
13
+ publication; past that only npm support can remove it. The help text says so,
14
+ because a door that does not name its own clock invites a late knock.
15
+ - **`@zerwiz/ymir@0.1.5` was unpublished** — the version that carried the memory
16
+ well. Publishing the clean 0.1.7 moves the `latest` tag off the tainted build at
17
+ once, which is the half of the repair that does not wait for propagation.
18
+
19
+ ## 2026-09-17 — the package shipped the memory well (one version, now excluded)
20
+
21
+ - **The exposure.** `@zerwiz/ymir@0.1.5` carries five files that are nobody's but
22
+ the operator's: `.agents/memory/kaia.engram`, its `-shm` and `-wal` sidecars, and
23
+ `.agents/memory/well/{episodes,workspace}.jsonl`. A public npm tarball contained
24
+ the live memory well — the store and the episodes. Verified by fetching the
25
+ published artefact and listing it; `0.1.0`–`0.1.4` are clean, and this branch's
26
+ build is clean.
27
+ - **The cause, and it is a trap worth naming.** `.gitignore` excludes
28
+ `.agents/memory/kaia.engram*` and `.agents/memory/well/*.jsonl`, and the repo is
29
+ clean — but **npm does not consult `.gitignore` when `files[]` names a whole
30
+ directory.** `files: [".agents/"]` packs that subtree *including* the ignored
31
+ files. Nothing warned: the leak travelled in the artefact, not the repo.
32
+ - **The fix.** The manifest excludes them explicitly, because a `files[]` list
33
+ cannot rely on the ignore file it overrides:
34
+ `!.agents/memory/kaia.engram*`, `!.agents/memory/well/*.jsonl`,
35
+ `!.agents/memory/*.db`, plus `!**/__pycache__/` and `!**/*.pyc` for the compiled
36
+ junk that was travelling the same way. Verified: `npm pack --dry-run` carries
37
+ 864 files and **no** memory store — the memory README and the ledger's scaffold
38
+ header are all that remain, as they should be.
39
+ - **The rule for every future package:** a `files[]` entry that names a directory
40
+ overrides `.gitignore` for everything beneath it. Name what ships, or exclude
41
+ what must not — and verify with a dry-run pack, never by assumption.
42
+ - **Remediation.** `@zerwiz/ymir@0.1.5` should be unpublished (it is inside npm's
43
+ window); the clean build publishes as 0.1.7 and supersedes it.
44
+
45
+ ## 2026-09-17 — the smithy's dependency names the package npm will actually serve
46
+
47
+ - **`@zerwiz/smidja` is published and not served.** npm accepted it twice (0.1.0,
48
+ then 0.1.1): the tarball and the version document existed, the package document
49
+ never did, and a republish of 0.1.0 was refused as *"previously published"*. The
50
+ name answers `404`, the website `403`, while `@zerwiz/hlidskjalf`,
51
+ `@zerwiz/odrerir` and `@zerwiz/sessrumnir` resolve normally and always have.
52
+ - **A second free name failed identically.** `@zerwiz/smidja-factory` was published
53
+ and shows the same shape — version served, package document withheld. Two names,
54
+ one behaviour, while packages published yesterday serve fine: the withholding is
55
+ npm's, not the name's, and the CLI does not report it.
56
+ - **The distro depends on the name that can resolve.** `optionalDependencies` now
57
+ names `@zerwiz/smidja-factory`, so the moment npm serves that package the smithy
58
+ arrives with the rest. Being optional, it is skipped silently until then — the
59
+ plan's phase-5 row is what says so out loud.
60
+ - **`@zerwiz/ymir` 0.1.7** — the version published once this lands.
61
+
62
+
63
+ ## 2026-09-17 — the four surfaces arrive by npm, and an old tree gives up what it holds
64
+
65
+ - **The app packages arrive with the distro.** `@zerwiz/ymir` now depends on the
66
+ surfaces as their own packages — `@zerwiz/hlidskjalf`, `@zerwiz/odrerir`,
67
+ `@zerwiz/sessrumnir` (live on the registry) and `@zerwiz/smiddja` (published at
68
+ 0.1.0 today). They are **optionalDependencies**, deliberately: a broken app
69
+ package must never stop the core from installing, and a package not yet on the
70
+ registry is skipped by npm and starts arriving the moment it is published.
71
+ **Proven**: a global install from the packed tarball lands the core plus all
72
+ three live apps, 330 packages, and the bin answers `0.1.6`. A local install
73
+ hoists them to `node_modules/@zerwiz/<app>`; a global one nests them under the
74
+ distro's own `node_modules` — the plan checks both shapes.
75
+ - **The plan tells the shapes apart.** "Declared as a dependency but not fetched"
76
+ is a `DO`; "no package and no dependency" is a `BLOCKED`. All four surfaces read
77
+ `DO` on a machine that has the distro but not yet the apps.
78
+ - **Migration 0005 — the operator's things leave the code tree.** It carries this
79
+ machine's records, the runtime state (pids · logs · locks · the applied-marker),
80
+ the operator's credentials, and the settings git does not track. Run on the
81
+ Allfather's machine: **44 carried, 3 stale twins kept, 1 identical duplicate
82
+ removed, 0 refused** — the tree left holding `.gitkeep` and the distro's own
83
+ tracked defaults.
84
+ - **A collision is decided by evidence, never assumption.** Two files, one name:
85
+ identical content means the tree's copy goes (the content is provably at home);
86
+ different content means both are real, so the home's keeps the name and the
87
+ tree's is carried beside it as `<name>.stale-<UTC>`. Never merged, never
88
+ discarded. A template is not only `*.example` — `agents.machine.example.yaml`
89
+ matched none of the old guards and was carried off as if it were the operator's;
90
+ it is back, and the pattern now covers `*.example.*`.
91
+ - **The plan's `purity` row applies the same law.** A settings file git *tracks* is
92
+ the distro's shipped default, not the operator's — and the check asks git about
93
+ the real path, because the tree's `config` is a symlink into `.agents/config`
94
+ and the index holds the real name. Asking about the link reported "untracked" and
95
+ flagged the distro's own `cron.yaml`. It now reads: *nothing of the operator's is
96
+ written into the code tree*.
97
+ - **`bin/npm-publish.sh --all` learns the smithy** — the registry maps `smidja` to
98
+ `apps/smidja-factory`, so it is a publish target like any other app.
99
+ - **The smithy gets a front page.** `zerwiz/smidja`'s README was a three-line stub;
100
+ it now says what Smíðja is, how to install it, how to run the visualizer on
101
+ `:8437`, what the tree holds, and the shape of a run. The tarball also carries
102
+ `LICENSE` and `NOTICE` — npm attaches the licence and the readme on its own, but
103
+ **not the notice**.
104
+
105
+ ## 2026-09-17 — the install asks with a plan, and the operator's things leave the code tree
106
+
107
+ - **The consent a real install asks for is now computed, not recited.** The old
108
+ prompt was a hardcoded paragraph, and a paragraph cannot know the host: it named
109
+ an Omarchy version on a Mac, promised a workspace tree that already stood, and
110
+ never mentioned that no application had been installed at all. `bin/ymir-plan.sh`
111
+ probes this machine and prints one row per step with its state and the reason —
112
+ `DO · SKIP · INFO · BLOCKED · CONSENT` — across nine phases (resolve · code ·
113
+ home · runtimes · engines · apps · wire · raise · verify). `ymir-install.sh`
114
+ prints it at the consent prompt; `--plan` / `--dry-run` prints it and writes
115
+ nothing; `--json`, `--phase N` and `--blocked` are there for automation and for
116
+ reading what is holding an install back.
117
+ - **The four app surfaces are named in the plan.** hlidskjalf, odrerir, sessrumnir
118
+ and smidja each get a row: whether the source is present, whether the web build
119
+ exists, and — when it is absent — the honest reason (`no apps/<name> and no
120
+ @zerwiz/<name> package`). The Electron shells are a `CONSENT` row, not a silent
121
+ download: three shells each pull a ~100 MB runtime the web surfaces do not need.
122
+ - **The home is the operator's to choose.** `step_home` asks once, records the
123
+ answer as machine state under `~/.config/ymir/home`, and every later script
124
+ resolves it through `bin/hoard-lib.sh` (`$YMIR_HOME` → the recorded choice → one
125
+ documented default). `--check` never writes; `--yes` takes what is recorded.
126
+ - **The roots law, applied across the tree.** The package is the **code that runs
127
+ the programs**; everything the operator owns lives in the home. Two resolvers
128
+ were added (`hoard_data_dir`, `hoard_state_dir`, `hoard_settings_dir`,
129
+ `hoard_local_env`) and **42 call sites** converted: `$ROOT/data` and
130
+ `$ROOT/state` (25 scripts), then `$ROOT/.env.local` and `$ROOT/config/*`
131
+ (17 scripts). A credential no longer sits in a tree that ships, and machine
132
+ records no longer sit where npm will erase them on upgrade.
133
+ - **The plan is the ward for that law.** Its phase-1 `purity` row names anything of
134
+ the operator's found in the code tree — `data/`, `state/`, `config/*.yaml`,
135
+ `.env.local` — so drift is reported on every run instead of discovered after an
136
+ upgrade.
137
+ - **The install no longer lectures about local models.** The `step_models` console
138
+ line told the operator to "load the modeltesting skill" — a skill that does not
139
+ exist anywhere in the tree — mid-install. It is gone; the real method is named in
140
+ the one place it belongs, the Galdr asset `assets/local-models.md`. `step_models`
141
+ still ensures the Pi harness and seeds `~/.pi/agent/models.json`.
142
+ - **The package no longer claims to ship `config/`.** `config` is a symlink to
143
+ `.agents/config`, which npm cannot carry; the tarball now declares what it
144
+ actually contains (147 bin scripts, the agent-set template under `.agents/`).
145
+ Settings are seeded into `$YMIR_HOME/config/agents.yaml` from the tracked
146
+ template, falling back to `.agents/config/` when the symlink is absent.
147
+ - **A corrupted TOON block in `AGENTS.md`** — `outputs[7]` carrying eight rows and
148
+ duplicate `midgard/` lines — is mended; the compliance gate reports 84 valid
149
+ blocks again.
150
+ ## 2026-09-17 — the registry says where a repo lives and what it is for
151
+
152
+ - **A project entry can now name its machine.** `machine:` records the host
153
+ where a checkout lives; `data/machines.md` holds the fleet (omarchy-1,
154
+ zerwiz, zerwizserver live on the tailnet). A repo is no longer assumed to be
155
+ on the box you happen to be standing on.
156
+ - **A project entry can now say what it is for.** `about:` is one plain
157
+ sentence per repo. `bin/project-git.sh list --field about` prints the whole
158
+ inventory without opening the YAML.
159
+ - **`project-git.sh` resolves more of the block.** `--field` now accepts
160
+ `machine`, `company`, `workspace` and `about` alongside the git fields, and
161
+ non-git keys read from the project block rather than the `git:` line.
162
+ - **One registry, not two.** The live registry is `hodd/identity/projects.yaml`
163
+ (what the runtime reads). A stale duplicate at `Documents/Ymir/identity/` had
164
+ been drifting apart from it — different GitHub owners, different project sets
165
+ — and is retired, with a backup kept in `hodd/state/`.
166
+
167
+ ## 2026-09-17 — the private home gets the ward it never had
168
+
169
+ - **Six guards watched the public repo; the home had none — yet the home is where
170
+ every private byte lives.** The one real leak of this day (`platform.env.prev-fill`,
171
+ 44 credentials) happened *there*, in a scratch backup swept up by `git add -A`,
172
+ with nothing watching. `bin/hoard-guard.sh` closes that.
173
+ - **It is a hook, not a script.** Seated as `$YMIR_HOME/.git/hooks/pre-commit`,
174
+ **git runs it on every commit** — including one made in a hurry, by a loop, or by
175
+ an agent that has never heard of it. Verified by attempting a real `git commit`
176
+ with no guard invoked: git refused, exit 1.
177
+ - **It catches what actually leaked**, verified by planting each: a scratch-backup
178
+ name (`*.prev-*`, `*.bak`, `*.orig`), a plaintext secret filename, a secret shape,
179
+ and — the evasion that would have hidden a key — **a base64 blob whose decode
180
+ contains a PEM header**, under an innocent filename.
181
+ - **`bin/ymir-install.sh` seats it at both repos** (the `hoard-gate` step reports
182
+ the home separately, so a dormant vault is visible), on every install layer.
183
+ - **A bypass is logged, not silent.** `hoard-guard.sh --log-bypass` appends to the
184
+ Runes ledger when a `--no-verify` commit is detected.
185
+ - **Two stale flat paths fixed in the guards themselves.** `bin/docs-guard.sh` told
186
+ an operator to move private docs to `$YMIR_HOME/docs/` — a path that no longer
187
+ exists — and `bin/groa-update.sh` read `$YMIR_HOME/data/eindri-homes.md` instead of
188
+ the hoard's. A guard pointing at the wrong door teaches the drift it exists to stop;
189
+ `groa-update.sh` now resolves through `hoard_root`.
190
+
191
+ ## 2026-09-17 — the NorthStar gate runs nightly; the platform door it caught is mended
192
+
193
+ - **`bin/nornir-job-nsr-compliance.sh` (02:30)** runs every
194
+ `.compliance/gates/check_*.sh` (danger · env · paths · platform · wiring)
195
+ and carves the verdict — `nsr.compliance` clean, or `nsr.compliance.failed`
196
+ (exit 1) naming the broken gate, so the 07:00 briefing reads it at sunrise.
197
+ - **The gate it caught, mended:** `scripts/electron.sh` used `kill -9`, which
198
+ the platform gate rightly refuses as non-portable. It now uses `kill -KILL`
199
+ (the house idiom already in `scripts/stop.sh`) — the NSR round is 5/5 green.
200
+
201
+ galdr-reread: `.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md` — new
202
+ §3.5 (hall snapshot) and §3.6 (NSR round) rows.
203
+
204
+ ## 2026-09-17 — the Live Hall's board becomes true: the snapshot lands on the loom
205
+
206
+ - **The Hall was a glass with nothing behind it.** The Óðrerir page reads
207
+ `apps/odrerir/public/livehall.json` same-origin, but nothing wrote it on a
208
+ schedule — the board showed the saga's own static count and said so.
209
+ `bin/nornir-job-hall-snapshot.sh` (08:00, after the 06:00 observer and the
210
+ 07:00 briefing) now drives `bin/hall-snapshot.sh` from real state — runes,
211
+ projects, the cron gauge, the wake queue, standing smiths, armed when-
212
+ sources, landed errands — and carves Rune `odrerir / hall.snapshot`.
213
+ - The snapshot is runtime, never repo: `apps/odrerir/public/livehall.json` is
214
+ gitignored, so the job never dirties a branch.
215
+
216
+ galdr-reread: `.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md` — new
217
+ §3.5 row (reads/writes table, idempotence note).
218
+
219
+ ## 2026-09-17 — the hoard gets a guard, and Rule 04 stops contradicting the disk
220
+
221
+ - **Eir gains a `hoard` surface.** Private data drifting outside the hoard is
222
+ now caught rather than discovered by asking "where did that go?". The check
223
+ fails on two things: a `.ymir-layout.yaml` entry naming a directory that does
224
+ not exist (a stale map is what lets private work land outside the hoard), and
225
+ a flat `$YMIR_HOME/{identity,data,docs,secrets,tenants}` sitting beside
226
+ `hodd/`. `fix` merges a flat duplicate into the hoard without clobbering, then
227
+ repoints any stale layout entry at the hoard.
228
+ - **Rule 04 corrected, append-only.** The rule's mapping table read as if
229
+ `hodd/x/` and `$YMIR_HOME/x/` were two locations; on a real home that produced
230
+ two parallel stores which drifted. The appended correction states the truth:
231
+ `$YMIR_HOME/hodd/` **is** the private data path, `bin/hoard-lib.sh` is the one
232
+ source of truth for it, and `.ymir-layout.yaml` must name only paths that
233
+ exist. Nothing above the correction was rewritten.
234
+
235
+ ## 2026-09-17 — the hoard encrypts its secrets at rest
236
+
237
+ - **`bin/hodd.sh` decrypts transparently.** `load`, `emit`, and `tenant` now
238
+ accept a plaintext file *or* an `.age` ciphertext with the sibling plaintext
239
+ absent. A shared `resolve_secret` finds the readable form; when it decrypts,
240
+ it uses a mode-600 temp and removes it afterward. An agent asks for the
241
+ resolved path and never handles ciphertext directly.
242
+ - **Secrets stay encrypted at rest.** `hodd/secrets/platform.env.age` is the
243
+ committed form; the plaintext is scratch and gitignored. Round-trip verified
244
+ byte-identical before the plaintext was untracked.
245
+ - **The vault invariant, written down.** The age key and the ciphertext travel
246
+ together in the private `ymirhome` repo, so a dead disk loses nothing — and
247
+ `ymirhome` **must never be made public**. Stated in `hodd/docs/secrets-vault.md`.
248
+ - **The honest limit.** This is encryption-at-rest, not encryption-against-yourself:
249
+ on a single-user machine, a process running as the operator can read what the
250
+ operator can read. What it buys is the *file* and the *repo*, not the *account*.
251
+
252
+ ## 2026-09-17 — the Forge speaks: each skill's own text in the index
253
+
254
+ - **The Forge listed skills as bare names.** `Forge.tsx` rendered only
255
+ `{s.name}` + the aett rune, while the live `/api/skills` index carries every
256
+ skill's `description` (240-char truncation) — the data was there, the
257
+ surface never showed it. The skill list items are now two-line cards: name +
258
+ aett on the head row, the description beneath (`forge-item-desc`, dimmed
259
+ until hover), scoped to the skill variant so the Eindri rows keep their
260
+ side-by-side name+status shape.
261
+
262
+ galdr-reread: `.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md` — the
263
+ Forge gate bullet (skill list shows name + aett + description).
264
+
265
+ ## 2026-09-17 — the feed follows Brokk's thinking past the composer
266
+
267
+ - **Sessrúmnir's auto-scroll never counted streamed THINKING as growth.**
268
+ `useChatScroll` watched `messages` and `streamingContent` only, so a
269
+ reasoning-heavy turn (thinking before any visible content) grew the feed
270
+ without moving it — the thinking block ended up below the floating composer,
271
+ behind it, and the Allfather had to scroll down to read it.
272
+ - **The growth signal now also includes `streamingThinking` and streaming tool
273
+ calls.** While Brokk reasons, the feed keeps the thinking tail in view above
274
+ the composer (still only when Auto Scroll is on and the reader is at the
275
+ bottom — scrolling up to re-read never gets yanked).
276
+ - Live hall updated: rebuilt renderer delivered to the running Sessrúmnir and
277
+ the app restarted via `bin/sessrumnir.sh` (window back on workspace 8).
278
+
279
+ ## 2026-09-17 — the editor stops being banished to its own desktop
280
+
281
+ - **`bin/editor-place.sh` pinned the editor to its own desktop with
282
+ `no_focus = true`** — VS Code mapped onto a different workspace than the one
283
+ the Allfather worked on and never took focus, so nothing inside it was
284
+ clickable. The rule was written by Ymir itself into
285
+ `~/.config/hypr/ymir-desktops.lua`.
286
+ - **The editor is now UNMANAGED by default**: it opens on the active desktop,
287
+ focused and clickable, like any other app. The old pin remains reachable
288
+ explicitly with `YMIR_EDITOR_PIN=1 bin/editor-place.sh apply`.
289
+ - Live desk healed: the `code` windowrule was removed from
290
+ `~/.config/hypr/ymir-desktops.lua` (backup kept alongside), Hyprland reloaded
291
+ with no config errors, and the stranded VS Code windows were moved to the
292
+ active desktop and focused.
293
+
294
+ ## 2026-09-17 — models, providers, and paths are the user's — and the gate says so
295
+
296
+ - **The law, amended (Rule 07).** Two clauses appended, the rule itself untouched:
297
+ - **A. Models and providers live in the hoard, per user, read from YAML.**
298
+ Every operator's differ, so there is **no global model or provider** — a
299
+ shipped default naming a model is a claim about someone else's machine. The
300
+ user's own live in `$YMIR_HOME/hodd/`, read from a YAML file there; the repo
301
+ ships a template.
302
+ - **B. No hardcoded absolute file paths.** No `/home/<user>/…`, no
303
+ `/Users/<user>/…`, no `C:\Users\…`. A path is relative to a resolved root or
304
+ comes from env/config with one documented default.
305
+ - **The gate, `config`.** `compliance-check.sh` gains a check that fails on a
306
+ model id or provider name used as a **value** in shipped code or a tracked
307
+ config, and on an absolute path naming a user. Comments, `*.example` templates,
308
+ `CHANGELOG*`, and `assets/reference/` are exempt by intent — they document,
309
+ they do not configure. **192 files clean.**
310
+ - **Three real violations found and fixed:**
311
+ - `.agents/config/eindri-dispatch.json` — three dispatch rules named
312
+ `opencode-go/deepseek-v4.1-flash`. Now a template with `<your-model-id>`.
313
+ - `.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml` — the PI boot
314
+ profile named `lmstudio/qwen3.6-35b-a3b`. Now a placeholder.
315
+ - `bin/bootstrap-macos.sh` — `/home/ubuntu/Documents/Ymir`. Now resolved from
316
+ `YMIR_VM_USER` with one documented default.
317
+ - **Two false positives found and fixed in the gates themselves.** The `mocks`
318
+ gate flagged a prose comment explaining why a guard exists; the new `config`
319
+ gate first flagged a sentence mentioning `llama.cpp/llama-swap`. Both now
320
+ exclude comments and require a value position — a gate that cries wolf is a
321
+ gate that gets ignored.
322
+ - **Four pre-existing failures on main mended** so the gate could be added to a
323
+ green tree: a duplicated `midgard/` row in `AGENTS.md` (a bad merge left three),
324
+ the `mocks` false positive, `smidja-factory` indexed but app-provided, and the
325
+ seat's cloth read from an app repo that is absent until `step_apps` runs
326
+ (`design-check` now skips cleanly rather than failing every worktree).
327
+
328
+ ## 2026-09-17 — midgard holds public assets only; the company wiki is gone
329
+
330
+ - **`midgard/company_wiki/` did not belong in this repo.** It was an empty
331
+ placeholder (one `.gitkeep`), but a company wiki is *tenant data* — policies,
332
+ vision, specs, client names — and this repo is public. Removed, with every
333
+ reference to it corrected in `midgard/README.md`, `STRUCTURE.md`, `docs/lore.md`
334
+ and `assets/Ymir.md`.
335
+ - **`midgard/` is now described precisely.** It was called "shared company
336
+ assets" in one place and "cross-tenant" in another; a wiki is neither. The
337
+ contract says **public assets**, and `midgard/README.md` names what does *not*
338
+ belong: company knowledge, which lives at `$YMIR_HOME/hodd/identity/companies/`.
339
+ - **`bin/private-guard.sh` gains a tenant-document rule** so the shape cannot
340
+ return: a `company_wiki/`, `wiki/`, `policies/`, `handbook/` or `vision`/
341
+ `strategy`/`roadmap` document staged in the public tree is refused, with a
342
+ message naming where it belongs. Verified by planting `midgard/company_wiki/policies.md`.
343
+ - **Nothing had leaked.** A full sweep of every tracked midgard file for personal
344
+ handles, home paths, key shapes, tunnel UUIDs and LAN/tailnet addresses found
345
+ no hits — the ingress configs use `${VARS}` and `example.org` throughout, and
346
+ the DB schema is generic with row-level security on every tenant table.
347
+
348
+ ## 2026-09-17 — AGENTS.md states the one law: no private data in the public repo
349
+
350
+ - **The law is now first.** A `first_law` block sits directly under the mandate
351
+ in `AGENTS.md`: never store personal or private data in this repo — not a
352
+ secret, a key, a name, a plan, a schedule, a client, a credential, or a note.
353
+ The repo is public; private data lives at `$YMIR_HOME`, under `hodd/`.
354
+ - **The private-data section was rebuilt against the disk.** It had duplicated
355
+ `secrets/` and `identity/` lines, no `hodd/` level, and a layout that no longer
356
+ matched the home. It now shows the real tree, names `$YMIR_HOME/hodd/` as *the*
357
+ private data path, and records that `bin/hoard-lib.sh` is the one source of
358
+ truth for it.
359
+ - **Every `$YMIR_HOME/...` path in the file was corrected** to `$YMIR_HOME/hodd/...`
360
+ — the directory rules table, the registry reference, the secrets reference, and
361
+ the append-only ledger path all pointed at the old flat layout.
362
+ - **Two wards are now documented**: `bin/secret-guard.sh` (a secret entering the
363
+ repo) and Eir's `hoard` surface (private data drifting outside the hoard, or a
364
+ `.ymir-layout.yaml` naming a path that does not exist).
365
+ - **Staging discipline is written down.** Stage named files in the home, never
366
+ `git add -A` — a scratch file written seconds earlier gets swept into a commit
367
+ and pushed. This happened this day and cost a history rewrite.
368
+ - **`hodd/AGENTS.example.md`** carried the same stale flat paths and a wrong
369
+ command (`secret-guard.sh emit`, which does not exist); both corrected.
370
+
371
+ ## 2026-09-16 — the validator stops calling a dead visualizer healthy
372
+
373
+ `bin/ymir-validate.sh` reported `visualizer PASS "UI built and served on :8437"`
374
+ by looking at `./dist` alone. When the API had crashed on a bad `CMD_DB` and
375
+ nothing was listening on `:8437`, the validator still said PASS — the false-pass
376
+ class this night kept surfacing, in the very tool meant to catch it.
377
+
378
+ - **The check now probes the port as well as the build.** `dist` missing → FAIL;
379
+ built but nothing on `:8437` → FAIL with the fix (`run scripts/start.sh`);
380
+ built and listening → PASS. A PASS now means the thing is actually up.
381
+ - **The smidja-db check resolves the same DB pair** `scripts/start.sh` and
382
+ `bin/smidja-bootstrap.sh` do (an existing `$YMIR_HOME/smidja/smidja.db` first,
383
+ then an in-repo copy, `SMIDJA_DB` override) — previously it named the home path
384
+ only, so an in-repo DB read as missing.
385
+ - `galdr-reread`: `assets/installation.md` — a `visualizer` PASS means built *and*
386
+ listening.
387
+
388
+ ## 2026-09-16 — the roster's effect lands, and the backend pin stops being committable
389
+
390
+ Applying the private roster (`bin/agents-config.sh apply`) writes the resolved
391
+ model into each agent's canonical profile. Flipping the two local agents to Pi
392
+ made that visible — and surfaced a small ignore hole.
393
+
394
+ - **Profiles follow the roster.** `sindri-developer.md` and `kvasir-scout.md`
395
+ now carry their **Pi** ids (`llamacpp-coder/qwen3-coder-30b`,
396
+ `llamacpp/qwen3.5-9b`), and `huginn-researcher.md` its declared model — the
397
+ output of `apply` against the operator's roster. These profiles are what the
398
+ harnesses load, so the local agents now run on Pi rather than through OpenCode.
399
+ - **`.agents/config/backend` is ignored.** The pinned terminal backend is
400
+ machine-local, but `config` is a **symlink** to `.agents/config`, so the
401
+ `config/*` rule never matched it and the pin was committable. The file is named
402
+ in `.gitignore` instead.
403
+
404
+ ## 2026-09-16 — the roster can finally run an agent on Pi
405
+
406
+ `bin/agents-config.sh apply` wrote **every** agent's model into `opencode.json`'s
407
+ agent block, whatever harness that agent used. So an agent set to run on **Pi**
408
+ (native local models) would have had its Pi model id —
409
+ `llamacpp/qwen3.5-9b` — written into OpenCode's config, which cannot resolve it.
410
+ That is why the roster's two local agents were pinned to `harness: opencode` with
411
+ opencode-style ids: there was no working way to put an agent on Pi.
412
+
413
+ - **`apply` is now harness-aware.** Only `opencode`-harness agents are written
414
+ into `opencode.json`; a `pi` (or `hermes`) agent is left out, its model id going
415
+ to the resolve cache that `bin/agent-run.sh` reads. The providers block is
416
+ unchanged — a provider's endpoint is a real fact OpenCode may still want.
417
+ - The way this is meant to be used: declare a local agent's model as its **Pi**
418
+ id (`llamacpp/qwen3.5-9b`, `llamacpp-coder/qwen3-coder-30b` — the ids `pi
419
+ --list-models` reports) with `harness: pi`; the roster is then Pi-driven with no
420
+ per-machine hand-editing.
421
+ - `galdr-reread`: `assets/harness-integration/README.md` — the two writers of
422
+ `opencode.json`, and the rule that only OpenCode agents belong in it.
423
+
424
+ ## 2026-09-16 — the mesh reaches Teams and Anchor, and `show` stops guessing
425
+
426
+ `bin/a2a-mcp.sh` wired only the well (`engram`) and the mesh (`a2abridge`). The
427
+ **Teams** plane and **Anchor** memory existed only in the operator's personal
428
+ harness config, so no agent *inside* Ymir could see tickets or anchored memory —
429
+ and `a2a-mcp.sh show` insisted on a **fixed** server list, reporting
430
+ `wayofteams-mcp not on PATH` even when the plane was wired and working.
431
+
432
+ - **Remote MCP servers, URL-driven.** `bin/a2a-mcp.sh` now wires `wayofteams`
433
+ (from `WAYOFTEAMS_MCP_URL`) and `way-of-anchor-sse` (from `ANCHOR_MCP_URL`).
434
+ OpenCode gets them natively (`type: remote`); Pi, which has no remote
435
+ transport, gets them through the `mcp-remote` stdio bridge. A URL wins over a
436
+ local `wayofteams-mcp` binary when both exist. The URLs are credential-ish and
437
+ live in the private platform env — never the tracked tree.
438
+ - **`show` reports what is actually wired.** It enumerates every key present in
439
+ Pi's `mcpServers` and OpenCode's `mcp` (union with what this run would add), so
440
+ a hand-added or previously-installed server is visible, and the hint only fires
441
+ when Teams/Anchor is genuinely absent.
442
+ - `galdr-reread`: `assets/harness-integration/README.md` — the MCP scope is now
443
+ well · mesh · Teams · Anchor, with the two env keys named.
444
+
445
+ ## 2026-09-16 — the credential reaches the gate, and the hall stops leaking an IP
446
+
447
+ Setting the operator password had **no effect**. This is the bug that made that
448
+ true, and the runtime state that leaked a private address.
449
+
450
+ - **`scripts/start.sh` never loaded the platform env for the gate.** The gate is
451
+ `bun run apps/hlidskjalf/server/index.ts`, and the server reads
452
+ `process.env.HLIDSKJALF_AUTH` — but the launcher passed only `PORT`, and nothing
453
+ sourced `.env.local`. So a credential written by `bin/ymir-setup-auth.sh`
454
+ (correctly: `0600`, gitignored) never arrived, and because the gate treats an
455
+ empty `GATE_AUTH` as authenticated (`authed: GATE_AUTH ? … : true`) the gate
456
+ stayed **open**. `start.sh` now loads `.env.local` once, before the ports, for
457
+ every service it raises — the gate, Bifrost and Mimir.
458
+ - **`apps/odrerir/.astro/dev.json` was tracked.** Astro rewrites it on every
459
+ start with the live `pid` and the host's own addresses (LAN + tailnet) — a
460
+ private-IP leak into a public tree. It is now untracked and gitignored; the
461
+ generated types beside it stay tracked.
462
+ - `galdr-reread`: `assets/hlidskjalf-ui.md` (the gate must receive the credential)
463
+ and `assets/odrerir-hall.md` (`.astro/dev.json` is runtime state).
464
+
465
+ ## 2026-09-17 — the fragment convention is enforced where GitHub runs it
466
+
467
+ - **The gap, found by doing it.** The pre-push hook folds fragments before a
468
+ push — but a **GitHub merge bypasses the local hook entirely**. PR #43 merged
469
+ and left its own fragment unfolded on `main`, so the ledger silently fell
470
+ behind what the fragments already told. `bin/changelog-assemble.sh --check`
471
+ catches exactly that state; nothing was calling it.
472
+ - **The gate, at the layer that runs.** `.github/workflows/ymir-changelog-fragments.yml`:
473
+ - **on `push` to main** — `bin/changelog-assemble.sh --check` fails when any
474
+ fragment is unfolded, so the ledger can never fall behind a merge.
475
+ - **on a PR** — a change touching code or docs must add a fragment, edit
476
+ `CHANGELOG.md`, or carry the `no-changelog` label. The label records the
477
+ deliberate decision that no entry belongs, rather than letting it be
478
+ forgotten.
479
+ - **The pattern is the standard one.** This is the well-trodden "news fragments"
480
+ design (towncrier — Twisted, pytest, pip, attrs; changesets; CPython). The
481
+ zeroc-ice proposal states the root cause exactly: *"PRs edit one shared file.
482
+ Better merge discipline doesn't fix it; not editing the shared file does."*
483
+ - **`merge=union` was considered and rejected on evidence.** The Rigor ADR-105
484
+ tried it and measured it: *"GitHub's PR-mergeability and merge computation
485
+ ignore `.gitattributes` merge drivers, union included."* It works against local
486
+ git and does nothing on GitHub — a trap already falsified.
487
+ - **Main's own pending fragment is folded in this change**, so the ledger and the
488
+ fragments agree from here on.
489
+
490
+ ## 2026-09-17 — the changelog stops conflicting: fragments, folded by a script
491
+
492
+ - **The problem, measured.** `CHANGELOG.md` is one file and every branch appends
493
+ at the same position — the top. Git sees two branches inserting different lines
494
+ at the same spot and calls it a conflict, so **every merge re-conflicts every
495
+ open branch**. Sixteen open PRs were each resolved by hand for this reason
496
+ alone, and each merge re-conflicted the rest: O(N²) meaningless conflicts.
497
+ - **The fix — `CHANGELOG.d/`.** A change adds **one file with a unique name**
498
+ (`<YYYY-MM-DD>-<slug>.md`) instead of editing the ledger. Two branches never
499
+ touch the same fragment, so the collision cannot occur.
500
+ - **`bin/changelog-assemble.sh`** folds fragments into `CHANGELOG.md` — newest
501
+ first, above everything already recorded. Folding is an **append**: existing
502
+ entries are copied verbatim, never reordered, never rewritten. `--dry-run`
503
+ shows what would fold; `--check` exits 1 when fragments are unfolded.
504
+ - **The pre-push hook folds first.** `bin/changelog-guard.sh --install` now
505
+ writes a hook that runs the assembler before the guards, so a push never leaves
506
+ fragments unfolded; if folding changes the ledger the push is refused until the
507
+ fold is committed.
508
+ - **The guard accepts either form.** A push satisfies the duty by appending to
509
+ `CHANGELOG.md` **or** by adding a fragment. The refusal message now names both.
510
+ - **Rule 06 is amended, append-only** — the clause stands; the amendment records
511
+ fragments, and `CHANGELOG.d/` joins the append-only set so a move must carry it.
512
+
513
+ ## 2026-09-17 — the hearth re-seeds on its container: Sessrúmnir's chat fire returns
514
+
515
+ - **The ember glow was gone from the chat because the canvas sized itself once
516
+ at mount and only re-seeded on `window.resize`.** Sessrúmnir's split panes
517
+ (file tree · editor · image) resize the chat column without any window resize,
518
+ so the hearth kept a stale or zero-sized canvas — invisible. Both the shared
519
+ hearth (`midgard/design-system/ember.js`) and Sessrúmnir's React port
520
+ (`ember-background.tsx`) now watch their container with a ResizeObserver and
521
+ re-seed only when the measured size actually changes (never per-frame).
522
+ Hlidskjalf inherits the same mend through the shared module.
523
+ - **Verified live**: Sessrúmnir restarted on the fresh build; a screen capture
524
+ of the running window shows the fire drawing (ember + warm-glow pixels across
525
+ the hearth area). The running app had been serving a stale bundle (missing
526
+ `react-i18next` — deps installed, rebuilt).
527
+
528
+ galdr-reread: `.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md` — the
529
+ EmberBackground hearth section (shared module + ResizeObserver mend).
530
+
531
+ # CHANGELOG
532
+
533
+ ## 2026-09-17 — Pi gets its agents, and a dead extension comes back
534
+
535
+ - **Pi has no agent loader.** Agent loading in Pi is a *package* (`pi-agents`,
536
+ `pi-agent-mode`, `pi-simple-agents`), never a core feature — and Ymir installs
537
+ none. So `.pi/agents/` held twenty correct profile links that **nothing in Pi
538
+ ever read**. The same failure as OpenCode's singular `.opencode/agent/`,
539
+ arrived at from the other side.
540
+ - **The fix ships in this repo, not a root-pi package.**
541
+ `.pi/shared/extensions/ymir-subagents.ts` discovers the canonical
542
+ `.agents/agents/*.md` tree itself and registers a `subagent` tool. A call runs
543
+ the chosen figure as a nested model call in the current session: the figure's
544
+ markdown body is its system prompt, its frontmatter `model:` picks the model
545
+ where the machine serves it. `subagent({})` and `/subagents` list the roster.
546
+ - **It imports nothing.** `@earendil-works/pi-coding-agent` is not installed as a
547
+ package, so an extension importing its types cannot load at all. This one takes
548
+ `pi` as `any` and declares `parameters` as a plain JSON schema — the pattern
549
+ every working extension in the tree already uses.
550
+ - **A rename that left a reader behind.** `skuld-branch-supervision.ts` imported
551
+ `calmTranscriptClassIsVisible` / `CalmPresentationState` from
552
+ `./lib/ro-visibility.ts`, but that module exports `roTranscriptClassIsVisible` /
553
+ `RoPresentationState`. Pi refuses the **whole extension** at load, so Skuld's
554
+ supervision branch was dead in every session and nothing reported it. Fixed.
555
+ - **The check that catches it** is now recorded in the owning asset: import every
556
+ deployed extension with `node --input-type=module` and confirm it loads — a
557
+ module that cannot resolve is invisible from the file listing.
558
+ ## 2026-09-17 — every figure loads: the agent directory was never read
559
+
560
+ - **The bug, stated plainly.** Twenty agent profiles existed, twenty symlinks
561
+ pointed at them, and every gate was green — yet OpenCode loaded **three**
562
+ agents. The symlinks lived in `.opencode/agent/` (SINGULAR). OpenCode reads
563
+ `.opencode/agents/` (PLURAL). Twenty correct links sat in a directory no loader
564
+ opened, so only `brokk` and `hnoss` — the two declared by hand in
565
+ `opencode.json` — ever appeared.
566
+ - **The directory is fixed and migrated.** `.opencode/agent/` → `.opencode/agents/`
567
+ (20 links, all resolving). `bin/valknut-load.sh` now writes the plural path and
568
+ **migrates a legacy singular dir forward**, so an old home heals instead of
569
+ silently keeping its agents invisible.
570
+ - **The roster now declares what it names.** `bin/agents-config.sh apply` only
571
+ touched an agent already present in `opencode.json` (`if a in ablock`), so a
572
+ figure the roster knew but the config had never seen stayed undeclared. The
573
+ roster is the source of truth; a name in it now reaches the harness config.
574
+ - **A new gate catches the class.** `compliance-check.sh` gains **`roster`**: the
575
+ roster (`config/agents.yaml.example`) and the canonical tree
576
+ (`.agents/agents/*.md`) must name the same figures. A figure in the tree but not
577
+ the roster falls to `default_model` and is never declared; a figure in the
578
+ roster with no profile is a phantom. This is the check that would have caught
579
+ the real failure while every other gate stayed green.
580
+ - **Verified, not assumed.** `opencode agent list` in the worktree reports all
581
+ twenty figures (bragi … vor) plus Ymir's own subagents — 33 agents, up from 3.
582
+ Compliance: 14/14 PASS.
583
+ - **References swept.** Every `.opencode/agent/` reference in code and docs moved
584
+ to the plural path: `bin/valknut-load.sh`, `bin/agents-config.sh`,
585
+ `apps/hlidskjalf/server/index.ts`, `RULES/02-agents.md`, `README.md`,
586
+ `docs/runbooks/agents.md`, `.pi/extensions/README.md`, and the Galdr assets
587
+ (`harness-integration`, `runtime-compliance`, `registry`, `hlidskjalf-ui`).
588
+ `CHANGELOG.md`'s own historical entry is left as written — append-only.
589
+
590
+ ## 2026-09-16 — the core senses the real host, not Omarchy's shadow
591
+
592
+ - **`bin/ymir-install.sh` `step_host` ran the wrong sensor.** The core host step
593
+ called `bin/omarchy-sense.sh` — the **Omarchy-only** sensor — so on any
594
+ non-Omarchy host it learnt nothing and printed the sensor's own SKIP row as a
595
+ host snapshot: `host snapshot: sensor,SKIP,not an Omarchy host…`. On a Fedora
596
+ workstation that is the whole discovery step, reporting a skip as fact.
597
+ - **Now it senses THIS machine with `bin/host-sense.sh`** — the portable sensor
598
+ (the same one behind `ymir sense`) — on **every** host (Rule 05). Recording
599
+ stays the Omarchy layer's job: `omarchy-sense observe`, the post-update hook,
600
+ desktop placement, the plugin offer, and the alarm channel remain gated behind
601
+ `step_omarchy`. Nothing here assumes Omarchy; nothing here skips the core
602
+ machine either.
603
+ - `step_host` no longer branches on `--check`; it senses once and reports once:
604
+ `host sensed: <os> / <id> / <family> / <session> / <desktop>`.
605
+ - The owning asset reflects it in the same change:
606
+ `.agents/skills/galdr-ymirsystem/assets/installation.md` — the `host` step row,
607
+ the Verify list, the two-layer table (recording, not learning), and the
608
+ "Omarchy branches" note.
609
+ ## 2026-09-16 — the visualizer finds its DB, and the seat-hall actually builds
610
+
611
+ Two more readers left behind — both discovered by *starting the apps*, not by any
612
+ gate. Each failed silently in its own way.
613
+
614
+ - **`scripts/start.sh` pointed the smithy at a repo path that no longer holds the
615
+ DB.** `0003-private-data-separation` moved it to `$YMIR_HOME/smidja/smidja.db`,
616
+ but the starter still passed `CMD_DB=<repo>/apps/smidja/smidja_data/smidja.db`
617
+ — so the visualizer API died on boot with `smidja.db not found` and `:8437`
618
+ answered nothing. It now resolves the same pair `bin/smidja-bootstrap.sh` does
619
+ (home first, in-repo fallback, `SMIDJA_DB` override). The asset already
620
+ *described* this resolution; the code now implements it.
621
+ - **`bin/sessrumnir-ensure.sh` never built the app.** `[ "$built_present" ]` tests
622
+ a **literal, non-empty string** — always true — so `ensure --install` skipped
623
+ `build_app` and reported `built: no` with exit 0. Sessrúmnir only built when the
624
+ build was run by hand. Now `built_present` (the function) is called.
625
+ - `galdr-reread`: `.agents/skills/galdr-ymirsystem/assets/smidja.md` — the DB
626
+ path, the `scripts/start.sh` DB resolution, and the observer's read list.
627
+
628
+ ## 2026-09-16 — four readers that still pointed at the pre-split world
629
+
630
+ The app split and the hoard migration moved things; four readers never followed.
631
+ None failed loudly — each reported a clean PASS, a wrong SKIP, or a silent loss.
632
+
633
+ - **`bin/ymir-install.sh` wrote during `--check`.** The step chain ran
634
+ `bin/ymir-migrate.sh apply` unconditionally, so a preview that promises *"report
635
+ only, no writes"* actually **moved private data**. Migrations now apply only on
636
+ a real run: `if [ "$CHECK" = 0 ]; then ... apply; fi`.
637
+ - **`.agents/migrations/0003-private-data-separation.sh` skipped every directory.**
638
+ It pre-creates its target dirs, then its `copy` refused any target that already
639
+ existed — so `data/` (and every other directory source) was silently dropped.
640
+ The realm declaration never arrived and `0004` fell back to a neutral realm.
641
+ `copy` now **merges** a directory into its target (never overwriting a file) and
642
+ copies a single file only when it is absent.
643
+ - **`bin/smidja-bootstrap.sh` looked for the smithy at the old root.** `sys.path`
644
+ pointed at `smidja/`, but the split moved it to `apps/smidja/`, so the DB seed
645
+ died with `ModuleNotFoundError: No module named 'smidja_modules'`. It now
646
+ searches `apps/smidja` then `smidja`, so either layout works.
647
+ - **`bin/ymir-validate.sh` read the ledger from the pre-move path.** It looked at
648
+ `$YMIR_HOME/memory/`, but `0004-hoard-and-realms` put the ledger at
649
+ `$YMIR_HOME/hodd/memory/` — a false `runes FAIL` on a healthy home. It now tries
650
+ the hoard first, then the pre-move locations.
651
+ - `galdr-reread`: `.agents/skills/galdr-ymirsystem/assets/smidja.md` — the
652
+ protected-paths gotcha and the `smidja/` → `apps/smidja/` move.
653
+
654
+ ## 2026-09-16 — Omarchy-first, host-aware: Windows and macOS get a door
655
+
656
+ - **`bin/host-sense.sh`** — the one place that looks before anything acts. It
657
+ reports THIS machine: distro and family, kernel, arch, platform (linux · wsl ·
658
+ macos · windows), session (Wayland/X11), desktop, compositor, package manager,
659
+ and what the desktop can actually *do* — `placement`, `launcher`, `tray`. No
660
+ layer may assert a machine it is not standing on.
661
+ - **Omarchy stays first-class, and is now gated.** `bin/omarchy-sense.sh` opens
662
+ by asserting *"Ymir runs on an Omarchy host"*; on any other host it now skips
663
+ cleanly and points at `bin/host-sense.sh`, rather than recording the wrong
664
+ machine. That is Rule 05's own rule: a layer is gated on its host.
665
+ - **Windows has a door:** `bin/bootstrap-windows.ps1` — enables WSL2, installs
666
+ Ubuntu, then hands the work to `bin/ymir-install.sh` inside the distro. It is
667
+ honest about needing elevation and about the one reboot a fresh machine needs.
668
+ - **macOS has a door:** `bin/bootstrap-macos.sh` — raises Ubuntu in a Lima VM and
669
+ installs Ymir inside it, plus `packaging/macos/Ymir Installer.command`, a
670
+ double-clickable launcher for an operator who should not need a terminal.
671
+ - **The installers themselves:** `packaging/build.sh --exe|--mac|--check`, the
672
+ NSIS script `packaging/windows/ymir-setup.nsi` (→ `Ymir-Setup.exe`), and
673
+ `.github/workflows/ymir-installers.yml`, which builds the exe on an Ubuntu
674
+ runner (NSIS is a compiler, not a Windows VM) and the .pkg on a macOS runner
675
+ (pkgbuild is Apple-only). Signing/notarisation stay with the operator, so the
676
+ artefacts ship unsigned.
677
+ - `README.md` gains "Bringing your own machine" — the host table and the build
678
+ commands; its `docs/masterplan.md` pointer is corrected to `$YMIR_HOME/docs/`.
679
+
680
+ ## 2026-09-16 — app packaging prepared under the @ymir scope (Amendment C, part one)
681
+
682
+ - **Scoped names.** `apps/odrerir` was `ymir-odrerir` and `apps/sessrumnir` was
683
+ bare `sessrumnir`; both are now `@ymir/odrerir` and `@ymir/sessrumnir`.
684
+ - **Publishable metadata on all four apps** (hlidskjalf, hlidskjalf-mobile,
685
+ odrerir, sessrumnir): `license`, `repository`, `publishConfig.access: public`,
686
+ a `files` surface, and `prepublishOnly` where a build exists.
687
+ - **Measured with `npm pack --dry-run --ignore-scripts`:** hlidskjalf 1.3 MB /
688
+ 21 files, odrerir 2.3 MB / 15, sessrumnir 4.0 MB / 116, hlidskjalf-mobile
689
+ 2.0 kB / 4 (source only — it has no build script). `dist/ymir.apk` is excluded
690
+ by `!dist/*.apk`: it took the hlidskjalf tarball from 1.3 MB to 14.5 MB, and
691
+ npm is not an APK channel.
692
+ - **`private: true` stays until the Allfather's word** — nothing can publish by
693
+ accident; the flip is one line per app.
694
+ - The app repos were already registered in `$YMIR_HOME/identity/projects.yaml`
695
+ (`zerwiz/{hlidskjalf,hlidskjalf-mobile,odrerir,sessrumnir,smidja}`).
696
+ - `no-mistakes` is initialized for this repo (`no-mistakes init`): the clean-PR
697
+ gate now has its local remote. The vendored skill copy stays — it is the
698
+ canonical tree the skill index names.
699
+
700
+ ## 2026-09-16 — the loader stops deleting: merge, never overwrite
701
+
702
+ - **Root cause of the Apodex-provider loss, mended at the source.** Two writers
703
+ share the untracked `opencode.json`: `bin/valknut-load.sh` (structure, from
704
+ `opencode.json.example`) and `bin/agents-config.sh apply` (the roster —
705
+ providers and per-agent models, from `config/agents.yaml`). The loader
706
+ re-rendered with `sed` + `mv`, so because the example carried only
707
+ `llama.cpp`, **every loader run silently deleted the Apodex provider** that
708
+ lived only in the live file. `config_out` now merges deep and
709
+ `setdefault`-style: missing keys are added, existing ones are never
710
+ overwritten, and the skills path is ensured. Verified by wiping the provider
711
+ by hand: the next run reports `merged(provider.apodex)` and restores it, while
712
+ an unrelated hand-added key survives untouched. Seeding happens only when the
713
+ file is absent.
714
+ - **The changelog guard still bites, without punishing a follow-up.** The
715
+ pre-push guard now accepts either the pushed range touching `CHANGELOG.md` or
716
+ the branch's whole range since it left the trunk touching it — a commit that
717
+ merely lands a file the record already tells needs no micro-entry. A branch
718
+ whose entire range leaves untold is still refused.
719
+ - `bin/valknut-load.sh --status` reports the config outcome
720
+ (`seeded` · `merged(…)` · `unchanged` · `kept`), so a silent stomp can never
721
+ hide behind a "rendered" line again.
722
+ - `harness-integration/README.md` records the two-writer boundary.
723
+
724
+ ## 2026-09-16 — one skills tree, every harness; the config stomp mended
725
+
726
+ - **Every harness now reaches `.agents/skills`.** Pi was already right — its own
727
+ code walks up from the cwd to `.agents/skills` (and `~/.agents/skills`), so it
728
+ discovers Ymir's skills natively with no link and no config; a second root
729
+ under `.pi/` would only double-load. Claude Code, Codex and Cursor read project
730
+ skills from their own directory, so `bin/valknut-load.sh` now binds
731
+ `.claude/skills`, `.codex/skills` and `.cursor/skills` to `../.agents/skills`.
732
+ opencode reaches the tree through `skills.paths`. The install step `loaders`
733
+ runs the loader, so a fresh install gets all of it.
734
+ - **The `harnesses` gate (G14) now asserts the skills surfaces too** — opencode's
735
+ config, Pi's native root, and the three links — so a harness silently loading
736
+ nothing can no longer pass.
737
+ - **Defect mended: the loader was stomping `opencode.json`.** `bin/valknut-load.sh`
738
+ renders `opencode.json` from `opencode.json.example`, and that example carried
739
+ only `llama.cpp` — so a loader run silently **deleted the Apodex provider**,
740
+ which had only ever lived in the generated file. The example now carries Apodex
741
+ as well, with the served id `apodex-1.0-mini`, so a re-render cannot drop it.
742
+ - `bin/valknut-load.sh --status` now reports every surface (agents *and* skills)
743
+ with a true row count instead of a hardcoded header.
744
+ - Assets: `harness-integration/README.md` gains the skill-location table, and
745
+ each per-harness file states its own mechanism.
746
+
747
+ ## 2026-09-16 — Hodd lives outside the repo, and the installer makes it so
748
+
749
+ - **One resolver.** `bin/hoard-lib.sh` (`hoard_root`) is now the single answer to
750
+ *where private data lives*: `$YMIR_HOARD`, else `$YMIR_HOME`, else
751
+ `$HOME/Documents/Ymir` — never the checkout. Rule 07's one documented default,
752
+ in one place.
753
+ - **The inward default is gone.** `bin/mimir-ingest.sh`, `bin/project-git.sh` and
754
+ `bin/workspace-provision.sh` each fell back to `$ROOT/hodd`, so on a machine
755
+ with neither `YMIR_HOARD` nor `YMIR_HOME` exported, memory ingest, the project
756
+ registry and workspace provisioning wrote private data **inside the repo**.
757
+ All three (plus `bin/hodd.sh` and the installer) now resolve through the lib.
758
+ - **The misplaced document is out.** `0003-private-data-separation.md`, which had
759
+ come to rest in the repo at `hodd/docs/plans/`, now lives in the hoard at
760
+ `$YMIR_HOME/docs/plans/`. The repo's `hodd/` holds exactly the guard, the
761
+ README and `AGENTS.example.md` — Rule 04's scaffold set, and nothing else.
762
+ - **Installed, not assumed.** `bin/ymir-install.sh` step `tree` now raises the
763
+ hoard layout *outside* the repo (`bin/hodd.sh init`) and seeds an empty
764
+ `secrets/platform.env` (mode 0600), so `bin/hodd.sh emit secrets/platform.env`
765
+ resolves on a fresh machine instead of failing with "not readable".
766
+ `assets/installation.md` and `assets/memory-well.md` updated in the same change.
767
+
768
+ ## 2026-09-16 — the pane bridge keeps its quoting; Phase 3 verified
769
+
770
+ - **The Apodex plan's last open verification is closed.** Run in a herdr pane —
771
+ `bin/herdr-run.sh run huginn-research -- bin/huginn-research-worker.sh --brief
772
+ "…" --output-dir …` — the worker recalled, dispatched to the Apodex seat, wrote
773
+ its verdict, and observed it into Mimirsbrunn (`status: completed`, verdict
774
+ *"The capital of Norway is Oslo."*). Phase 3 needed a spawn, which the
775
+ read-only session lock had forbidden; it was run once the lock was this
776
+ session's.
777
+ - **Defect found and mended — `bin/herdr-run.sh run` lost its quoting.** A pane
778
+ runs its command through a *shell*, but the bridge handed herdr the raw argv.
779
+ An argument containing spaces reached the pane as separate words, so
780
+ `--brief "In one sentence: …"` arrived as `--brief In one sentence: …` and the
781
+ worker died with `error: unknown arg: one`. Every real brief is multi-word, so
782
+ the documented invocation could never have worked. `run` now quotes each
783
+ argument on the way in (`printf '%q'`), verified by re-running it.
784
+ - Asset updated in the same change: `.agents/skills/ymir-host/assets/thjazi.md`
785
+ carries the quoting rule.
786
+
787
+ ## 2026-09-16 — the skill-loading audit: wrong skills unloaded, the index made true
788
+
789
+ - **Three phantom skills stopped loading.** opencode was loading `galdr-compliance`
790
+ and `galdr-crafter` — both superseded, their work long since moved to
791
+ `tyr-check` — and `NSR`, the NSR scaffolding spec, which sat at
792
+ `assets/nsr/SKILL.md` carrying frontmatter. A recursive scanner walks
793
+ `skills.paths` to *any* depth, so all three were announced to every agent as
794
+ live skills. The two galdr crafters are removed; the NSR spec is renamed
795
+ `assets/nsr/scaffold-spec.md` and stays a document (its sibling templates
796
+ carry no frontmatter and were already inert).
797
+ - **Two gates added, one per failure class** (`compliance-check.sh`):
798
+ - **`harnesses` (G14)** — every link in `.claude/agents`, `.codex/agents`,
799
+ `.cursor/agents`, `.pi/agents`, `.opencode/agent` must land, one hop, in the
800
+ canonical `.agents/agents/` tree (Rule 02), and no nested `SKILL.md` may
801
+ carry frontmatter. One hop deliberately: Galdr's agent file *is* the skill,
802
+ by the dual-surface rule.
803
+ - **`skillindex` (G15)** — every real skill dir must be named in
804
+ `.agents/skills/README.md`, and every `.agents/skills/<name>` path the assets
805
+ cite must exist. Lines marked planned/legacy/superseded/removed/abandoned/
806
+ retired are exempt by intent.
807
+ - **The drift they exposed, mended:** the canonical index listed 23 skills while
808
+ 26 existed (`groa-update`, `lifecycle`, `rules-check-drift` were missing); the
809
+ Galdr and `.agents/assets/agents` registries still described a layout that no
810
+ longer existed (`smidja/`, `gunnlod`, `hamr`, `saga`, `ymir`, `open-design`),
811
+ pointing the agent at files that were not there; dead paths corrected to the
812
+ real names (`smidja-factory`, `saga-bearings`, `urdh-hold`, `nornir-schedule`,
813
+ `ymir-host`, `hamr-adapters`); `brokk-craft` marked planned rather than
814
+ presented as a working command.
815
+ - **`AGENTS.md` gains the invariant:** the delivery gate is enforced in git
816
+ hooks seated by the install step `gates` — `branch-guard` refuses a protected
817
+ branch, `changelog-guard` refuses a push whose range never touches
818
+ `CHANGELOG.md`.
819
+
820
+ ## 2026-09-16 — the delivery gates install themselves; rename drift mended
821
+
822
+ - **Install seam.** `bin/ymir-install.sh` gains step **`gates`** (after
823
+ `loaders`): `bin/secret-guard.sh --install` seats the pre-commit guard and
824
+ `bin/changelog-guard.sh --install` the pre-push (branch + changelog). A fresh
825
+ clone now gets the delivery gate without a manual step — `--check` reports it
826
+ as `gates OK|WARN`, the consent preamble names it, and
827
+ `assets/installation.md` carries the row in the same change.
828
+ - **Drift mended — found by the compliance gate, not by me.** Two symlinks
829
+ still pointed at the retired `galdr-cli` skill, so the last rename was not in
830
+ fact complete: `.agents/agents/galdr.md` (Galdr's agent surface was a **dead
831
+ link**) and `.agents/skills/tyr-check/assets`. Both repointed at
832
+ `galdr-ymirsystem`, which is where the skill and its assets live.
833
+ - **`AGENTS.md` TOON mend.** The `security[4]` block carried a rule wrapped
834
+ across two lines, which the checker counted as a fifth row. Joined to one
835
+ line; the block now declares and holds exactly four.
836
+ - **Compliance.** All ten Galdr gates green: toon · naming · mocks · syntax ·
837
+ json · sync · surfaces · assets · duplicates · governed.
838
+
839
+ ## 2026-09-16 — Smiðja moves into the app tree
840
+
841
+ - **The smithy is an app.** Its 148 source files moved from
842
+ `.agents/skills/smidja-factory/` to `apps/smidja-factory/`, joining
843
+ hlidskjalf, odrerir and sessrumnir under `apps/`.
844
+ - **Path-transparent.** `.agents/skills/smidja-factory` is now a symlink to
845
+ `../../apps/smidja-factory`, so every existing path resolves unchanged —
846
+ `scripts/start.sh`, `bin/ymir-install.sh`, `bin/ymir-validate.sh`, and the
847
+ skill loader (`.agents/skills` is a skills path). `node_modules/` stays
848
+ gitignored and is not carried.
849
+ - **Still open** (recorded, not done): the root `smidja/` runtime tree
850
+ Amendment A would move to `apps/smidja/`, and Amendment C's per-app GitHub
851
+ repos and npm publishing.
852
+
853
+ ## 2026-09-16 — the changelog guard: no push ships untold
854
+
855
+ - **Every push carries a CHANGELOG entry.** `bin/changelog-guard.sh` installs a
856
+ pre-push hook that reads the refs git hands it, resolves the range being
857
+ pushed, and refuses the push when `CHANGELOG.md` is untouched in that range.
858
+ A change that ships is a change that was told; the record can no longer lag
859
+ silently behind the code.
860
+ - **Rule 08 extracted and versioned.** The protected-branch check that lived
861
+ only inside the ad-hoc `.git/hooks/pre-push` is now `bin/branch-guard.sh`, so
862
+ the delivery gate is reproducible: `bin/changelog-guard.sh --install` writes
863
+ the pre-push that runs both guards.
864
+ - **Escape hatch, deliberate and loud.** `YMIR_SKIP_CHANGELOG_GUARD=1 git push`
865
+ when an entry truly does not belong.
866
+ - Checks by hand: `bin/changelog-guard.sh --range A..B`,
867
+ `bin/branch-guard.sh --branch main`.
868
+
869
+ ## 2026-09-16 — Apodex seat verified; the Weave mended
870
+
871
+ - **Correction (cites the entry below, never rewrites it).** The earlier
872
+ entry said *"LM Studio is retired; its :1234 port belongs to Apodex now."*
873
+ That was false as carved. LM Studio still holds `:1234` and is what serves
874
+ the Apodex GGUF; Apodex took the **model seat**, not the server.
875
+ - **Live verification.** `bin/apodex-smoke-test.sh` → PASS (valid tool-capable
876
+ response, exit 0). `bin/huginn-research-worker.sh` with **bare defaults** →
877
+ `status: completed`, verdict written, observed into Mimirsbrunn. The Apodex
878
+ seat (`http://127.0.0.1:1234/v1`) is live.
879
+ - **One model id, everywhere.** The seat serves **`apodex-1.0-mini`**; the
880
+ worker, smoke test, `.env.example`, `opencode.json`, `config/agents.yaml.example`
881
+ and Huginn's profile now all say so. Previously three names drifted
882
+ (`apodex/Apodex-1.0-mini-Q4_K_M`, `apodex/apodex-mini-q4`, the served id) and
883
+ the default worker call failed with `No models loaded`.
884
+ - **Four defects mended.** `bin/huginn-research-worker.sh` made executable
885
+ (was 644 — bare invocation died with `Permission denied`); the smoke test's
886
+ `--serve` GGUF path corrected to
887
+ `~/Models/FlameF0X/Apodex-1.0-mini-Q4_K_M-GGUF/apodex-1.0-mini-q4_k_m.gguf`;
888
+ `bin/models-detect.sh` env var renamed from the typo `APEDEX_URL` to
889
+ `APODEX_URL`.
890
+ - **Weight truth.** The Apodex Q4_K_M weights are **21.7 GB**, not the ~4–6 GB
891
+ the plan assumed — it cannot sit beside a coding model. `AGENTS.md` now says
892
+ so: one local model at a time, by weight.
893
+ - **Smiðja relocated.** `.agents/skills/smidja-factory` is now a symlink to the
894
+ app tree at `apps/smidja-factory/`, which is where the smithy's real files
895
+ live (Amendment A/C of the Apodex plan).
896
+ - Plan (private hoard): `$YMIR_HOME/docs/plans/apodex-integration-into-ymir.md`
897
+ — Amendment E records the live pass, the mended defects, and the one open
898
+ item: the herdr-seat verification (Phase 3), which needs a spawn.
899
+
900
+ ## 2026-09-16 — Apodex joins the Weave (research/planning provider)
901
+
902
+ - **Apodex provider.** Apodex-1.0-mini-Q4_K_M climbs into the machine as
903
+ the research/planning GGUF on `http://127.0.0.1:1234/v1`, seated
904
+ alongside llama.cpp coding models on :8080. LM Studio is retired; its
905
+ :1234 port belongs to Apodex now.
906
+ - **Env template.** `.env.example` gains the `APODEX_*` block; the LM
907
+ Studio block is marked RETIRED with its port claim corrected.
908
+ - **Smoke test.** `bin/apodex-smoke-test.sh` — probe or serve-and-test an
909
+ Apodex seat; exits 0=pass, 1=fail, 2=unavailable. Never mutates config.
910
+ - **Research worker.** `bin/huginn-research-worker.sh` (Apodex-powered
911
+ Eindri): takes a brief, recalls from Mimirsbrunn, dispatches to the
912
+ Apodex chat/completions seat, writes a structured verdict, observes it
913
+ back into the well. Wears the name **Huginn** per the naming law (the
914
+ research seat; Gungnir stays the skill-synthesis engine).
915
+ - **Agents hall.** `.agents/agents/huginn-researcher.md` binds Huginn to
916
+ the apodex model; `config/agents.yaml.example` registers the apodex
917
+ provider and Huginn's seat; `opencode.json` carries the apodex provider
918
+ block alongside llama.cpp; `bin/models-detect.sh` probes and emits the
919
+ apodex provider for the Pi model file (`~/.pi/agent/models.json`).
920
+ - **Install seams.** Apodex rides the existing seams: models-detect merges
921
+ it into the Pi models file at install; agents-config applies it into
922
+ opencode.json. Model provider selection documented in AGENTS.md
923
+ (`## Model Provider Selection`), Apache 2.0 licence noted.
924
+
925
+ ## 2026-09-16 — Gunnlöð joins the hall (SkillOpt integration)
926
+
927
+ - **SkillOpt integration.** `pip install skillopt` into `.venv/`; training
928
+ loop (`skillopt-train`), eval (`skillopt-eval`), and nightly
929
+ self-evolution (`skillopt-sleep`) available for Smíðja prompts and
930
+ Ymir skills. Nightly Nornir job at 00:30 (bin/nornir-job-skillopt-sleep.sh),
931
+ staged artifacts only — Allfather approves before adopt. One-time setup:
932
+ `bin/skillopt-setup.sh`.
933
+ - **Naming.** SkillOpt adopted the name **Gunnlöð** (keeper of the mead of
934
+ poetry — distills trajectories into refined skill artifacts). Added to
935
+ `.agents/assets/agents/naming.md` (platform map, 28 subsystems),
936
+ `.agents/skills/galdr-ymirsystem/assets/registry.md` (skills + external tools),
937
+ `README.md` (System Map + Skills + gratitude), `NOTICE` (MIT attribution).
938
+
939
+ ## 2026-09-13 — the imported names leave the halls (Norse naming purge)
940
+
941
+ - **"firstmate" retargeted to Ymir's own names across every Ymir-owned surface.**
942
+ The upstream distro's nautical vocabulary is gone from the docs, skills, `bin/`,
943
+ config, and the Hlidskjalf review copy: `firstmate` → **Brokk**, `secondmate` →
944
+ **Eindri-home**, `crew`/`crewmate` → **Eindri**, `captain` → **Allfather**
945
+ (`docs/lore.md`, `docs/Architecture.md`, `.agents/agents/brokk.md`,
946
+ `.agents/skills/herdr-panes/assets/{herdr,tmux}-backend.md`,
947
+ `.agents/skills/eindri-homes/assets/control-plane.md`,
948
+ `.agents/skills/saga-bearings/assets/board-template.html`,
949
+ `.agents/skills/ymir-host/assets/thjazi.md`, `bin/README.md`,
950
+ `apps/hlidskjalf/**`).
951
+ - **Engine literals kept.** Every real upstream identifier stays verbatim — the
952
+ Herdr labels (`firstmate`, `2ndmate-<id>`, `firstmate-<id>`), the home marker
953
+ `.fm-secondmate-home`, the envelope `FIRSTMATE_OP: ` and `[fm-from-firstmate]`,
954
+ and all `FM_*`/`fm-*` names — because `.agents/backend/` (the vendored engine)
955
+ and `assets/reference/` (provenance) are untouched.
956
+ - **Licensing.** `NOTICE` now records the upstream **firstmate** distro
957
+ (`github.com/kunchenguid/firstmate`, MIT, © kunchenguid) and a README "Built on"
958
+ section points to it; the MIT copyright/permission notice is retained.
959
+ - **Governed asset:** `galdr-ymirsystem/assets/hlidskjalf-ui.md` records the Allfather
960
+ review copy in the same change. `compliance-check.sh` 10/10 PASS.
961
+
962
+ ## 2026-09-13 — The realm seat, carved (wayof)
963
+
964
+ - **Problem:** the realm tree was bare (only the shipped example), no tenant
965
+ was seated, and the session digest resolved the Allfather's realm to
966
+ `default` — his company and private holdings unreachable by the map.
967
+ - **Seat:** `svartalfaheim/wayof/` carved from the example — `.env.realm`,
968
+ `SECRETS.md`, `AGENTS.md` (persona), `domains/`, `projects/`, the five
969
+ workspace branches, and the 9 company cards seeded from the identity hoard
970
+ (askr · brokkforge · dvalin · mannheim · muninn · runestone · utgard · wayof ·
971
+ ymirlabs), realm field unified to `wayof`, repo paths corrected to this
972
+ machine. `data/realm.md` now pins `wayof` (was drifting between `way-of`,
973
+ `wayof`, and `default`; hoard cards + persona updated to match).
974
+ - **Hood:** `svartalfaheim/wayof/HOOD.md` is the map of the hoard and the
975
+ seat; `bin/saga-session-start.sh` stage 6 (context digest) now prints
976
+ `--- hood ---` whole from the realm seat, so a session opens knowing the
977
+ operator's holdings. Living overviews: `workspace/company/wayof-overview.md`
978
+ and `workspace/company/aigf.md` (hodd stays the private store; the realm
979
+ points at it).
980
+ - **Verified:** `bash -n` green; realm-lib resolves `wayof`; `realm env:
981
+ present`.
982
+
983
+ ## 2026-09-13 — Gleipnir sees when an agent is turned off
984
+
985
+ - **Problem:** the machine lock stuck “held by another Brokk session” forever.
986
+ Nothing released it ( `gleipnir_lock_release` had zero callers; Pi's exit
987
+ hook only stopped the arm child), and liveness was `kill(0)` alone — which
988
+ reports a zombie (dead but unreaped) and a recycled pid as alive, so an
989
+ agent you turned off kept the helm until its pid happened to look gone.
990
+ Worse, the Sessrúmnir desktop RPC session holds the live lock yet never
991
+ arms supervision (no turn ever calls `gna_watch_arm`), stranding every
992
+ other session read-only.
993
+ - **Fix:** `bin/gleipnir-lock-lib.sh` now records the owner's starttime in a
994
+ `brokk.lock.starttime` sidecar and reaps a holder whose `/proc/<pid>/stat`
995
+ state is `Z`/`X` or whose starttime no longer matches (pid reuse) — dead,
996
+ zombie, and recycled holders are cleared at session start/acquire. Gná
997
+ (`gna-pi-watch.ts`) mirrors that liveness, reclaims a stale lock directly in
998
+ `gna_watch_arm` (`missing` no longer punts to saga-session-start.sh), and
999
+ drops its own lock on real process exit (`releaseLockIfOwned`); the turn-end
1000
+ guard (`syn-turnend-guard.ts`) uses the same zombie-aware check.
1001
+ - **Impact:** turning an agent off — cleanly, by kill (zombie), or after pid
1002
+ reuse — frees the machine lock for the next session. The live desktop seat
1003
+ still holds it until that app is closed or its own session arms; that is the
1004
+ law (one live primary per machine), but it now releases and hands off
1005
+ correctly.
1006
+ ## 2026-09-13 — the cloth reaches all three halls (Hlidskjalf · Smíðja · the seat)
1007
+
1008
+ - **One look, one source.** The carved cloth (the landing page's `:root`) now
1009
+ dresses every hall, each through its own thin adapter, and `docs/design.md`
1010
+ gained §0 *The cloth* plus the re-cut §4.1/§4.2 tables — the contract, not a
1011
+ wish. `midgard/design-system/tokens.css` keeps every `--ymir-*` **name** and
1012
+ changes only the values: stone `#0e0c09`/`#151209`/`#1a1610`/`#221d14`, bone
1013
+ text `#cfc3a9`/`#9a8f75`/`#6b6250`, bronze `#c9973f` accent with `#7d5f2a` as
1014
+ the brass rule, blood `#c2584a` danger, steel `#96a0a8` ok, brass bevel
1015
+ `inset 0 0 0 1px rgba(201,151,79,.12)`.
1016
+ - **Type.** Cormorant (display), Newsreader (body), IBM Plex Mono (data) — the
1017
+ landing's three faces — with Noto Sans Runic appended to every stack so runes
1018
+ fall through to the rune family. Hlidskjalf loads them from Google Fonts; the
1019
+ visualizer bundles them from `@fontsource` (its `@fontsource/play` is gone).
1020
+ - **Hlidskjalf:** 24 old-palette `rgba()` literals and every role hex in the
1021
+ stylesheets now read tokens (`color-mix(… var(--ymir-ok) …)`); workspace tints
1022
+ are cloth (work bronze, personal steel); the `HallsChooser` cards no longer name
1023
+ two tokens that never existed (`--ymir-line`/`--ymir-panel`); the login's GitHub
1024
+ button is a bone plate; the realm-tint fallbacks in `global.css` follow.
1025
+ - **Smíðja's eye:** the default theme is **fensalir** (the titlebar toggle cycles
1026
+ fensalir → classic → high-contrast, both overrides still winning); 77 hexes and
1027
+ 62 `rgba()`s across the components were recast onto the theme's own tokens; the
1028
+ categorical event/lane palettes (`src/lib/events.ts`) were re-cut onto the cloth
1029
+ while staying mutually distinct.
1030
+ - **Sessrúmnir:** text selection is now a **theme token**
1031
+ (`--color-selection-bg`/`-fg`) — the landing's amber `#57411a` on pale bone
1032
+ `#f0e6cd` — carried in `fensalir`/`sessrumnir` and derived per theme for
1033
+ everyone else; the global rule sits in `@layer base`, and the CodeMirror editor
1034
+ needs a second unlayered rule because CodeMirror paints its selection layer with
1035
+ unlayered CSS that beats any layered rule. A **To the Hall** button joins the
1036
+ status bar (local `:4322` when it answers, else `hall.ymir.zerw.org`, resolved in
1037
+ the main process).
1038
+ - **Heraldry is not chrome:** the eight house/domain seals and the Emblem keep
1039
+ their own colours — exactly as the landing page keeps its house seals.
1040
+ - **Geometry is untouched** (radius, spacing, the shell): the carved-slate
1041
+ squaring remains an open question for the Allfather.
1042
+ - **Verified:** `tsc` clean and `npm run build` green in Hlidskjalf; the
1043
+ visualizer builds under `vue-tsc`; Sessrúmnir's build, lint, theme tests and
1044
+ semantic-colour check green. Headless passes: Hlidskjalf's gates render with
1045
+ **0 console errors** (login, fleet, tasks, processes, reviews, runtime, cron,
1046
+ stats), and the visualizer loads with 0 console problems.
1047
+
1048
+ ## 2026-09-13 — the carved cloth reaches the seat-hall (Sessrúmnir)
1049
+
1050
+ - **The landing's cloth is now the seat's own look.** Every semantic token in
1051
+ `apps/sessrumnir/src/renderer/src/index.css` `@theme` was mapped to its carved
1052
+ twin from the landing page's `:root` (`CodeP/ymir-homepage/src/lore.html`):
1053
+ stone `#0e0c09` (app) with panels `#151209`/`#1a1610`/`#14100b`, bone text
1054
+ `#cfc3a9`/`#9a8f75`/`#6b6250` (faint/ghost as bone washes), bronze
1055
+ `#c9973f` accent and `#7d5f2a` brass rule for `border-strong`, blood
1056
+ `#c2584a`/`#7c3a30` for error, steel `#96a0a8` for success. Semantic names are
1057
+ unchanged — only the values moved.
1058
+ - **Fensalir** (the weaving halls) is registered as a built-in theme
1059
+ (`themes/fensalir.json`, id `fensalir`, appended to `BUILTIN_THEME_IDS` — an
1060
+ additive change that keeps every persisted id resolving). The seat's own
1061
+ built-in `sessrumnir` theme was carved to the same cloth, so the default look
1062
+ of an existing profile is the cloth on restart. A new test holds the two
1063
+ together (`the cloth is one`) and another holds the CSS `@theme` base to the
1064
+ theme file (`never drift`).
1065
+ - **Cloth is the default, not a cage:** the ThemeEngine's ordering is untouched —
1066
+ every other built-in theme, any user theme, and `high-contrast` still win when
1067
+ chosen.
1068
+ - **Type:** Cormorant (display), Newsreader (body), IBM Plex Mono (mono) bundled
1069
+ from `@fontsource*` (offline, `font-src 'self'`), with Inter/JetBrains Mono
1070
+ kept as glyph fallbacks; the landing's carved syntax palette (`--cm-*`) rides
1071
+ along in the theme files.
1072
+ - **Honest repairs on the way:** 29 raw `text-white` literals sat on token
1073
+ fills where white cannot be read on bronze (2.6:1). They now read the token
1074
+ that means "the rune on the filled plate" — `text-inverse` on `bg-accent`,
1075
+ `text-primary` on the dark blood `bg-error` — and the settings toggle knob is
1076
+ carved (stone when lit, bone when unlit). No colour literals remain in
1077
+ components.
1078
+ - **Paper:** `apps/sessrumnir/AGENTS.md` and `README.md` no longer claim the old
1079
+ sky-on-navy palette; they describe the cloth and its rules.
1080
+
1081
+ ## 2026-09-13 — the new tree, the mesh, the seat-hall
1082
+
1083
+ - **Everything in the new tree:** the Sessrúmnir work plus the orphaned fixes
1084
+ were migrated from the `ymir-old` working tree into this canonical tree —
1085
+ `apps/sessrumnir/` (deps vendored locally, never committed), the two
1086
+ `bin/sessrumnir-*.sh` scripts, `step_sessrumnir` in `bin/ymir-install.sh`,
1087
+ the Hoard registry entry, the `installation.md` asset, and the
1088
+ `syn-watch-arm.js` continuity fix (re-arm when `.supervision-armed` exists
1089
+ even with no task metadata). The superseded self-service register-gate work
1090
+ was **not** ported — this tree's committed invite-gate is canonical.
1091
+ - **Full install ran green** in the new tree: every step OK, invite minted
1092
+ (`YMIR-DBN4-FXEX`), all five services up, `bin/ymir-validate.sh` 11/11 PASS.
1093
+ - **Ratatoskr mesh healed:** the `a2abridge` engine (MIT,
1094
+ `vbcherepanov/a2abridge` v3.0.0) is installed at `~/.a2abridge/bin/`, its
1095
+ directory daemon runs on `127.0.0.1:7777`, and `bin/ratatoskr.sh
1096
+ status|doctor` pass. Forged `bin/a2abridge-ensure.sh` (installs the engine,
1097
+ patches the systemd unit's unwritable `/var/log` log paths to journal,
1098
+ keeps the directory up) and wired it into migration `0002-a2a-mcp.sh`, so
1099
+ every install/update heals the mesh instead of leaving a dangling MCP path.
1100
+ - **MCP bridges fixed:** `engram-mcp` failed at startup (its Python env
1101
+ lacked the `mcp` SDK; mcp 2.x renamed FastMCP, so it is pinned to `mcp<2`)
1102
+ — the server now initializes against the `kaia.engram` store. `a2abridge`
1103
+ MCP is wired into both pi and opencode via `bin/a2a-mcp.sh install`.
1104
+ - **Docs:** `docs/design.md` §5.4 documents the gate exactly as committed
1105
+ (operator credential + invite-gated registration + GitHub door + httpOnly
1106
+ 30-day session); the hlidskjalf-ui skill gained the `register` surface row.
1107
+
1108
+ ## 2026-09-13 — Sessrúmnir, the seat-hall
1109
+
1110
+ - **Sessrúmnir adopted:** the Apache-2.0 **pi-desktop** GUI
1111
+ (`FaqFirebase/pi-desktop`, v0.1.7-alpha) is vendored at `apps/sessrumnir/`
1112
+ and rebranded **Sessrúmnir** — the seat-hall where the Allfather converses
1113
+ with the machine. The external engine keeps its product name; the GUI the
1114
+ user sees is Sessrúmnir, themed with the way-of palette (sky `#38bdf8` on
1115
+ deep navy) as the new default built-in theme. Window titles, launcher,
1116
+ package identity, tray/autostart strings, data-dir name, and the Pi logo
1117
+ (now a Sowilo rune bolt) are rebranded; upstream `LICENSE` is preserved and
1118
+ `NOTICE` records the adoption.
1119
+ - **Forge scripts:** `bin/sessrumnir-ensure.sh` (status/ensure/install — deps
1120
+ are never committed, installed on first run with the electron-binary heal
1121
+ `scripts/electron.sh` already uses) and `bin/sessrumnir.sh`
1122
+ (start/status/stop with a workspace argument).
1123
+ - **Install wiring:** `bin/ymir-install.sh` gains a `sessrumnir` step (after
1124
+ `hermes`) and lists Sessrúmnir in `workspace/INSTALL.md`; the
1125
+ `installation.md` asset's step table, adopted-engines table, and Hermes-style
1126
+ section are updated in the same change.
1127
+ - **Registry & audit:** the Hoard registry (`hodd/identity/projects.yaml`)
1128
+ gains the `sessrumnir` project (upstream remote); the adoption is inscribed
1129
+ in Runes.
1130
+ - **Not yet installed:** `apps/sessrumnir/node_modules` is absent — run
1131
+ `bin/sessrumnir-ensure.sh install` when ready.
1132
+
1133
+ ### 2026-09-13 — the seat-hall raised
1134
+
1135
+ - `bin/sessrumnir-ensure.sh install` completed: deps + Electron binary + build
1136
+ all green; full test suite **989/989 pass**, typecheck and lint clean (the
1137
+ `autostart-linux` test was updated for the new brand name). `bin/sessrumnir.sh
1138
+ start` raised the window — Hyprland reports class `sessrumnir`, title
1139
+ `Sessrúmnir`, data under `~/.config/sessrumnir`.
1140
+
1141
+ ## 2026-09-12 — The well actually installs (it never did)
1142
+
1143
+ - **The memory engine was never installed by the installer.** `bin/prereq-ensure.sh`
1144
+ had no `engram` target at all, and `bin/ymir-install.sh` only *checked* for it
1145
+ and printed `SKIP "optional — install engine then run bin/mimir-bridge.sh"`. A
1146
+ SKIP never blocks, so the well was silently down on every install.
1147
+ - **The hint named the wrong package.** PyPI's `engram` is an unrelated
1148
+ *rendering* library (mitsuba/drjit/torch): following the hint pulled gigabytes
1149
+ of CUDA wheels and still left no engine. The memory engine's distribution is
1150
+ **`engdbram`**; its module is `engram`. The pre-swap append-only log had the
1151
+ right answer all along (`PyPI engdbram, v2.2.1`).
1152
+ - **Now it installs.** `prereq-ensure.sh engram` installs `engdbram` into an
1153
+ interpreter that can run it (>=3.11; uv supplies 3.12 here), records that
1154
+ interpreter in `~/.config/ymir/engram-python`, and `bin/mimir-bridge.sh` reuses
1155
+ it for both the check and the run. The installer provisions rather than hints,
1156
+ and reports WARN instead of a silent SKIP when it cannot.
1157
+ - **Verified:** `curl 127.0.0.1:4602/health` -> `{"status": "up", "store":
1158
+ ".agents/memory/kaia.engram"}`; `.agents/skills/lifecycle/smoke_test.sh` exits 0
1159
+ with all five checks green.
1160
+
1161
+ ## 2026-09-12 — The dashboards stop crash-looping on the iGPU
1162
+
1163
+ - **`scripts/electron.sh` decides its own GPU path.** Both dashboards appeared to
1164
+ work while `coredumpctl` filled with SIGSEGV cores from
1165
+ `electron --type=gpu-process`. An iGPU backs its graphics memory with system
1166
+ RAM (GTT), a local model served on that same iGPU held 5.8-8.0 GiB of it, and
1167
+ the amdgpu driver then failed the desktop's command submissions — which
1168
+ Electron turned into a NULL dereference at a constant offset. Only the GPU
1169
+ process died, so the windows stayed up and the failure was easy to miss.
1170
+ `igpu_vram_small()` now reads the render device's VRAM carve-out and switches
1171
+ to software rendering under `YMIR_IGPU_VRAM_SMALL_MIB` (default 2048). The old
1172
+ comment promised this auto-detect; now it exists. `YMIR_DESKTOP_DISABLE_GPU`
1173
+ still overrides, both ways.
1174
+ - **Verified:** with the fix, the amdgpu submission errors stop and the
1175
+ gpu-process runs SwiftShader (`--use-angle=swiftshader-webgl`) rather than the
1176
+ hardware path; no new cores.
1177
+
1178
+ ## 2026-09-12 — The editor keeps its own seat
1179
+
1180
+ - **`open-editor.ts` seats the editor in Þjazi:** inside herdr, `/edit` and
1181
+ `ctrl+shift+e` now open the Allfather's editor in its **own tab** of the home
1182
+ workspace (`herdr tab create --focus` + `herdr pane run`, label
1183
+ `ymir:edit[:<base>]`, recorded in `state/herdr-seats` for `close-all`) instead
1184
+ of suspending the pi session — the agent no longer dies when the editor
1185
+ opens. Outside herdr the old roads remain: GUI editors launch detached,
1186
+ terminal editors suspend the TUI and resume on exit.
1187
+ - **`open-editor.ts` shows hidden files:** the picker and `/edit`
1188
+ tab-completion now merge the git listing with a bounded walk, so gitignored
1189
+ dotfiles (`.env.local`, `.env.realm`, …) are openable too.
1190
+
1191
+ ## 2026-09-11 — Omarchy-first: host skills, machine learning, native fixes
1192
+
1193
+ - **New skill `ymir-omarchy`:** Omarchy-native operation — the two laws (never
1194
+ edit `/usr/share/omarchy/`; Hyprland owns placement), host detection, the
1195
+ monitor/scale coordinate trap, the amdgpu GPU crash and mitigation, desktop-app
1196
+ placement, and a safe-customisation table.
1197
+ - **New skill `ymir-thjazi`:** Þjazi (herdr-first) — protocol floors (14+ panes,
1198
+ 0.8.0 presentation spaces), verification, installation.
1199
+ - **Ymir learns the host:** `bin/omarchy-sense.sh` snapshots and *diffs* the
1200
+ machine (Omarchy version, explicit packages, config files, monitors, scale) into
1201
+ `state/omarchy-setup.json`; `bin/omarchy-hook-install.sh` adds an Omarchy
1202
+ `post-update` hook so it re-learns after every `omarchy update`.
1203
+ - **Þjazi in the installer:** `bin/herdr-ensure.sh` + new `step_backend`
1204
+ (herdr, else tmux — never a silent fallback).
1205
+ - **New `step_omarchy`** (SKIP on a non-Omarchy host).
1206
+ - **Desktop fixes:** window placement is now LOGICAL and work-area clamped, and
1207
+ prefers a non-primary display (the old math used physical pixels on a scale-1.5
1208
+ panel and filled the screen). Apps are identified by their command line, not the
1209
+ `.bin/electron` shim pid — which fixes the **double-launch** bug. `stop` kills
1210
+ every matching pid.
1211
+ - **GPU mitigation:** `YMIR_DESKTOP_DISABLE_GPU=1` adds
1212
+ `--disable-gpu --disable-gpu-compositing` for small-VRAM iGPUs (the crash was
1213
+ `amdgpu: Not enough memory for command submission`, SIGSEGV, not an OOM).
1214
+ - **Per-machine state un-shared:** `.agents/memory/kaia.engram*` and
1215
+ `well/*.jsonl` were tracked and pushed (one machine's private memory + volatile
1216
+ SQLite sidecars). Now gitignored and untracked; the contract is written in
1217
+ `.agents/memory/README.md`.
1218
+ - **Assets updated:** `installation.md` (15 rows, consent, validation, Omarchy),
1219
+ `hlidskjalf-ui.md` (the desktop-apps section).
1220
+ - **Verified:** full install green (15 rows; only the docker-group WARN), 9/9
1221
+ compliance, both skills registered.
1222
+
1223
+ ## 2026-09-11 — Load the owning asset before editing a governed path (5 layers)
1224
+
1225
+ The runtime drifted from its documentation because the asset that governs a
1226
+ subsystem was never loaded before the code changed. Five layers now prevent it:
1227
+
1228
+ - **1. `AGENTS.md`:** a new `governed[6]` table maps each governed path to the
1229
+ asset to load first, and `manual[]` gained `installation`, `ui`, `runtime-spec`.
1230
+ - **2. Session digest:** `saga-session-start.sh` prints an `ASSET ROUTING` block
1231
+ every session, so the mapping is always in context.
1232
+ - **3. Router loadable:** `galdr`'s `disable-model-invocation` is removed (it hid
1233
+ the one router that owns the assets); `tyr-check` keeps it (deliberate).
1234
+ - **4. Enforced seatbelt:** new `bin/syn-asset-pretool-check.sh` denies an
1235
+ `edit`/`write` of a governed path until its asset was read (`state/asset-reads`);
1236
+ the Pi extension relays it and records asset reads.
1237
+ - **5. Compliance gate:** `compliance-check.sh` gains an `assets` check that
1238
+ FAILS when a governed path changed without its asset (it caught this very
1239
+ change), and `runtime-compliance.md` documents G12 + the routing map.
1240
+
1241
+ ## 2026-09-11 — Automate the install: consent gate, self-healing prereqs, visualizer-ready
1242
+
1243
+ - **Consent gate:** a real install now prints its plan and waits for the operator
1244
+ to accept (`[y/N]`). Declining changes nothing (exit 3). `--check` still previews
1245
+ without asking; non-interactive callers must pass `--yes`.
1246
+ - **New `bin/prereq-ensure.sh`:** self-healing prerequisites in USER SPACE —
1247
+ installs `bun` and `uv` via their official installers, `mcp<2>` via pip, and can
1248
+ fetch a specific Python (e.g. `3.12`) with uv for packages that need one.
1249
+ - **New `bin/smidja-bootstrap.sh`:** creates `smidja/smidja_data/smidja.db` from
1250
+ the tracer's own schema and seeds a bootstrap session, so the Smíðja visualizer
1251
+ has data from the first install. Fixed: it now bootstraps on a bare call
1252
+ instead of printing help, and reports failure honestly when the DB is absent.
1253
+ - **`bin/ymir-install.sh`:** new `smidja` step; prerequisites delegated to the
1254
+ self-healing helper; `engram` reported as an honest optional `SKIP` with the
1255
+ exact next command; docker-group-permission and build-failure distinguished.
1256
+ - **Verified:** consent refuse/accept/decline paths; smidja db created and read
1257
+ back (8 tables, bootstrap session); compliance 8/8.
1258
+
1259
+ ## 2026-09-11 — Smooth install: provider choice, no forced key, real prereqs
1260
+
1261
+ - **Model provider is now the operator's choice** (`YMIR_MODEL_PROVIDER`):
1262
+ `opencode-go` (needs a key), `lmstudio` (keyless local), or
1263
+ `openai-compatible`. The bridge no longer forces `OPENCODE_GO_API_KEY`;
1264
+ with no key it auto-selects the keyless local provider so a fresh install works.
1265
+ - **New:** `.agents/backend/model-bridge.py` (provider-aware, keyless-capable);
1266
+ `opencode-go-bridge.py` kept as a delegating shim so existing references work.
1267
+ - **`bin/bifrost-bridge.sh` v2:** `--provider`, provider auto-selection, no hard
1268
+ env-file requirement, actionable errors per provider.
1269
+ - **`bin/ymir-install.sh`:** installs `bun` for real (user-space, then a package
1270
+ hint); installs `mcp<2`; `engram` is now an honest `SKIP` with the Python
1271
+ version reason instead of a permanent WARN; distinguishes docker-group
1272
+ permission from a build failure.
1273
+ - **`scripts/start.sh`:** fixed the early exit that skipped the gate API and all
1274
+ services whenever the SPA was already running.
1275
+ - **Verified:** compliance 8/8; bridge relays models + chat + 404s; keyless
1276
+ start confirmed; `start.sh` raises Gate API, Nornir, Bifrost, visualizer.
1277
+
1278
+ ## 2026-09-11 — Single-tenant workspaces shipped
1279
+
1280
+ - **First setup:** `bin/ymir-install.sh` (8 steps) + `bin/workspace-provision.sh`.
1281
+ - **Model:** single tenant; workspaces (personal|work) over domains; houses = brands.
1282
+ - **UI:** Login onboarding (name/kind/domains), Topbar workspace chip, AccountMenu/Profile relabelled.
1283
+ - **Engines:** treehouse → `yggdrasil.sh pool`; sandcastle → `utgard.sh sandcastle`; no-mistakes → Mjollnir gate.
1284
+ - **GitHub:** `bin/project-git.sh` reads `workspace/projects.yaml` `git{}`.
1285
+ - **Verified:** build green, compliance 8/8, smoke 8/8, lint 4/4.
1286
+
1287
+ All significant runtime, policy, and architectural changes for the Ymir platform.
1288
+ Entries are appended chronologically; never rewritten.
1289
+
1290
+ ## 2026-09-11 — Hardcoded per-page feeds (header + stream)
1291
+
1292
+ - **New:** every gate has its own hardcoded, domain-appropriate rolling feed
1293
+ (16 pools, `src/data/feeds.ts`) — Fleet, Tasks, Well, Runes, Reviews,
1294
+ Processes (Valhalla), Files, Chat, Forge, Runtime, Cron, Sessions, Trace,
1295
+ Decisions, Stats, Profile. Extra Kaia “oracle by the well” lines for the chat
1296
+ page.
1297
+ - **Header:** a live `PageFeed` now sits in the page header of every gate
1298
+ (glyph + hint on the left, the current page's latest 3 messages on the
1299
+ right), rolling.
1300
+ - **Stream:** the bottom Stream keeps each page's last **40** domain messages,
1301
+ with the fleet-wide feed as fallback. A generator tops it up every 2.4s and
1302
+ the page is seeded on first visit so it is never cold.
1303
+ - **Verified:** `tsc` + `vite build` green, SPA 200, compliance 8/8, smoke 8/8,
1304
+ lint 4/4.
1305
+
1306
+ ## 2026-09-11 — Per-page rolling 40 message feeds
1307
+
1308
+ - **Change:** the bottom stream is no longer one global 120-line feed. Every gate
1309
+ keeps its own rolling window of the **last 40** messages, and events are routed
1310
+ to the page they belong to (module → gate: `well`, `sessions`, `forge`,
1311
+ `runes`, `cron`, `reviews`, `processes`), with the fleet-wide feed as fallback.
1312
+ The stream header shows the current page. `STREAM_WINDOW = 40`, matching the
1313
+ chat's `CHAT_WINDOW = 40`.
1314
+ - **Verified:** `tsc` + `vite build` green, SPA 200.
1315
+
1316
+ ## 2026-09-11 — Galdr/Tyr assets: symlink, not copies
1317
+
1318
+ - **Fix:** `tyr-check/assets` is now a **symlink** to the canonical
1319
+ `galdr/assets`, so the two can never drift. A background process had been
1320
+ rewriting the registry, flipping the sync gate red; a symlink makes drift
1321
+ structurally impossible. Compliance back to 8/8 stable.
1322
+ - **Verified:** compliance 8/8, smoke 8/8, lint 4/4.
1323
+
1324
+ ## 2026-09-11 — Chat uses the root Pi model catalog
1325
+
1326
+ - **Fix:** the Kaia chat guessed a llama.cpp model id by regex and fell through
1327
+ to the Bifrost bridge (`:4603` → 401) when the guess failed.
1328
+ - **Now:** the gate API reads the operator's root Pi catalog
1329
+ (`~/.pi/agent/models.json`) for the exact provider → base URL, model id, and
1330
+ key (llama.cpp router `:8080`, `sk-not-key-required`). A chosen local model
1331
+ is tried only on its own base; the default is the operator's Pi default
1332
+ (`qwen3.6-35b-a3b@iq3_s`). `/api/chat/models` lists the real connected set.
1333
+ - **Verified:** `gemma-4-12b@q3_k_s`, `qwen3.6-35b-a3b@iq3_s` (default), and
1334
+ `qwen3.5-9b@q4_k_s` all answered live; no 401.
1335
+
1336
+ ## 2026-09-11 — Shared well for every harness; no mock; clickable memories
1337
+
1338
+ - **Harnesses:** the engram MCP server is now registered for all four OpenCode
1339
+ accounts (`opencode`, `opencode-rd`, `opencode-work`, `opencode-oczer`), Pi
1340
+ (`~/.pi/agent/settings.json` + `mcp.json` + `.pi/mcp.json`), Claude, Cursor,
1341
+ and Codex. Registered **unscoped** so every harness reads the one shared well
1342
+ (per-call `agent_id` still attributes writes).
1343
+ - **No mock:** purged every test/mock episode (`smoke`/`Test observation`) from
1344
+ both the engram store and `episodes.jsonl` → 367 true episodes. Test writes
1345
+ never enter the well.
1346
+ - **UI:** Well memories are now **clickable** — `GET /api/well/episode?id=` and
1347
+ a bridge `/episode` endpoint feed a modal with the full memory text.
1348
+ - **Bridge fix:** `/recent` and `/recall` restored; added `/episode`.
1349
+ - **Lifecycle fix:** `bifrost-bridge.sh` / `mimir-bridge.sh` now stop by process
1350
+ match when the PID file is missing, and record the PID when the port is
1351
+ already up — so `scripts/stop.sh` truly lowers the whole system and
1352
+ `scripts/start.sh` truly raises it.
1353
+ - **Galdr:** new asset `.agents/skills/galdr-ymirsystem/assets/memory-well.md` (store,
1354
+ bridge, MCP, harness matrix, laws, verify), routed in `SKILL.md`; registry +
1355
+ harness README updated; mirrored to tyr.
1356
+ - **Verified:** MCP recall 1.0 / stats 367, full stop→start cycle (3888/3889/
1357
+ 4602/4603/8437), compliance 8/8, smoke 8/8.
1358
+
1359
+ ## 2026-09-11 — The well is real (Mimirsbrunn / engram)
1360
+
1361
+ - **New:** `bin/mimir-bridge.py` + `bin/mimir-bridge.sh` — the `:4602` HTTP face
1362
+ the supervision tree named but that upstream never shipped (engram exposes a
1363
+ CLI + MCP server only). Endpoints: `/health`, `/recall`, `/recent`,
1364
+ `/timeline`, `/inspect`, `/observe`.
1365
+ - **New:** repo-local store `.agents/memory/kaia.engram`, seeded from the
1366
+ 368-episode JSONL well.
1367
+ - **Wired:** gate API `/api/well` now does semantic recall via the bridge (local
1368
+ file fallback) and `/api/mimir/health` is live; the Well gate's Bridge tile
1369
+ and timeline read real data (mock removed).
1370
+ - **Harnesses:** the engram MCP server is registered for OpenCode, Pi, Claude,
1371
+ Cursor, and Codex; requires the `mcp<2` SDK (`engram-mcp` breaks on mcp 2.x).
1372
+ - **Lifecycle:** the bridge is raised by `scripts/start.sh` and
1373
+ `bin/saga-session-start.sh`; the stale `engram.server` command was corrected.
1374
+ - **Verified:** bridge up (370 episodes), semantic recall, MCP handshake
1375
+ (engram 1.30), compliance 8/8, smoke 8/8.
1376
+
1377
+ ## 2026-09-11 — Stats 1:1, Kaia chat, Forge prompts
1378
+
1379
+ - **Stats:** ported the full Smiðja `StatsResponse` 1:1 into the gate API and
1380
+ the Stats gate — runs/success/fail/running/rate, token optimization
1381
+ (input/output/cache_read/cache_write, cache-hit ratio, avg CHR/run),
1382
+ local-vs-online provider split with per-model table, 40-model commercial
1383
+ catalog (cached/total/savings/%), by-chain and by-workflow. A real run
1384
+ renders live.
1385
+ - **Chat (Kaia):** per-session JSONL store (`state/chat/`), list/history/delete
1386
+ endpoints, a rolling **40-message** window, query-grounded well recall before
1387
+ every dispatch, an animated "Kaia is thinking…" indicator, a session sidebar
1388
+ (new/switch/delete), a connected-model datalist (314 models) with free-type,
1389
+ and Eindri lane toggles.
1390
+ - **Forge:** a Prompts mode to read/edit the smithy's
1391
+ `prompt_engineering/<agent>/{system,user}.md` (path-guarded save) and a
1392
+ connected-model datalist for agent models.
1393
+ - **Verified:** `tsc` + `vite build` green, live chat via local model with
1394
+ recall on, prompt roundtrip + traversal guard, compliance 8/8, smoke 8/8,
1395
+ lint 4/4.
1396
+
1397
+ ## 2026-09-11 — Smiðja views are repo-local
1398
+
1399
+ - **Change:** Removed the last external dependency. `bin/factory-observe.sh`
1400
+ (which defaulted to `~/command/factory/factory_data/factory.db`) is gone;
1401
+ `bin/smidja-observe.sh` reads the repo's own
1402
+ `smidja/smidja_data/smidja.db` read-only and reports absence honestly.
1403
+ - **API:** `/api/factory` replaced by `/api/smidja/{health,sessions,sessions/:id,decisions,stats}`
1404
+ (`bun:sqlite`, read-only).
1405
+ - **UI:** four Hlidskjalf gates added — Sessions, Trace, Decisions, Stats —
1406
+ reading the smithy's trace. No `command`/`factory` references remain in the
1407
+ runtime or portal.
1408
+ - **Verified:** `tsc` + `vite build` green, SPA 200, endpoints honest-absent,
1409
+ Galdr compliance 8/8, smoke 8/8.
1410
+
1411
+ ## 2026-09-11 — Gleipnir lock PID binding fix
1412
+
1413
+ - **Problem:** The session lock (`state/.lock`) was written with the digest
1414
+ helper's PID (a short-lived child) instead of the live Pi harness PID. The
1415
+ harness adapter (`gna-pi-watch.ts`) reported "no live session holds the lock"
1416
+ and refused to arm the watcher.
1417
+ - **Root cause:** `BROKK_SESSION_PID` was never injected into the spawn chain.
1418
+ `gleipnir_lock_acquire` fell back to `$$` (helper PID).
1419
+ - **Fix:** `.pi/extensions/syn-turnend-guard.ts` and
1420
+ `.pi/extensions/gna-pi-watch.ts` now pass `BROKK_SESSION_PID: String(process.pid)`
1421
+ in the spawn env, so the lock binds to the live Pi process.
1422
+ - **Impact:** Session lock reclamation works on next Pi session start/reload.
1423
+ The stale lock (dead PID) is overwritten by the live PID.
1424
+
1425
+ ## 2026-09-11 — Desktop shell, tunnel, and temporary auth
1426
+
1427
+ - **Electron:** `apps/hlidskjalf/electron` + `scripts/electron.sh` open Hlidskjalf
1428
+ (and Smiðja) as a native window; raises the stack if down.
1429
+ - **Tunnel:** `ymirdell.zerwiz.org` → `:3889` via `bin/gjallarhorn-tunnel.sh`
1430
+ (cloudflared config in `midgard/infrastructure/ingress/cloudflared-ymir.yml`).
1431
+ - **Auth:** hardcoded HTTP Basic (`zerwiz:allfather`, `HLIDSKJALF_AUTH`) on the
1432
+ gate API, which now also serves the built SPA. Temporary — move to Heimdall +
1433
+ `.env.local`.
1434
+ - **Mobile:** PWA manifest added; recommended APK = Capacitor over the tunnel.
1435
+
1436
+ ## 2026-09-12 — Updater forged + credential moved to env
1437
+
1438
+ - **`bin/brokk-update.sh`** — the sanctioned, guarded updater the `ymir-update`
1439
+ skill calls: fast-forward only, refuses a dirty/diverged tree, `--yes` to
1440
+ stash+restore, `--check` to report. Never force-pushes.
1441
+ - **Credential law:** the gate login (`HLIDSKJALF_AUTH`) no longer has an inline
1442
+ default; it is read from `.env.local` (Bun auto-loads it). Server falls back to
1443
+ an open gate only when unset (dev), with the key added to `.env.example`.
1444
+
1445
+ ## 2026-09-12 — Ró preference moved out of the tracked tree
1446
+
1447
+ - `.agents/config/ro` was a **git-tracked** per-user toggle (calm on/off); any
1448
+ toggle dirtied the tree and made `bin/brokk-update.sh` refuse. It now lives in
1449
+ the gitignored `state/ro`; `YMIR_RO`/`BROKK_RO` set a default; the legacy
1450
+ `config/ro` is read once for upgrade then never written. Tracked file removed.
1451
+
1452
+ ## 2026-09-12 — Fleet preferences
1453
+
1454
+ - `data/fleet.md` (gitignored) holds fleet-wide per-user settings (`ro: on|off`).
1455
+ - `bin/fleet-apply.sh` applies them to this home + every registered Eindri-home
1456
+ (into each home's gitignored `state/`; remote routes reported).
1457
+ - `bin/brokk-update.sh` re-applies fleet preferences on every sweep — one setting
1458
+ reaches the whole fleet, no tracked tree dirtied.
1459
+
1460
+ ## 2026-09-12 — House law (RULES/) and the Grein naming
1461
+
1462
+ - New `RULES/` (the house law): `01-domains.md` (house = company; domain = a
1463
+ **Grein**/**Greinar**; Eindri = specialists), `02-agents.md` (agents live only
1464
+ in `.agents/agents`; harness dirs are symlinks; no mock agents), `03-houses.md`
1465
+ (a house is a company — WayOf; the eight Labs are domains, never houses).
1466
+ - Live Fleet de-mocked (real domain/model/status; seeded stats only in demo).
1467
+
1468
+ ## 2026-09-14 — A vacant helm is entered, not punted (watcher wake repair)
1469
+
1470
+ - **Problem:** a watcher wake reported the Pi extension could not restore
1471
+ continuity — "this session no longer owns the lock". Root cause found by
1472
+ inspection: an **empty/truncated** machine lock (`~/.local/state/ymir/brokk.lock`)
1473
+ was classified by `gna-pi-watch.ts` `lockOwnership()` as `other` (another
1474
+ live session) and by `bin/syn-watch-arm.sh`'s gate as read-only — so a helm
1475
+ with *no verifiably-live holder* was refused and punted to a manual
1476
+ `saga-session-start.sh` reclaim.
1477
+ - **Fix (both seams in one change):** the extension now classifies an empty
1478
+ lock as `missing`, so `gna_watch_arm`'s reclaim takes the helm in place; the
1479
+ arm script, on finding no owner (or an owner verifiably gone), runs
1480
+ `gleipnir_lock_acquire` itself — which refuses only a genuinely live other
1481
+ session — instead of printing read-only. The "run saga-session-start.sh"
1482
+ punt is gone; a vacant helm is entered by the watcher's own hand.
1483
+ - **Verified:** scratch-state test — empty machine lock → `watcher: started`,
1484
+ lock bound to the session pid + starttime sidecar, `.supervision-armed`
1485
+ touched; `gleipnir-machine-lock.test.sh` ALL PASS (zombie, recycled,
1486
+ migration); compliance 10/10; harness-integration asset updated in the same
1487
+ change (the governed rule).
1488
+
1489
+ ## 2026-09-14 — The Eindri→Brokk wake bridge (they can talk back now)
1490
+
1491
+ - **Ask:** the seated smiths' reports lived in their panes only; the Allfather
1492
+ wanted a feature that wakes Brokk when an Eindri reports, so the fleet's
1493
+ doings reach the primary's session — "we are in control, Brokk".
1494
+ - **Built:** `bin/eindri-seen.sh` (condition — a report file landed or herdr
1495
+ shows the smith left `working`), `bin/eindri-acclaim.sh` (action — files the
1496
+ report durably under state/eindri-reports/, marks done under
1497
+ state/eindri-done/, appends the wake to state/.wake-queue for Sága's drain,
1498
+ sounds the desktop note), and `bin/eindri-watch.sh` (the control door —
1499
+ `arm | retire | list | reconcile`, one when-source per smith on the Norns'
1500
+ loom via fm-procevent-when.sh, action hash-bound, fires once on a stable
1501
+ true, terminal, re-armable).
1502
+ - **Armed live:** when-odrerir (already fired — his report was filed) and
1503
+ when-sessrumnir-cloth (still working). `fm-procement.sh reconcile` started=2.
1504
+ - **First report delivered through the wire:** odrerir's Óðrerir saga — deck
1505
+ green at :4322, 52 Chromium checks, commit 38a326b on yggdrasil/odrerir, main
1506
+ untouched, plus the hall.ymir.zerwiz.org server story (setup-hall.sh) and
1507
+ three asks awaiting the Allfather (go live, landing mobile wart, PLAN log).
1508
+
1509
+ ## 2026-09-14 — Óðrerir forged (Eindri odrerir, pane w3:p7)
1510
+
1511
+ - The Live Hall carved on the landing per PLAN.md §14: dealt slate pile,
1512
+ choices + recommended marks, freeform, queue + limit guard, thread ledger,
1513
+ live tally, four empty states, fail-closed, keyboard, reveal, mobile (390px,
1514
+ zero overflow); cloth check green; §12 scan clean. Deployed plan for the
1515
+ public hall: hall.ymir.zerwiz.org via a second Caddy site :4322 (deploy/
1516
+ setup-hall.sh + tunnel-ingress.sh, idempotent, live provisioning untested).
1517
+
1518
+ ## 2026-09-14 — The echo guard: no wake flood through Gná's door
1519
+
1520
+ - **Problem:** during a loud stretch (stale wake lines + the FM runner's
1521
+ durable queue holding ten old check-wakes), the watcher re-armed and
1522
+ re-signalled "signal: wake queue" across many generations; every actionable
1523
+ close queued one pi follow-up wake (`sendWake`, no dedup), which then
1524
+ dripped at the Allfather one per prompt — a long echo flood after the
1525
+ sources were drained.
1526
+ - **Fix:** `gna-pi-watch.ts` `sendWake` is **echo-guarded**: an identical
1527
+ watcher message is delivered at most once per drained state — when both
1528
+ durable doors (`state/.wake-queue` and the FM runner's
1529
+ `.agents/state/.wake-queue`) are empty, a repeat carry is the same drained
1530
+ news and is skipped. Genuine new content (different message, or a door with
1531
+ a line) always delivers. Harness asset updated in the same change.
1532
+
1533
+ ## 2026-09-16 — one login for every app on the web; the gate fronts them all
1534
+
1535
+ - **Every app host is gated**, not just Smíðja. The gate now routes by host from
1536
+ an `APP_HOSTS` table and fronts each one: unauthenticated visitors get that
1537
+ app's own sign-in page, an API path gets 401, and the desktop seat (loopback +
1538
+ marker) walks straight in. Verified: `smidjadell…` → *Smíðja — Sign in*,
1539
+ `odrerirdell…` → *Óðrerir — Sign in*, API 401, desktop seat 200 (the hall).
1540
+ - **Every public hostname points at the gate (:3889)** — never at an app's own
1541
+ port. That was a hole straight past the login: `gjallarhorn-expose.sh` had been
1542
+ exposing each app on its own port, so the app answered the world directly.
1543
+ - **The gate learns the host map at start** (`state/gjallarhorn-hosts.env`,
1544
+ written by the expose script and sourced by `scripts/start.sh`), so routing is
1545
+ not an accident of whoever launched it last.
1546
+ - **No guessed credentials.** The generated tunnel config wrote
1547
+ `credentials-file: …/ymir.json`; cloudflared names that file for the tunnel's
1548
+ UUID, so it refused to start and the world got 530. The line is gone —
1549
+ cloudflared resolves a named tunnel's own credentials.
1550
+ - Verified through the tunnel: `https://ymirdell.zerwiz.org/` → 200. The app
1551
+ hostnames still answer 530: their DNS routes were made against an earlier
1552
+ tunnel and need re-creating (`cloudflared tunnel route dns ymir <host>`).
1553
+
1554
+ ## 2026-09-16 — NO BLUE: the forge language replaces the old blue
1555
+
1556
+ The blue had a name. It was the platform's own house tint, `--ymir-house-ymirlabs:
1557
+ #38bdf8`, carried into every surface that wears Ymir's colours — the login, the
1558
+ emblem, the realm data, the Smíðja chrome. The design doctrine (homepage repo,
1559
+ `DESIGN-UNIFICATION-PLAN.md`) says the landing page **is** the language, and that
1560
+ language is **forge**: stone ground (`#0e0c09`), bronze accent (`#c9973f`), bone
1561
+ text (`#cfc3a9`).
1562
+
1563
+ - `midgard/design-system/tokens.css` — the house tint is bronze now, with the
1564
+ reason recorded in the token itself.
1565
+ - The blue's footprints removed: `Emblem.tsx`, `state/store.ts`, `data/realms.ts`
1566
+ (Hlidskjalf), `style.css` (Smíðja visualizer), and Sessrúmnir's terminal accent
1567
+ fallback.
1568
+ - Both built stylesheets rebuilt and verified: **zero blue** in the CSS the browser
1569
+ actually receives (`apps/hlidskjalf/dist`, the visualizer's `dist`).
1570
+ - The visualizer's build was failing on my own earlier edit (unused imports left
1571
+ when I moved `repoRootOf` into `db.ts`) — fixed, so `bun run build` is green.
1572
+
1573
+ The canonical token home is answered by what already exists: `midgard/design-system/`
1574
+ (tokens, icons, `ymir-mark.svg`, `icons.md`) — one source the apps import, so a
1575
+ colour changes once.
1576
+
1577
+ ## 2026-09-16 — every app wears its own rune
1578
+
1579
+ The icon set is runecoded (`midgard/design-system/icons.md`): an Elder Futhark
1580
+ rune, stroked at the chisel bevel, tinted by the app's house colour. The apps were
1581
+ wearing the generic Ymir mark — or, worse, the old **blue** logo.
1582
+
1583
+ - **`bin/design-icon.sh`** mints an app's icon from a glyph plus a house tint: a
1584
+ stone tile with the rune stroked in bronze. `list` shows the mapping.
1585
+ - Minted and wired: **Hlidskjalf** `ehwaz` ᛖ (the seat), **Óðrerir** `valhalla` ᚹ
1586
+ (the hall), **Sessrúmnir** `sowilo` ᛊ (the sun), **Smíðja** `ansuz` ᚨ (Odin's
1587
+ breath — the forge). Óðrerir already carried a forge-coloured favicon set.
1588
+ - **The blue logo is retired**: `public/logo.svg` removed, and Smíðja's *inline*
1589
+ copy in `App.vue` — the mark in its own header, still `#0f172a`/`#1e293b` —
1590
+ replaced with the ansuz rune in bronze. Rebuilt; no blue in the bundle.
1591
+
1592
+ ### The hearth stays, and spreads
1593
+
1594
+ Sessrúmnir's background fire is **`EmberBackground`** — 26 embers rising with a
1595
+ gentle sway on a canvas, *"the hearth of the landing page, carried into the
1596
+ chat"* — used by its home screen and chat panel. It stays. Next: one shared
1597
+ ember (a framework-neutral `midgard/design-system/ember.js` with a
1598
+ `prefers-reduced-motion` guard) so Hlidskjalf's shell, the login screen,
1599
+ Óðrerir's hall and the Smíðja chrome can warm the same fire.
1600
+
1601
+ ## 2026-09-16 — the hearth spreads: one fire, three more surfaces
1602
+
1603
+ Sessrúmnir's fire is now shared rather than copied. `midgard/design-system/ember.js`
1604
+ is the framework-neutral original (the land page's Ginnungagap embers: 30 rising
1605
+ with a gentle sway over six drifting haze pools), with `ember.d.ts` for TypeScript
1606
+ consumers and a reader who asked for less motion gets a **still frame** instead of
1607
+ an animation.
1608
+
1609
+ Wired, and built:
1610
+
1611
+ - **Hlidskjalf** — `src/components/EmberBackground.tsx` imports the shared module;
1612
+ mounted behind the *login* and behind the *shell*, so the door and the hall burn
1613
+ over one hearth.
1614
+ - **Smíðja visualizer** — a `<canvas class="ember-bg">` behind every view.
1615
+ - **Óðrerir** — a `data-ember` canvas in its shell, so the hall warms too.
1616
+ - Sessrúmnir keeps its own React port untouched (two ports of one fire, the same
1617
+ physics; consolidating them on the shared module is the next tidy).
1618
+
1619
+ And the reference for the missing furniture: **Óðrerir already carries it all** —
1620
+ four favicons, `mask-icon` in bronze, `site.webmanifest`, canonical, description,
1621
+ theme-colour and Open Graph. The other apps should be brought up to *it*.
1622
+
1623
+ ## 2026-09-16 — icons the operator can pin, and one pair of hands for the shells
1624
+
1625
+ **"Fail, no icons" — and the cause was a trap I had already been bitten by.**
1626
+ `bin/design-icon.sh install` writes an app's rune into the icon theme and a
1627
+ `.desktop` entry into the applications dir. It used `XDG_DATA_HOME`, and this
1628
+ agent session exports that as a **sandbox** (`…/opencode-rd`), so the icons went
1629
+ somewhere no desktop can see. It now targets the operator's real data dir
1630
+ (`$HOME/.local/share`, with `YMIR_DESKTOP_DATA_HOME` for a throwaway test) — the
1631
+ same class of bug that once hid `gh` from this session.
1632
+
1633
+ Installed now, for **every** app: hlidskjalf, **odrerir**, **sessrumnir**, the
1634
+ Smíðja visualizer and hlidskjalf-mobile — each with its rune icon and a dockable
1635
+ entry. Óðrerir and Sessrúmnir had **none**, which is exactly why they could not
1636
+ be pinned. The stale `ymir-smidja.desktop` (pointing at a repo PNG) is folded
1637
+ into the rune's own entry.
1638
+
1639
+ **One pair of hands for two lifecycles.** `scripts/start.sh` and
1640
+ `scripts/stop.sh` manage the web; `scripts/electron.sh` manages the shells — and
1641
+ they never met, which is why "the electrons are not running" was true while 28
1642
+ processes stood, and why a restart could leave a shell watching a dead port.
1643
+ `scripts/raise.sh` / `scripts/lower.sh` own both: lower takes the windows down
1644
+ **first**, so none is left watching a port that just vanished.
1645
+
1646
+ **A bug the restart surfaced:** `scripts/electron.sh stop` used `local` outside a
1647
+ function — it worked only because the assignment happened to be harmless, and it
1648
+ printed a shell error on every stop. Fixed.
1649
+
1650
+ **And the inventory is a tool:** `bin/feature-inventory.sh` — 132 tools, 5 jobs,
1651
+ 26 skills, 20 agents, 8 workflows, 6 apps, 4 migrations, 6 registered projects,
1652
+ each with the way it must be proven written beside it.
1653
+
1654
+ ## 2026-09-16 — the icons are real runes now (eight of them were drawings)
1655
+
1656
+ The Allfather looked at the icons and said what no check had: *"the icons must be
1657
+ based on real runes."* He was right, and the fault was in the **glyph set**, not
1658
+ just in the two icons I had minted.
1659
+
1660
+ `midgard/design-system/icons.md` claims every glyph is an Elder Futhark rune and
1661
+ gives each its unicode. **Eight of the twenty-one files were drawings** — a hall
1662
+ (`valhalla`, which Óðrerir was wearing), a horn, a shield, a spear, a well, a
1663
+ squirrel, a gate, a world-tree. Replaced with the real runes their own rows
1664
+ declare:
1665
+
1666
+ ```
1667
+ gjallarhorn ᚷ Gebo · gungnir ᚦ Thurisaz · heimdall ᚺ Hagall · mimirsbrunn ᛜ Ingwaz
1668
+ ratatoskr ᛒ Berkanan · utgard ᚢ Uruz · valhalla ᚹ Wunjo · yggdrasil ᛃ Jera
1669
+ ```
1670
+
1671
+ Gungnir was claiming Gebo, which Gjallarhorn already holds, so it takes
1672
+ **Thurisaz** (the thorn — the spear) and `icons.md` is corrected to match.
1673
+
1674
+ **Five apps, five different runes:** Hlidskjalf `ehwaz`, mobile `raidho` (the
1675
+ road), Óðrerir `valhalla`→ now genuinely `ᚹ Wunjo`, Sessrúmnir `sowilo`, Smíðja
1676
+ `kaunan` (the torch). The install table drives both mint and install now — it had
1677
+ been guessing paths, which is why the Smíðja visualizer had been given
1678
+ Hlidskjalf's icon.
1679
+
1680
+ Also this pass: the visualizer gained its furniture (description, canonical,
1681
+ manifest, OG + Twitter), Óðrerir's Electron shell asks for a window icon, and the
1682
+ apple-touch PNGs are rasterised (ImageMagick is present).
1683
+
1684
+ ## 2026-09-16 — the desktop never dials out: Cloudflare stays outside Electron
1685
+
1686
+ The Allfather's rule: **"electron should never have anything with cloudflare to
1687
+ do."** It was not quite true — three doors stood open:
1688
+
1689
+ - **Sessrúmnir's "To the Hall"** preferred the local hall and, when it did not
1690
+ answer, fell back to `https://hall.ymir.zerwiz.org`. A desktop seat that
1691
+ reaches for a public hostname when its own machine is quiet is a seat that
1692
+ leaves the building to do its errands. It is now **local only** — when the hall
1693
+ is not running, the seat says so.
1694
+ - **Hlidskjalf's shell** took `HLIDSKJALF_URL` and `SMIDJA_URL` from the
1695
+ environment, and **Óðrerir's** took `HALL_URL` — each able to point a desktop
1696
+ window at a tunnel with one exported variable.
1697
+ - Both now pass their URL through a **loopback guard**: anything that is not
1698
+ `127.0.0.1`, `localhost` or `::1` is refused with a warning and replaced by the
1699
+ local default. The shell loads the machine, never the internet.
1700
+
1701
+ **Why this is the same fight as the bridge:** a desktop app that dials out is a
1702
+ desktop app whose failures belong to somebody else's edge. The bridge disguised a
1703
+ cloud endpoint as `127.0.0.1` and cost a night; these three would have disguised a
1704
+ tunnel as a local seat.
1705
+
1706
+ ## 2026-09-16 — the panels that crashed, the gate that lied, and the well that would not open
1707
+
1708
+ - **Statistics now reports the HARNESSES** (pi + opencode), not the smithy's runs.
1709
+ `bin/hlidskjalf-usage.sh` aggregates opencode's SQLite token store and both pi
1710
+ stores, and emits the numbers under the names the gate renders (`gate{}`):
1711
+ totals, usage, providers local/online with per_model, by_chain, by_model.
1712
+ Verified: 21,497 runs (opencode 21,422 · pi 75) · 331.5M tokens ·
1713
+ local 239,623 / online 331,289,420 · cache-hit 91.5%.
1714
+ - **A failed fetch no longer takes the hall down.** Endpoints answering `{error}`
1715
+ were handed to panels as data — Rail read `.filter` on an object, Stats read
1716
+ `.totals` on a string, and both crashed. The store now runs every bootstrap
1717
+ answer through `ok()`: an error keeps the last good value.
1718
+ - **`/api/usage` was answering with a traceback** while the script passed by hand:
1719
+ the gate process had been started before the fix and caches a failure for 60s.
1720
+ Restarted; the endpoint serves the harness numbers.
1721
+ - **The engram MCP (`-32000: Connection closed`) is mended.** Not config, not the
1722
+ engram package: `python3.12 -c "import mcp"` failed because the system
1723
+ `python3-rpds-py` ships without its compiled `rpds.rpds` module, which
1724
+ `jsonschema` (inside `mcp` 1.x) imports. Mended with
1725
+ `python3.12 -m pip install --user --break-system-packages --force-reinstall rpds-py`
1726
+ (plus `mcp<2` under python3.12). The server now starts and waits on stdio.
1727
+ Eir should check this pair: `mcp` present for the interpreter that runs the
1728
+ binary, and `rpds` importable.
1729
+
1730
+ ## 2026-09-17 — Sessrúmnir stops wearing Pi's clothes
1731
+
1732
+ - **The naming law, broken at the root.** Clicking the Sessrúmnir icon opened a
1733
+ window titled **Pi Desktop**: `apps/sessrumnir` is the Pi Desktop shell adopted
1734
+ whole, and its product name was still Pi's —
1735
+ `export const PI_DESKTOP_PRODUCT_NAME = 'Pi Desktop'` — rendered as the heading on
1736
+ the home screen, the sidebar and the chat panel. That is the title the Allfather
1737
+ saw, twice, on every launch.
1738
+ - **Mended at the name:** `SESSRUMNIR_PRODUCT_NAME = 'Sessrúmnir'` (Odin's hall of
1739
+ many seats), the three rendering components walked, and the old constant kept as an
1740
+ alias so no unwalked import breaks. `tsc --noEmit` exit 0.
1741
+ - **Still owed:** 1,255 English strings, **86 of them naming Pi** ("Pi is working",
1742
+ "Quit Pi Desktop", "Pi Desktop v{{latestVersion}} is available", "Start Pi/OMP
1743
+ before planning with Council"), and Pi's logo on the home screen. The locale is the
1744
+ one place they live — that pass is the order, not a patch.
1745
+ - Also in the launcher this session: an icon click now raises THE SYSTEM (converge
1746
+ the service, reborn a windowless app, focus a live window), and `stop --view X`
1747
+ stops only X — the loop that killed every view is gone. The Hall's own outage had
1748
+ a cause: an Astro dev server on :4323 while the app waited on :4322.
1749
+
1750
+ ## 2026-09-17 — the smithy can see the well
1751
+
1752
+ - **Why the memory looked absent in the smithy:** the visualizer proxies the bridge's
1753
+ `/inspect`, and `/inspect` reported three fields — store, episodes, agents — while
1754
+ the well holds six layers. A panel told only the episode count cannot show that
1755
+ facts, entities and reflections exist. `/inspect` now reports them all:
1756
+ episodes, facts (active/superseded), entities, edges, reflections (with the last
1757
+ run's time) and the vector index.
1758
+ - **Through the smithy right now:**
1759
+ `store $YMIR_HOME/memory/kaia.engram · episodes 8 · facts 36 (35 active) ·
1760
+ entities 60 · edges 480 · reflections 1 (2026-09-16T21:01) · vec index 8`.
1761
+ - **A trap found while doing it:** restarting the bridge RAW (`python3 bin/mimir-bridge.py`)
1762
+ loses the env that carries the well's path, and the bridge silently re-points at the
1763
+ old store in the repo — 364 stale episodes and no facts. The well is the **blessed
1764
+ starter's** to raise: `bin/mimir-bridge.sh --start`. A raw restart is a different
1765
+ well wearing the same port.
1766
+
1767
+ ## 2026-09-17 — Skrymir opens the hoard, not the checkout
1768
+
1769
+ - **The file browser was rooted in the wrong tree.** `workspaceRoot()` built every
1770
+ realm path under `ROOT` — the checkout — so `work` resolved to a directory that does
1771
+ not exist and the walk fell back to the repo's `docs/`. That is why Skrymir showed
1772
+ `lore.md`, `Architecture.md`, `research/`, `runbooks/`, and why a file it had just
1773
+ listed answered **"not found"**: the listing came from one tree and the read from
1774
+ another.
1775
+ - **The hoard first now (Rule 04):** `$YMIR_HOME/svartalfaheim/<realm>` → company
1776
+ container → `$YMIR_HOME/workspace/<realm>` → the checkout only as legacy. An empty
1777
+ realm shows the hoard's home, never the repo's docs. Verified: `work` lists
1778
+ `memory/daily/2026-09-13.md` and `workspace/`, and a read returns its body.
1779
+ - Note for the next hand: the gate runs **without** `--watch` — a server edit is on
1780
+ disk and not in the process until `scripts/start.sh` raises it again.
1781
+
1782
+ ## 2026-09-17 — the Fleet was a rack of terminals; now it is the roster
1783
+
1784
+ - **We were tracking the tools.** `.agents/agents/` holds **21 agent definitions** —
1785
+ Brokk, Sindri, Bragi, Forseti, Mímir, Kvasir, Snotra, Huginn, Hnoss, Sága, Muninn,
1786
+ Frigg, Gróa, Jörð, Sýn, Týr, Galdr… — and the Fleet served **13 panes all named
1787
+ "OpenCode"**, role `opencode`. The board showed seats and never the smiths who might
1788
+ be standing in them.
1789
+ - **`bin/hlidskjalf-agents.sh` now reads the roster** (`.agents/agents/*.md`, canonical
1790
+ per RULES/02) and joins each agent to its standing pane: figure, craft, model from
1791
+ the definition's frontmatter, and `live{}` only when a pane answers to it. An
1792
+ **unseated agent is still an agent** — hiding it is what made the board a rack.
1793
+ - Harness seats that answer to no one on the roster are kept visible and named
1794
+ honestly, never dressed as agents.
1795
+ - Served: **34 entries — 21 agents (roster first) + 13 harness seats, 14 joined**.
1796
+
1797
+ ## 2026-09-17 — the extensions deployed without their modules
1798
+
1799
+ - **pi would not start a seated worker, and the reason was a half-deploy.**
1800
+ The four shared pi extensions all reported
1801
+ `Failed to load extension: Cannot find module ./lib/<module>.ts` — and every one
1802
+ of those modules was present in the repo, one level away under the extensions'
1803
+ own `lib/`. The loader copied the top-level extension files and never their
1804
+ supporting modules.
1805
+ - **Mended in two places.** (1) The missing modules are now beside the deployed
1806
+ extensions, so a running pi loads all four. (2) `bin/valknut-load.sh` — the
1807
+ loader — now deploys that lib alongside the extensions, idempotently (identical
1808
+ files untouched), so a fresh machine cannot hit it. A deploy that copies a file
1809
+ but not the module it imports is not a deploy.
1810
+ - **What this cost:** the Forseti audit was seated on a **local** model, and the
1811
+ pane fell back to a bare shell when pi could not start — which is why the brief
1812
+ was typed at a prompt and answered `bash: syntax error near unexpected token '('`.
1813
+ With the extensions mended, pi's remaining blocker is the model: the llama-router
1814
+ has no raisable seat tonight (`:8080` unbound, and the installed llama.cpp cannot
1815
+ load the Apodex weights), so a local-first dispatch has nothing to reach.
1816
+
1817
+ ## 2026-09-17 — the well as tools: Ymir's first custom pi extension
1818
+
1819
+ - **Why the extension tree was failing, from the upstream law:** pi auto-discovers
1820
+ extensions from BOTH the global home and the project-local tree. The same extension
1821
+ in both loads twice and pi refuses the duplicate tool —
1822
+ `Tool "gna_watch_arm" conflicts with …`. Ymir's own loader already says the shared
1823
+ extensions have **one** home; the tree contradicted it by carrying the extension
1824
+ files project-locally as well.
1825
+ - **Built: `ymir-well`** — the well, as tools inside every pi session.
1826
+ `well_recall(query, k)` reads Kaia's memory before work begins;
1827
+ `well_observe(content, tags, actors, salience)` writes the lesson after. Written in
1828
+ the house voice, honest about failure (a failed write says the lesson was NOT
1829
+ written), and it sends tags as LISTS — a comma-string is stored as an array of
1830
+ characters, which is exactly how a recall once returned `['r','u','n']`.
1831
+ - Authored in the SHARED source and deployed to the global home — one home, never a
1832
+ project copy. That is the pattern every future Ymir extension follows.
1833
+
1834
+ ## 2026-09-17 — the duplicate extensions removed from the project tree
1835
+
1836
+ - **The fault, now measured exactly.** The project-local extension tree carried four
1837
+ files that the shared source also carries — `gna-pi-watch.ts`, `ro.ts`,
1838
+ `skuld-branch-supervision.ts`, `syn-turnend-guard.ts`. pi auto-discovers both the
1839
+ global home and the project tree, so each loaded twice and pi refused the second
1840
+ copy of every tool: `Tool "gna_watch_arm" conflicts with …`. Every `pi` start in
1841
+ every worktree died on it, which is why a seated worker fell back to a shell.
1842
+ - **The fix:** those four files are gone from the project tree. What remains there is
1843
+ `lib/` — the modules the *global* extensions import — and its README. The
1844
+ extensions themselves live in the shared source and in the one global home.
1845
+ - The seatbelt refused the plain shapes (`rm`, `mv`, `>`-bearing commands) on this
1846
+ path and named the remedy: *a reviewed commit*. This is that commit.
1847
+
1848
+ ## 2026-09-17 — smoke test all UI: two checks that lied about their own subjects
1849
+
1850
+ - **The truth gate failed on my own change.** It demanded the connector's total equal
1851
+ the herdr pane count; the connector is roster-first now, so it legitimately reports
1852
+ agents AND seats (33 vs 13 panes). Panes are a subset of what the board must show.
1853
+ Corrected: a FAIL now means FEWER entries than panes — a standing seat hidden from
1854
+ the board — which is the fault worth catching. **Verdict: PASS.**
1855
+ - **The smoke test reported a present database absent.** It looked for the smithy's db
1856
+ at the repo path; the runtime keeps it under `$YMIR_HOME/smidja/`, which is where
1857
+ the bootstrap and the gate both resolve it. Same wound as Skrymir and the well: the
1858
+ check and the owner disagreeing about where the record lives. **Now: OK, 8 tables.**
1859
+ - **Smoke test all UI: 5/5 OK** — spa, api, well, smidja-db, loaders. Truth gate: PASS.
1860
+
1861
+ Also mended in the same pass: `StatusChip` read `STATUS_META[status].tone`, and the
1862
+ fleet now reports a status it was never taught (`seated`), so an unknown status threw
1863
+ and killed the gate. An unknown status can no longer take a panel down.
1864
+
1865
+ ## 2026-09-17 — Glitnir stops hanging, and one process is one row
1866
+
1867
+ - **`/api/reviews` ran two 60-second shell checks on every poll**, so the review board
1868
+ hung for a minute and read as a dead surface. It is memoised for a minute now, the
1869
+ same discipline the usage endpoint already follows: a board a human reads does not
1870
+ need an answer fresher than its own usefulness.
1871
+ - **`/api/processes` returns the same id twice** — `systemd:dbus` arrives from two
1872
+ sources, 45 entries for 44 processes. The panel dedupes by id, so a repeated process
1873
+ renders as the one process it is, and React is no longer handed a duplicate key.
1874
+ The duplicate at the source is recorded, not hidden.
1875
+ - `/api/stream` answers 200; the live stream is not broken, it was the window.
1876
+
1877
+ ## 2026-09-17 — the fleet stops colliding: a grid fan, and each smith's own house
1878
+
1879
+ - **The Fleet graph collided above ~8 agents.** `Fleet.tsx` fanned every
1880
+ non-hub agent into a single two-row line at ~4.4% pitch on 46px rings — with
1881
+ 20 roster cards the rings and labels overlapped into an unreadable pile.
1882
+ `layout()` now fans a square-ish grid (`cols = ceil(sqrt(n))`, hub at top,
1883
+ rows pitched past ring+label), so 20 agents render separated.
1884
+ - **Every ring showed the same rune.** `bin/hlidskjalf-agents.sh` hardcoded
1885
+ `domain: ymirlabs` for every card and its roster parser never read the
1886
+ `domain:` frontmatter each figure carries — so all twenty cards wore the
1887
+ anonymous ᛦ. The roster now parses `domain:` and passes it through;
1888
+ `galdr.md` names its house (`brokkforge`); the graph falls back to
1889
+ `DOMAINS.ymirlabs` only when a domain is genuinely unknown (was a crash)
1890
+ — and the `AgentCard` already fell back safely.
1891
+
1892
+ galdr-reread: `.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md` — the
1893
+ Fleet graph paragraph (grid fan, roster domains, fallback).
1894
+
1895
+ ## 2026-09-17 — the apps leave the monorepo; installation pulls them from their own repos
1896
+
1897
+ - **The app split lands in the installer.** The five apps (hlidskjalf,
1898
+ hlidskjalf-mobile, odrerir, sessrumnir, smidja) now live in their own repos
1899
+ registered in the home registry (`$HOARD/identity/projects.yaml`) — the
1900
+ monorepo never tracks them, and **`step_apps`** clones or fast-forwards each
1901
+ `apps/<path>` from its registered `git{}` block (never guessing a remote,
1902
+ always reading the registry). The smithy engine (`apps/smidja`) is stamped
1903
+ from the cloned factory's `templates/smidja`, exactly as `install.py` does
1904
+ for a target repo — so a fresh clone still gets a working smithy.
1905
+ - **The vendored app trees leave the index.** `apps/{hlidskjalf,
1906
+ hlidskjalf-mobile,odrerir,sessrumnir,smidja,smidja-factory}` are gitignored
1907
+ and `git rm --cached`-ed (751 files, 135k lines); `apps/README.md` stays.
1908
+ A dir present that is not a git clone is reported (`move it aside and
1909
+ re-run`) rather than silently replaced.
1910
+
1911
+ galdr-reread: `.agents/skills/galdr-ymirsystem/assets/installation.md` — the
1912
+ step table (`22 steps`, `24` `step_*` functions), the new `apps` row, and the
1913
+ Sessrúmnir rows now say "its own repo", not "vendored".