@zerwiz/ymir 0.1.13 → 0.1.15

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 (78) hide show
  1. package/.agents/agents/brokk.md +10 -9
  2. package/.agents/agents/forseti-reviewer.md +2 -2
  3. package/.agents/agents/mimir-planner.md +2 -2
  4. package/.agents/assets/agents/registry.md +22 -0
  5. package/.agents/config/agents.yaml +53 -0
  6. package/.agents/config/{cron.yaml → cron.yaml.example} +5 -3
  7. package/.agents/config/tailscale-sync.yaml +9 -0
  8. package/.agents/config/wedge-alarm +3 -0
  9. package/.agents/migrations/0003-private-data-separation.sh +4 -4
  10. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +6 -1
  11. package/.agents/skills/galdr-ymirsystem/assets/installation.md +5 -4
  12. package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +5 -5
  13. package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +59 -4
  14. package/.agents/skills/galdr-ymirsystem/assets/registry.md +74 -338
  15. package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +1 -1
  16. package/.agents/skills/galdr-ymirsystem/assets/smidja.md +5 -3
  17. package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +1 -1
  18. package/.agents/skills/ratatoskr-a2a/SKILL.md +1 -1
  19. package/.agents/skills/tyr-check/SKILL.md +5 -5
  20. package/.agents/skills/ymir-host/SKILL.md +1 -1
  21. package/.agents/state/.wake-queue +0 -0
  22. package/.agents/state/.wake-queue.seq +1 -0
  23. package/.agents/state/.watcher-down +1 -0
  24. package/.agents/state/procevent-inbox/when-hall-button.1.adapter +1 -0
  25. package/.agents/state/procevent-inbox/when-hall-button.1.handled +0 -0
  26. package/.agents/state/procevent-inbox/when-hall-button.1.result +8 -0
  27. package/.agents/state/procevent-inbox/when-hall-button.2.adapter +1 -0
  28. package/.agents/state/procevent-inbox/when-hall-button.2.handled +0 -0
  29. package/.agents/state/procevent-inbox/when-hall-button.2.result +5 -0
  30. package/.agents/state/procevent-inbox/when-odrerir.1.adapter +1 -0
  31. package/.agents/state/procevent-inbox/when-odrerir.1.handled +0 -0
  32. package/.agents/state/procevent-inbox/when-odrerir.1.result +8 -0
  33. package/.agents/state/procevent-inbox/when-odrerir.2.adapter +1 -0
  34. package/.agents/state/procevent-inbox/when-odrerir.2.handled +0 -0
  35. package/.agents/state/procevent-inbox/when-odrerir.2.result +5 -0
  36. package/.agents/state/procevent-inbox/when-odrerir.3.adapter +1 -0
  37. package/.agents/state/procevent-inbox/when-odrerir.3.handled +0 -0
  38. package/.agents/state/procevent-inbox/when-odrerir.3.result +5 -0
  39. package/.agents/state/procevent-inbox/when-odrerir.4.adapter +1 -0
  40. package/.agents/state/procevent-inbox/when-odrerir.4.handled +0 -0
  41. package/.agents/state/procevent-inbox/when-odrerir.4.result +8 -0
  42. package/.agents/state/procevent-inbox/when-odrerir.5.adapter +1 -0
  43. package/.agents/state/procevent-inbox/when-odrerir.5.handled +0 -0
  44. package/.agents/state/procevent-inbox/when-odrerir.5.result +8 -0
  45. package/.agents/state/procevent-inbox/when-sessrumnir-cloth.1.adapter +1 -0
  46. package/.agents/state/procevent-inbox/when-sessrumnir-cloth.1.handled +0 -0
  47. package/.agents/state/procevent-inbox/when-sessrumnir-cloth.1.result +8 -0
  48. package/AGENTS.md +17 -10
  49. package/CHANGELOG.md +129 -0
  50. package/bin/a2a-mcp.sh +9 -2
  51. package/bin/app-lib.sh +8 -1
  52. package/bin/docs-guard.sh +1 -1
  53. package/bin/erindi-brief.sh +1 -1
  54. package/bin/hamr-harness.sh +1 -1
  55. package/bin/hoard-lib.sh +10 -0
  56. package/bin/mimir-bridge.py +8 -1
  57. package/bin/mimir-bridge.sh +7 -1
  58. package/bin/mimir-reflect.sh +8 -1
  59. package/bin/nornir-cron-start.sh +21 -1
  60. package/bin/nornir-job-bragi-scrape.sh +116 -0
  61. package/bin/nornir-job-daily-briefing.sh +7 -7
  62. package/bin/nornir-job-forgejo-git.sh +87 -0
  63. package/bin/nornir-job-observer.sh +5 -4
  64. package/bin/rodd-operational-input.sh +1 -1
  65. package/bin/saga-session-start.sh +4 -3
  66. package/bin/sessrumnir.sh +11 -0
  67. package/bin/syn-arm-pretool-check.sh +1 -1
  68. package/bin/syn-cd-pretool-check.sh +1 -1
  69. package/bin/syn-watch-arm.sh +1 -1
  70. package/bin/vor-crew-state.sh +1 -1
  71. package/bin/ymir-install.sh +47 -2
  72. package/bin/ymir-marketing-stack.sh +323 -0
  73. package/docs/runbooks/models.md +1 -1
  74. package/docs/workspaces.md +4 -0
  75. package/package.json +10 -4
  76. package/scripts/electron.sh +2 -2
  77. package/.agents/bus/messages.json +0 -1
  78. package/.agents/config/agents.machine.example.yaml +0 -16
@@ -27,8 +27,8 @@ Every output must land in the correct path. No exceptions.
27
27
  | Personal / Schedules | `svartalfaheim/<realm>/workspace/life/` |
28
28
  | Daily logs | `svartalfaheim/<realm>/workspace/memory/daily/YYYY-MM-DD.md` |
29
29
  | Shared company assets | `midgard/` |
30
- | Global audit entries | `workspace/memory/runes_audit.md` |
31
- | Architecture & plans | `docs/plans/` |
30
+ | Global audit entries | `hodd/memory/runes_audit.md` (in `$YMIR_HOME`) |
31
+ | Architecture & plans | `$YMIR_HOME/memory/plans/<domain>/` |
32
32
  | Skills (new) | `.agents/skills/<norse-name>/SKILL.md` |
33
33
  | Sub-agent roles | `.agents/subagents/<role>.md` |
34
34
 
@@ -40,14 +40,14 @@ Every output must land in the correct path. No exceptions.
40
40
 
41
41
  Two files are sacred — you APPEND, never rewrite:
42
42
 
43
- ### `docs/masterplan.md`
43
+ ### `$YMIR_HOME/hodd/docs/masterplan.md`
44
44
  - Forge orders live here (W0001, W0002, …)
45
45
  - New work: append at end of Backlog with next W-number
46
46
  - Close work: append `+ <date> COMPLETED — <what>` under the order
47
47
  - Never rewrite a status in place
48
48
  - Queue is the one exception — republish with a move note
49
49
 
50
- ### `docs/append-only-log.md`
50
+ ### `$YMIR_HOME/hodd/docs/append-only-log.md`
51
51
  - Every significant action gets an ENTRY
52
52
  - Format: `## ENTRY YYYY-MM-DD-NNN — <title>`
53
53
  - Fields: Status, Owner, Context, ADD, NOT, KEEP, Files
@@ -148,18 +148,19 @@ Output is TOON format. Exit codes: 0=success, 1=error, 2=usage error.
148
148
 
149
149
  ## 8. PLAN DOCS — How to Read and Write Plans
150
150
 
151
- Plans live in `docs/plans/`. Each is a markdown file with:
151
+ Plans live in `$YMIR_HOME/memory/plans/<domain>/` (live working plans in
152
+ `$YMIR_HOME/hodd/plans/`). Each is a markdown file with:
152
153
  - Title and status (proposed → approved → in-progress → done)
153
154
  - Scope, dependencies, acceptance criteria
154
155
  - Source references (ENTRY numbers, Architecture.md sections)
155
156
 
156
- The plan index is at `docs/plans/README.md`.
157
+ The plan index is at `$YMIR_HOME/memory/plans/README.md`.
157
158
 
158
159
  When creating a new plan:
159
- 1. Use the next available number (currently plans 01–27 exist)
160
+ 1. File it under the right domain folder in `memory/plans/` (core, mesh, portal, …)
160
161
  2. Follow the template in `.agents/assets/templates/`
161
- 3. Reference relevant ENTRY numbers from append-only-log.md
162
- 4. Update `docs/plans/README.md` index
162
+ 3. Reference relevant ENTRY numbers from the append-only log
163
+ 4. Update the §'index' row in `memory/plans/README.md`
163
164
 
164
165
  ---
165
166
 
@@ -42,7 +42,7 @@ ymir_tools:
42
42
  - yggdrasil
43
43
  workspace_patterns:
44
44
  - development/
45
- - docs/plans/
45
+ - $YMIR_HOME/memory/plans/
46
46
  - .agents/skills/
47
47
  security:
48
48
  runs_in_utgard: true
@@ -78,7 +78,7 @@ witness them.
78
78
 
79
79
  ## Workspace patterns
80
80
 
81
- `development/` · `docs/plans/` · `.agents/skills/`
81
+ `development/` · `$YMIR_HOME/memory/plans/` · `.agents/skills/`
82
82
 
83
83
  ## Security posture
84
84
 
@@ -42,7 +42,7 @@ ymir_tools:
42
42
  - yggdrasil
43
43
  workspace_patterns:
44
44
  - development/
45
- - docs/plans/
45
+ - $YMIR_HOME/memory/plans/
46
46
  - .agents/assets/templates/
47
47
  security:
48
48
  runs_in_utgard: true
@@ -77,7 +77,7 @@ sequencing, and risks. Mímir changes no code; the builder executes the plan.
77
77
 
78
78
  ## Workspace patterns
79
79
 
80
- `development/` · `docs/plans/` · `.agents/assets/templates/`
80
+ `development/` · `$YMIR_HOME/memory/plans/` · `.agents/assets/templates/`
81
81
 
82
82
  ## Security posture
83
83
 
@@ -88,6 +88,28 @@ commands[4]{command,purpose}:
88
88
  "bin/hall-snapshot.sh","the planning feed: real system state -> public-safe livehall.json for the Óðrerir Hall"
89
89
  ```
90
90
 
91
+ ## The marketing stack doors (provisionable — one stack, any computer)
92
+
93
+ `bin/ymir-marketing-stack.sh up|status|down|doors` stands Mautic + Postiz +
94
+ Activepieces (+ optionally Forgejo) on ANY computer — same OSS engines the
95
+ server runs, env-driven, ports virtualized, secrets in the home, never inline.
96
+ The Allfather's server stack (zerwizserver) and the public doors agents reach:
97
+
98
+ ```
99
+ marketing_doors[6]{service,door,reach_note}:
100
+ "Mautic (email automation)","mautic.zerwiz.org -> server 127.0.0.1:8001","list building + campaigns; agent-carved via the local provisioned stack when the public door is closed"
101
+ "Postiz (social publishing)","postiz.zerwiz.org -> server 127.0.0.1:4007","schedule X/LinkedIn/insta; queue per site"
102
+ "Activepieces (workflow)","activepieces.zerwiz.org -> server 127.0.0.1:8080","event->post flows; meetup booked -> thread scheduled"
103
+ "Forgejo (git · issues · PRs)","forgejo.zerwiz.org -> server 127.0.0.1:3030","the local git forge: issues->PR loop lives here"
104
+ "SearXNG (search)","searxng on the server","private search for research (Bragi)"
105
+ "Grafana","grafana on the server :3003","fleet + stack observability"
106
+ ```
107
+
108
+ An agent (Bragi for marketing, Sindri for git) provisions the stack locally for
109
+ any user with `bin/ymir-marketing-stack.sh`; the server stack is the Allfather's
110
+ live one. Public-door exposure on the server is tunnel-driven (cloudflared) —
111
+ mend the door layer on the server, not in the tree.
112
+
91
113
  ## Maintaining this
92
114
 
93
115
  - **Owner:** Brokk. **Loaded by:** `AGENTS.md`. **Mirror:** `.agents/skills/galdr-ymirsystem/assets/registry.md`.
@@ -0,0 +1,53 @@
1
+ # config/agents.yaml.example — TEMPLATE for the Allfather's personal setup.
2
+ #
3
+ # Installation copies this to config/agents.yaml when none exists
4
+ # (bin/ymir-install.sh step: host) — or run: bin/agents-config.sh init
5
+ # Edit config/agents.yaml, then: bin/agents-config.sh apply
6
+ # config/agents.yaml is gitignored: it is YOURS, private, and pushable to a
7
+ # private repo. Override its path with YMIR_AGENTS_YAML=/path/to/yours.yaml.
8
+ # Any agent without its own `model:` inherits `default_model`.
9
+
10
+ version: 1
11
+
12
+ # The harness is chosen by where the model lives — local through pi, online
13
+ # through opencode. An agent may still name `harness:` to override the rule.
14
+ harness:
15
+ local: pi # a model on a local provider runs through pi
16
+ online: opencode # a hosted model runs through opencode
17
+ local_providers: [llama.cpp, llama-cpp, lmstudio]
18
+ # The same local server is named differently per harness; translate on the way.
19
+ providers:
20
+ llama.cpp: { pi: llama-cpp }
21
+
22
+ # The fallback smith for any agent that does not name a model.
23
+ default_model: opencode-go/deepseek-v4.1-flash
24
+
25
+ # Local, keyless model servers. `apply` writes these into the project harness
26
+ # config (opencode.json) so a model listed here is immediately usable. A bare
27
+ # alias (no @quant) is auto-resolved against the server's /v1/models.
28
+ providers:
29
+ llama.cpp:
30
+ npm: "@ai-sdk/openai-compatible"
31
+ name: "llama-server (local)"
32
+ base_url: "http://127.0.0.1:8080/v1"
33
+ models:
34
+ # A local llama.cpp router needs the EXACT served id (the @quant suffix);
35
+ # `apply` resolves the bare alias below to the id the server reports.
36
+ - frontend-design-expert-8b
37
+
38
+ # agent name -> { model, harness?, primary? }. Omit model to inherit
39
+ # default_model. Omit harness to follow the local/online rule above.
40
+ # `primary: true` marks the agent runnable directly (mode: all), not only
41
+ # dispatchable by another agent.
42
+ agents:
43
+ brokk: { model: opencode-go/deepseek-v4.1-flash }
44
+ # Hnoss the Shaper runs local (no cloud key) -> pi, and is directly runnable.
45
+ hnoss: { model: "llama.cpp/frontend-design-expert-8b", primary: true }
46
+ sindri: { model: opencode-go/deepseek-v4.1-flash }
47
+ bragi: { model: opencode-go/deepseek-v4.1-flash }
48
+ huginn: { model: opencode-go/deepseek-v4.1-flash }
49
+ kvasir: { model: opencode-go/deepseek-v4.1-flash }
50
+ mimir: { model: opencode-go/deepseek-v4.1-flash }
51
+ snotra: { model: opencode-go/deepseek-v4.1-flash }
52
+ forseti: { model: opencode-go/deepseek-v4.1-flash }
53
+ galdr: { model: opencode-go/deepseek-v4.1-flash }
@@ -1,6 +1,8 @@
1
- # Nornir cron schedule — real jobs
2
- # Format: HH:MM <command>. Started idempotently by bin/nornir-cron-start.sh at
3
- # every session start. Private (gitignored).
1
+ # Nornir cron schedule — TEMPLATE, never the live job list.
2
+ # Copy to YOUR home and edit there: cp config/cron.yaml.example $YMIR_HOME/config/cron.yaml
3
+ # The runtime reads the operator's own schedule from $YMIR_HOME/config/cron.yaml
4
+ # (or BROKK_CONFIG_OVERRIDE) — the tracked tree ships only this shape.
5
+ # Format: HH:MM <command>. Started idempotently by bin/nornir-cron-start.sh.
4
6
 
5
7
  07:00 bin/nornir-job-daily-briefing.sh
6
8
  06:00 bin/nornir-job-observer.sh
@@ -0,0 +1,9 @@
1
+ # The Allfather's machine mesh — hodd + company, peer-to-peer over Tailscale.
2
+ machine: omarchy
3
+ peers:
4
+ - host: zerwiz
5
+ paths:
6
+ - ~/ymir/hodd/
7
+ - ~/ymir/svartalfaheim/
8
+ - ~/ymir/data/
9
+ include_auth: false
@@ -0,0 +1,3 @@
1
+ # The channel the away-mode wedge alarm fires on when an escalation
2
+ # cannot be delivered into the pane. See bin/wedge-notify.sh.
3
+ desktop
@@ -56,10 +56,10 @@ copy "$ROOT/state" "$YMIR_HOME/state"
56
56
  # 7. Migrate data/ → YMIR_HOME/data/
57
57
  copy "$ROOT/data" "$YMIR_HOME/data"
58
58
 
59
- # 8. Migrate .agents/memory/kaia.engram* → YMIR_HOME/memory/
60
- copy "$ROOT/.agents/memory/kaia.engram" "$YMIR_HOME/memory/kaia.engram"
61
- copy "$ROOT/.agents/memory/kaia.engram-wal" "$YMIR_HOME/memory/kaia.engram-wal"
62
- copy "$ROOT/.agents/memory/kaia.engram-shm" "$YMIR_HOME/memory/kaia.engram-shm"
59
+ # 8. Migrate .agents/memory/kaia.engram* → the HOARD's memory (the one store)
60
+ copy "$ROOT/.agents/memory/kaia.engram" "$YMIR_HOME/hodd/memory/kaia.engram"
61
+ copy "$ROOT/.agents/memory/kaia.engram-wal" "$YMIR_HOME/hodd/memory/kaia.engram-wal"
62
+ copy "$ROOT/.agents/memory/kaia.engram-shm" "$YMIR_HOME/hodd/memory/kaia.engram-shm"
63
63
 
64
64
  # 9. Migrate smidja/smidja_data/smidja.db* → YMIR_HOME/smidja/
65
65
  copy "$ROOT/smidja/smidja_data/smidja.db" "$YMIR_HOME/smidja/smidja.db"
@@ -458,7 +458,12 @@ The adapter pattern is ported from the validated upstream **Brokk** agent-distro
458
458
  ## 13. The Well — memory for every harness (engram)
459
459
 
460
460
  The well is **Mimirsbrunn**, backed by the validated OSS engine **engram**. It is
461
- one repo-local store, `.agents/memory/kaia.engram`, reached two ways:
461
+ ONE store and it lives in the hoard — `$YMIR_HOME/hodd/memory/kaia.engram`
462
+ reached two ways. Every reader resolves it through `hoard_memory_store`
463
+ (bin/hoard-lib.sh) or an explicit `ENGRAM_DB`; the rendered `.pi/mcp.json`
464
+ carries the hoard path (`__YMIR_HOME__/hodd/memory/kaia.engram`). The well
465
+ rides the private vault between the Allfather's computers as one store — the
466
+ legacy `memory/kaia.engram` duplicates are struck.
462
467
 
463
468
  **HTTP bridge (`:4602`)** — `bin/mimir-bridge.py`, raised by
464
469
  `bin/mimir-bridge.sh` (and by `scripts/start.sh` + `bin/saga-session-start.sh`).
@@ -396,7 +396,7 @@ install[23]{step,what,self-heals}:
396
396
  "backend","Þjazi — herdr (protocol 14+) or tmux","bin/herdr-ensure.sh detects/tests version, installs via the pinned installer or falls back to tmux"
397
397
  "host","this machine — sensed on EVERY host","bin/host-sense.sh senses the setup on ANY host (Rule 05); the Omarchy layer then RECORDS it (bin/omarchy-sense.sh observe), places the apps (bin/desktop-place.sh), installs the post-update hook and the wedge-alarm channel, and (on Omarchy) offers the suggested shell plugins — listed, never installed unbidden; seeds the private config/agents.yaml from its example"
398
398
  "sandbox","utgard-runner:latest image","builds via bin/utgard.sh build on Docker or rootless Podman; distinguishes an unreachable engine from a build failure"
399
- "memory","engram store + harness MCP registrations","raises the bridge; reports MCP coverage"
399
+ "memory","engram store + harness MCP registrations","raises the bridge; reports MCP coverage — the store is ONE well in the hoard ($YMIR_HOME/hodd/memory/kaia.engram), resolved via hoard-lib or ENGRAM_DB"
400
400
  "smidja","smidja/smidja_data/smidja.db","bin/smidja-bootstrap.sh creates it from the tracer schema + a bootstrap session"
401
401
  "visualizer","the Smíðja visualizer UI (Vue, served on :8437)","builds ./dist with bun when absent — the API serves the UI from dist, and without it the API answers but shows no interface"
402
402
  "loaders","agents/skills into the harnesses","runs bin/valknut-load.sh"
@@ -456,7 +456,7 @@ The Smíðja visualizer **API** runs on `:8437` and serves its **UI** from
456
456
  now build it when absent:
457
457
 
458
458
  ```bash
459
- (cd .agents/skills/smidja-factory/apps/visualizer && bun run build) # vue-tsc + vite
459
+ (cd apps/smidja-factory/apps/visualizer && bun run build) # vue-tsc + vite
460
460
  ```
461
461
 
462
462
  `bin/ymir-validate.sh` reports `visualizer` FAIL when `./dist` is missing **and**
@@ -702,7 +702,7 @@ cd apps/hlidskjalf && npm install --no-audit --no-fund
702
702
  npm run typecheck && npm run build # dist/ is what the SPA serves
703
703
 
704
704
  # Smiðja visualizer (bun + bun.lock)
705
- cd .agents/skills/smidja-factory/apps/visualizer && bun install && bun run build
705
+ cd apps/smidja-factory/apps/visualizer && bun install && bun run build
706
706
  ```
707
707
 
708
708
  The visualizer's `dist/` is not optional: its API serves the UI from `./dist`,
@@ -954,6 +954,7 @@ it reports `all 25 governed paths exist`.
954
954
 
955
955
  `bin/ymir-install.sh` and `bin/ymir-validate.sh` are the two files of this asset
956
956
  that the sweep corrected. The visualizer path is
957
- `.agents/skills/smidja-factory/apps/visualizer` — **not** a doubled
957
+ `apps/smidja-factory/apps/visualizer` (the smidja repo clone) — **not** the
958
+ skill tree (dropped 2026-09-17, the skill carries no copy), not a doubled
958
959
  `smidja-factory-factory`, and not the abandoned `.agents/skills/smidja/` tree
959
960
  (stale build output, moved aside).
@@ -21,7 +21,7 @@ way in, observe on the way out.
21
21
 
22
22
  | Component | Path | Role |
23
23
  |---|---|---|
24
- | Store | `.agents/memory/kaia.engram` | the single SQLite memory (episodes, facts, entities) |
24
+ | Store | `$YMIR_HOME/hodd/memory/kaia.engram` | THE single SQLite memory (episodes, facts, entities) — one well, always in the hoard (Rule 04/07); resolved via `hoard_memory_store` (hoard-lib) or the `ENGRAM_DB` override |
25
25
  | Append log | `.agents/memory/well/episodes.jsonl` | the raw episode log (source of truth for re-seeding) |
26
26
  | HTTP bridge | `bin/mimir-bridge.py` (+ `bin/mimir-bridge.sh`) | the `:4602` face over the engram library |
27
27
  | CLI | `bin/mimir.sh` | operator CLI: `health` `recall` `observe` `timeline` |
@@ -70,7 +70,7 @@ which agent wrote it.
70
70
 
71
71
  ## 3. MCP for harnesses (the shared well)
72
72
 
73
- `engram-mcp --db $YMIR_ROOT/.agents/memory/kaia.engram` — **unscoped**, so
73
+ `engram-mcp --db $YMIR_HOME/hodd/memory/kaia.engram` — **unscoped**, so
74
74
  every harness reads the one well. (A scoped `--agent-id` filters reads to that
75
75
  agent and would hide the seeded `well` episodes; pass `agent_id` per `remember`
76
76
  call instead when attribution is wanted.)
@@ -99,7 +99,7 @@ well_laws[5]{id,law}:
99
99
  1,"No mock data — the well holds only true observations; test writes are purged"
100
100
  2,"Drink before you act — recall on the way in; never answer the Allfather dry"
101
101
  3,"Water it after — observe a lesson once it lands"
102
- 4,"Repo-local — the store is .agents/memory/kaia.engram; never an external repo"
102
+ 4,"Hoarded — the store is $YMIR_HOME/hodd/memory/kaia.engram (one well, never a duplicated migrated copy)"
103
103
  5,"One well — every harness shares it; scope per-call, never per-server"
104
104
  ```
105
105
 
@@ -125,8 +125,8 @@ python3 - <<'PY'
125
125
  import json
126
126
  from datetime import datetime
127
127
  from engram import Engram
128
- eng = Engram(path=".agents/memory/kaia.engram", agent_id="well")
129
- for l in open(".agents/memory/well/episodes.jsonl"):
128
+ eng = Engram(path="~/Documents/Ymir/hodd/memory/kaia.engram", agent_id="well")
129
+ for l in open("~/Documents/Ymir/hodd/memory/well/episodes.jsonl"):
130
130
  if not l.strip().startswith("{"): continue
131
131
  e = json.loads(l); ts = e.get("timestamp")
132
132
  when = datetime.fromisoformat(ts.replace("Z","+00:00")) if ts else None
@@ -63,16 +63,37 @@ same day. That is deliberate: cron is idempotent-by-date, not retrying-by-failur
63
63
  | `BROKK_ROOT_OVERRIDE` | script's parent | Root when `BROKK_HOME` unset. |
64
64
  | `BROKK_HOME` | `$ROOT` | Home owning the jobs and state. |
65
65
  | `BROKK_STATE_OVERRIDE` | `$YMIR_STATE_DIR` (`<home>/state`, via `bin/hoard-lib.sh`) | Scheduler state directory — in the home the operator chose, never in the code tree. |
66
- | `BROKK_CONFIG_OVERRIDE` | `$BROKK_HOME/config` | Where `cron.yaml` lives. |
66
+ | `BROKK_CONFIG_OVERRIDE` | (see §2) | Where `cron.yaml` lives — an explicit override always wins. |
67
67
  | `BROKK_CRON_LOG_MAX_BYTES` | `1048576` | Rotation threshold. |
68
68
  | `BROKK_REALM` | `""` | Realm exported to jobs (jobs also fall back to `data/realm.md`). |
69
69
 
70
70
  ---
71
71
 
72
- ## 2. `config/cron.yaml` format
72
+ ## 2. The schedule is the user's — `$YMIR_HOME/config/cron.yaml`
73
+
74
+ **The tracked tree ships a template, never the live job list.** The scheduler
75
+ resolves the schedule in this order:
76
+
77
+ 1. `BROKK_CONFIG_OVERRIDE` (explicit, unmistakeable);
78
+ 2. the **home's own** `$YMIR_HOME/config/cron.yaml` — where an operator edits
79
+ their real jobs (`$YMIR_HOME` resolves through `bin/hoard-lib.sh`, the one
80
+ answer the whole runtime shares);
81
+ 3. the repo's `config/cron.yaml.example` — a template a fresh install copies,
82
+ **never** a live schedule. A tracked `config/cron.yaml` is not consulted.
83
+
84
+ To take charge of your schedule:
85
+
86
+ ```bash
87
+ cp ~/ymir/config/cron.yaml.example ~/Documents/Ymir/config/cron.yaml
88
+ # edit ~/Documents/Ymir/config/cron.yaml, then:
89
+ bin/nornir-cron-start.sh --status # jobs=<n> from YOUR schedule
90
+ bin/nornir-cron-start.sh # resolve + start (idempotent)
91
+ ```
92
+
93
+ ### The format
73
94
 
74
95
  ```
75
- # Nornir cron schedule — real jobs
96
+ # Nornir cron schedule — the user's own jobs
76
97
  # Format: HH:MM <command>. Started idempotently by bin/nornir-cron-start.sh.
77
98
  07:00 bin/nornir-job-daily-briefing.sh
78
99
  06:00 bin/nornir-job-observer.sh
@@ -83,7 +104,8 @@ same day. That is deliberate: cron is idempotent-by-date, not retrying-by-failur
83
104
  - One job per line: `HH:MM <command>` (24-hour, zero-padded).
84
105
  - Blank lines and lines starting with `#` are ignored.
85
106
  - Commands are run with `bash -lc` from `$BROKK_HOME`, so relative `bin/...` paths resolve.
86
- - `cron.yaml` is private/gitignored (`config/*` in `.gitignore`).
107
+ - The example template lives at `config/cron.yaml.example` in the tracked tree;
108
+ an operator's real schedule is private in their home (`$YMIR_HOME/config/`).
87
109
 
88
110
  ---
89
111
 
@@ -188,6 +210,39 @@ round, `nornir / nsr.compliance.failed` (exit 1) naming the failed gates.
188
210
 
189
211
  - The morning briefing reads the ledger, so a FAIL is seen at 07:00, not
190
212
  found by accident.
213
+
214
+ ### 3.7 Forgejo — the local git round (`bin/nornir-job-forgejo-git.sh`, 02:45)
215
+
216
+ The issue-to-PR loop, read each night: lists the local forge's open issues and
217
+ carves one Rune with the tally, so a growing queue (or a dead tunnel) is seen
218
+ at sunrise. The forge address is the user's, from the home — never the tree:
219
+ `$YMIR_HOME/config/forge.env` (`FORGEJO_URL`, optional `FORGEJO_TOKEN`).
220
+
221
+ | Reads | Writes |
222
+ |---|---|
223
+ | `$YMIR_HOME/config/forge.env` · `GET {forge}/api/v1/repos/issues/search?state=open` | digest `$_HOME/memory/daily/forgejo-YYYY-MM-DD.md` · Rune `forgejo / git.issues` |
224
+
225
+ - No `FORGEJO_URL` configured → clean exit (the loop is not armed); a closed
226
+ door (tunnel down) → exit 1 and Rune `forgejo / git.door-down`.
227
+ - The forge may be the server's (`forgejo.zerwiz.org` → :3030) or a locally
228
+ provisioned one (`bin/ymir-marketing-stack.sh --with-forgejo`).
229
+
230
+ ### 3.8 The marketing stack (`bin/ymir-marketing-stack.sh`)
231
+
232
+ Not a cron job — a **provisioner**: stands Mautic + Postiz + Activepieces
233
+ (+ optional Forgejo) on ANY computer, the same OSS engines the server runs.
234
+ Env-driven (ports virtualized), secrets generated once into the home, never
235
+ inline. Agents (Bragi for marketing, Sindri for git) run it for any user.
236
+
237
+ ```
238
+ bin/ymir-marketing-stack.sh up|status|down|doors
239
+ # doors: Mautic :8001 · Postiz :8003 · Activepieces :8005 · Forgejo :8007 (defaults)
240
+ ```
241
+
242
+ - Rune `marketing / stack.<action>` carved on each provision action.
243
+ - The Allfather's live stack is the server's (`zerwizserver`); its public
244
+ doors are tunnel-driven (`cloudflared`) — see the registry's
245
+ `marketing_doors[]` table.
191
246
  - Idempotent: gates are pure checks; the cron date-guard suppresses repeat
192
247
  dispatch within a day; safe to invoke by hand (`bash bin/nornir-job-nsr-compliance.sh`).
193
248