@zerwiz/ymir 0.1.5 → 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.
- package/.agents/agents/huginn-researcher.md +1 -1
- package/.agents/agents/kvasir-scout.md +1 -1
- package/.agents/agents/sindri-developer.md +1 -1
- package/.agents/backend/README.md +74 -0
- package/.agents/backend/model-bridge.py +74 -4
- package/.agents/config/cron.yaml +2 -0
- package/.agents/config/eindri-dispatch.json +6 -6
- package/.agents/migrations/0003-private-data-separation.sh +11 -1
- package/.agents/migrations/0005-roots-out-of-tree.sh +158 -0
- package/.agents/skills/README.md +1 -1
- package/.agents/skills/galdr-ymirsystem/SKILL.md +2 -1
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +73 -10
- package/.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md +44 -1
- package/.agents/skills/galdr-ymirsystem/assets/installation.md +215 -23
- package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +3 -1
- package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +39 -1
- package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +4 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml +7 -2
- package/.agents/skills/galdr-ymirsystem/assets/registry.md +1 -1
- package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +2 -2
- package/.agents/skills/galdr-ymirsystem/assets/smidja.md +16 -11
- package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +147 -4
- package/.agents/skills/groa-update/SKILL.md +20 -0
- package/.agents/skills/hamr-adapters/SKILL.md +2 -2
- package/.agents/skills/lifecycle/smoke_test.sh +7 -2
- package/.agents/skills/ymir-host/SKILL.md +2 -1
- package/.agents/skills/ymir-host/assets/install.md +69 -0
- package/AGENTS.md +78 -34
- package/CHANGELOG.md +1033 -1
- package/README.md +1 -1
- package/RULES/02-agents.md +2 -2
- package/RULES/04-hoard.md +32 -0
- package/RULES/06-append-only.md +50 -0
- package/RULES/07-config.md +56 -0
- package/RULES/09-electron.md +58 -0
- package/RULES/README.md +2 -0
- package/bin/a2a-mcp.sh +42 -7
- package/bin/agents-config.sh +30 -7
- package/bin/apodex-smoke-test.sh +14 -1
- package/bin/bifrost-bridge.sh +25 -6
- package/bin/bootstrap-macos.sh +6 -1
- package/bin/brokk-send.sh +14 -1
- package/bin/changelog-assemble.sh +154 -0
- package/bin/changelog-guard.sh +39 -7
- package/bin/crash-sense.sh +14 -1
- package/bin/design-check.sh +80 -0
- package/bin/design-icon.sh +153 -0
- package/bin/docs-guard.sh +2 -2
- package/bin/editor-place.sh +33 -15
- package/bin/eindri-acclaim.sh +14 -1
- package/bin/eindri-seat.sh +83 -0
- package/bin/eindri-seen.sh +14 -1
- package/bin/eindri-start.sh +14 -1
- package/bin/eir-doctor.sh +47 -1
- package/bin/feature-inventory.sh +73 -0
- package/bin/fleet-apply.sh +15 -2
- package/bin/github-deploy.sh +14 -1
- package/bin/gjallarhorn-expose.sh +43 -9
- package/bin/gjallarhorn-notify.sh +14 -1
- package/bin/gjallarhorn-purge.sh +14 -1
- package/bin/gjallarhorn-tunnel.sh +16 -3
- package/bin/groa-update.sh +9 -1
- package/bin/hall-snapshot.sh +21 -2
- package/bin/herdr-run.sh +23 -2
- package/bin/hlidskjalf-agents.sh +172 -0
- package/bin/hlidskjalf-usage.sh +196 -0
- package/bin/hoard-guard.sh +135 -0
- package/bin/hoard-lib.sh +91 -11
- package/bin/hodd.sh +28 -4
- package/bin/huginn-research-worker.sh +14 -1
- package/bin/local-model-lock.sh +22 -3
- package/bin/mimir-bridge.py +33 -0
- package/bin/mimir-bridge.sh +14 -1
- package/bin/mimir-reflect.sh +27 -0
- package/bin/mjollnir-webhook.sh +14 -1
- package/bin/mjollnir.sh +22 -3
- package/bin/model-hardware.sh +17 -3
- package/bin/model-resolve.sh +14 -1
- package/bin/nornir-job-hall-snapshot.sh +28 -0
- package/bin/nornir-job-nsr-compliance.sh +54 -0
- package/bin/npm-publish.sh +136 -0
- package/bin/omarchy-install.sh +18 -5
- package/bin/omarchy-plugins.sh +15 -2
- package/bin/omarchy-sense.sh +14 -1
- package/bin/pi-model-agnostic.sh +71 -0
- package/bin/private-guard.sh +20 -0
- package/bin/project-git.sh +18 -4
- package/bin/public-guard.sh +3 -2
- package/bin/sessrumnir-ensure.sh +1 -1
- package/bin/sessrumnir.sh +16 -3
- package/bin/smidja-bootstrap.sh +5 -1
- package/bin/syn-asset-pretool-check.sh +14 -1
- package/bin/syn-spawn-pretool-check.sh +58 -0
- package/bin/tailscale-sync.sh +15 -2
- package/bin/telegram-bot.sh +14 -1
- package/bin/ui-truth-check.sh +75 -0
- package/bin/valknut-load.sh +42 -4
- package/bin/wedge-notify.sh +14 -1
- package/bin/workspace-rag.sh +14 -1
- package/bin/ymir-install.sh +219 -54
- package/bin/ymir-plan.sh +356 -0
- package/bin/ymir-say.sh +14 -1
- package/bin/ymir-setup-auth.sh +12 -1
- package/bin/ymir-validate.sh +28 -8
- package/docs/lore.md +5 -1
- package/docs/runbooks/agents.md +1 -1
- package/package.json +13 -3
- package/scripts/electron.sh +74 -15
- package/scripts/lower.sh +34 -0
- package/scripts/raise.sh +42 -0
- package/scripts/start.sh +52 -2
- package/.agents/config/agents.yaml +0 -50
- package/.agents/config/tailscale-sync.yaml +0 -27
- package/.agents/memory/kaia.engram +0 -0
- package/.agents/memory/kaia.engram-shm +0 -0
- package/.agents/memory/kaia.engram-wal +0 -0
- package/.agents/memory/well/episodes.jsonl +0 -367
- package/.agents/memory/well/workspace.jsonl +0 -27
|
@@ -28,6 +28,9 @@ Quick rules:
|
|
|
28
28
|
## Location & stack
|
|
29
29
|
|
|
30
30
|
- App: `apps/hlidskjalf` — **React 19 + Vite + TypeScript**, state via **Zustand**.
|
|
31
|
+
- The app lives in **its own repo** (`zerwiz/hlidskjalf`, registered in the home
|
|
32
|
+
registry) — the monorepo never tracks it; `bin/ymir-install.sh`'s `apps` step
|
|
33
|
+
clones it into `apps/hlidskjalf` at install, or fast-forwards a present clone.
|
|
31
34
|
- Gate API: `apps/hlidskjalf/server/index.ts` — **Bun + `bun:sqlite`**, read-only,
|
|
32
35
|
bound to the runtime and the smithy trace; Vite proxies `/api` → `:3889`.
|
|
33
36
|
- Raise everything with the scripts (do not hand-start each process):
|
|
@@ -95,6 +98,13 @@ Rules that hold it honest:
|
|
|
95
98
|
|
|
96
99
|
- `.shell` grid: `236px rail | 1fr`; rows `56px topbar · stage · stream`
|
|
97
100
|
(the stream height is draggable, persisted in `streamHeight`).
|
|
101
|
+
- The **Fleet graph** (`gates/Fleet.tsx`) lays the roster on a 100×100 canvas:
|
|
102
|
+
Brokk as the hub, everyone else in a square-ish grid fan (`cols =
|
|
103
|
+
ceil(sqrt(n))`, pitch ≥ one ring + label) so 20 agents never collide; rings
|
|
104
|
+
carry the house glyph from `DOMAINS[agent.domain]` with a `ymirlabs`
|
|
105
|
+
fallback, and the live cards come from `bin/hlidskjalf-agents.sh` — which
|
|
106
|
+
reads each figure's `domain:` frontmatter (never a hardcoded `ymirlabs` for
|
|
107
|
+
everyone).
|
|
98
108
|
- `.rail` (brand · gates · tenants · status), `.topbar` (realm chip · search ·
|
|
99
109
|
accent · density · trace index · account), `main.stage` (the gate), `.stream`
|
|
100
110
|
(Ratatoskr + Runes, pausable).
|
|
@@ -156,6 +166,18 @@ router `:8080`, Bifrost `:4603`), never only the first — a dead engine falls
|
|
|
156
166
|
through to a live one. Recall reads `.agents/memory/well/episodes.jsonl`
|
|
157
167
|
directly, so restoring that file revives the chat's memory without a restart.
|
|
158
168
|
|
|
169
|
+
### The EmberBackground hearth (the shared fire)
|
|
170
|
+
|
|
171
|
+
The animated glow behind the shell, the login, and Sessrúmnir's chat comes from
|
|
172
|
+
**one** hearth, not four copies: `midgard/design-system/ember.js` (`startEmbers`),
|
|
173
|
+
with Sessrúmnir's `ember-background.tsx` as its React port. Both draw the same
|
|
174
|
+
embers + haze, respect reduced-motion, and — since the Sep 17 mend — re-seed
|
|
175
|
+
via **ResizeObserver on the container**, not just `window.resize`: a split pane
|
|
176
|
+
or toggled sidebar changes the chat column's size without a window resize, and a
|
|
177
|
+
canvas that sized itself once at a stale dimension never shows the fire. The
|
|
178
|
+
shared module watches the host; the port watches its parent; re-seeding fires
|
|
179
|
+
only when the measured size actually changed (never per-frame).
|
|
180
|
+
|
|
159
181
|
### The gate API reads cheaply (added 2026-09-16)
|
|
160
182
|
|
|
161
183
|
The gate reads append-only ledgers (Runes, the well's `episodes.jsonl`, masterplan
|
|
@@ -201,7 +223,10 @@ API on the same port (`scripts/start.sh` raises it). Details: `assets/smidja.md`
|
|
|
201
223
|
## Agents, skills & mythological naming
|
|
202
224
|
|
|
203
225
|
- The Forge gate (`src/gates/Forge.tsx`) creates/edits **Eindri** and **skills**,
|
|
204
|
-
and reads/edits the smithy's prompts.
|
|
226
|
+
and reads/edits the smithy's prompts. The skill list shows each skill's own
|
|
227
|
+
text: the name + aett rune on the head row, and the description line
|
|
228
|
+
underneath (`forge-item-desc`, dimmed until hover) — the description comes
|
|
229
|
+
from the live `/api/skills` index, truncated to 240 chars by the gate API.
|
|
205
230
|
- Naming law: `src/data/mythology.ts` maps a craft/capability → the Norse figure
|
|
206
231
|
whose myth matches it (smith→Sindri, skald→Bragi, sage→Huginn, judge→Tyr,
|
|
207
232
|
forger→Brokk …). Skills take an **aett** prefix.
|
|
@@ -253,6 +278,17 @@ npm run build # must be green
|
|
|
253
278
|
- When the shell, tokens, gates, or the gate API change, update this asset and
|
|
254
279
|
`docs/design.md` together.
|
|
255
280
|
|
|
281
|
+
### The agent path the Fleet gate reads (2026-09-17)
|
|
282
|
+
|
|
283
|
+
`server/index.ts` decides whether a figure is *registered* by testing for its
|
|
284
|
+
profile in the OpenCode agent directory. That directory is **`.opencode/agents/`
|
|
285
|
+
— PLURAL**, which is what OpenCode actually loads. The singular
|
|
286
|
+
`.opencode/agent/` was never read by the harness, so twenty correct symlinks sat
|
|
287
|
+
in a directory no loader opened and the gate reported figures unregistered while
|
|
288
|
+
the tree held them all. Any code that resolves an agent profile must use the
|
|
289
|
+
plural path; the loader (`bin/valknut-load.sh`) migrates a legacy singular dir
|
|
290
|
+
forward and binds the plural one.
|
|
291
|
+
|
|
256
292
|
## Domains, not houses (Rule 01/03)
|
|
257
293
|
|
|
258
294
|
The eight Labs are **domains (Greinar)** — the knowledge axes — not houses. A
|
|
@@ -292,6 +328,13 @@ the password comes from `HLIDSKJALF_AUTH` in `.env.local`, never inline. A
|
|
|
292
328
|
hardcoded name here is both a leak into the public tree and wrong for any other
|
|
293
329
|
operator — `bin/public-guard.sh` exists to catch exactly that class of mistake.
|
|
294
330
|
|
|
331
|
+
**The gate must actually receive it.** `scripts/start.sh` loads `.env.local`
|
|
332
|
+
(mode `0600`, gitignored) into the environment before raising the gate, because
|
|
333
|
+
the bun process reads `process.env.HLIDSKJALF_AUTH` and nothing else was loading
|
|
334
|
+
it — so a credential set by `bin/ymir-setup-auth.sh` never took effect, and an
|
|
335
|
+
empty `GATE_AUTH` makes the gate treat every request as authenticated. After
|
|
336
|
+
setting a credential, restart the gate: `scripts/stop.sh; scripts/start.sh`.
|
|
337
|
+
|
|
295
338
|
### One login, and it is the one with the lore (2026-09-12)
|
|
296
339
|
|
|
297
340
|
There used to be **two** ways in, and the second was a mistake:
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
> page is the map.
|
|
6
6
|
|
|
7
7
|
One command sets up the whole system for the user; it self-heals what it can and
|
|
8
|
-
reports what it cannot. It **asks for consent first**
|
|
9
|
-
|
|
8
|
+
reports what it cannot. It **asks for consent first** — with a plan it computes on
|
|
9
|
+
this host, not a recited paragraph — and it **validates at the end** that what it
|
|
10
10
|
claims is actually running.
|
|
11
11
|
|
|
12
12
|
```
|
|
13
13
|
bin/ymir-install.sh # the first setup (idempotent; asks to proceed)
|
|
14
|
+
bin/ymir-install.sh --plan # the plan, probed — changes nothing (--json too)
|
|
14
15
|
bin/ymir-install.sh --check # report only, no writes, no prompt
|
|
15
16
|
bin/ymir-install.sh --yes # non-interactive (accept the plan)
|
|
16
17
|
bin/ymir-install.sh --skip-engines --skip-services
|
|
@@ -18,25 +19,198 @@ bin/ymir-install.sh --no-desktop # don't open the desktop apps at the end
|
|
|
18
19
|
bin/ymir-install.sh --status # alias of --check
|
|
19
20
|
```
|
|
20
21
|
|
|
22
|
+
## The plan comes first — `bin/ymir-plan.sh`
|
|
23
|
+
|
|
24
|
+
The consent a real install asks for is a **computed plan**, one row per step, each
|
|
25
|
+
carrying its state and the reason for it. A hardcoded paragraph cannot know the
|
|
26
|
+
host: the old one named an Omarchy version on a Mac, promised a workspace tree that
|
|
27
|
+
already stood, and never mentioned that no application had been installed at all.
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
bin/ymir-plan.sh # the plan (TOON)
|
|
31
|
+
bin/ymir-plan.sh --json # the same, for automation
|
|
32
|
+
bin/ymir-plan.sh --phase 5 # one phase
|
|
33
|
+
bin/ymir-plan.sh --blocked # only what cannot proceed, and why
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
plan_states[5]{state,means}:
|
|
38
|
+
"DO","a change will be made"
|
|
39
|
+
"SKIP","already satisfied — nothing to do"
|
|
40
|
+
"INFO","a fact about this host, discovered; no change implied"
|
|
41
|
+
"BLOCKED","cannot run — the reason names what is missing"
|
|
42
|
+
"CONSENT","needs the operator's word (a credential, an invite, the shells)"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
plan_phases[9]{n,name,gate}:
|
|
47
|
+
"0","resolve","this host, the container engine, the code root, and the home"
|
|
48
|
+
"1","code","the tree is intact — and holds nothing of the operator's"
|
|
49
|
+
"2","home","the operator's world, outside the tree"
|
|
50
|
+
"3","runtimes","git/python3 · bun/uv/mcp<2> · pi · hermes · the terminal backend"
|
|
51
|
+
"4","engines","treehouse · no-mistakes · sandcastle · the Utgard image"
|
|
52
|
+
"5","apps","hlidskjalf · odrerir · sessrumnir · smidja — web build required, shell gated"
|
|
53
|
+
"6","wire","the way in (auth · invite) and the launcher entries"
|
|
54
|
+
"7","raise","every port listening, then the desktop apps"
|
|
55
|
+
"8","verify","what stands, honestly"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`ymir-install.sh` prints the plan at the consent prompt; `--plan`/`--dry-run` prints
|
|
59
|
+
it and exits without writing. The plan is recomputed on every run, so it cannot
|
|
60
|
+
drift behind the code the way a paragraph did. `bin/ymir-plan.sh` is the ward for
|
|
61
|
+
the law below: its phase-1 `purity` row names any of the operator's things found in
|
|
62
|
+
the code tree.
|
|
63
|
+
|
|
64
|
+
## Where things live — the package is code, the home is the operator's
|
|
65
|
+
|
|
66
|
+
**Law (Rule 04):** the package carries the **core systems** — everything needed to
|
|
67
|
+
run the programs. Everything the **operator** owns goes to `$YMIR_HOME`: their
|
|
68
|
+
info, their records, their documents, their settings, their state, their
|
|
69
|
+
credentials. A packaged install (npm) treats its tree as read-only; the next
|
|
70
|
+
upgrade replaces it, so anything of theirs kept there is kept at its peril.
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
roots[5]{root,resolves_from,holds}:
|
|
74
|
+
"ymir_home_root","$YMIR_HOME → the choice recorded at installation → one documented default","everything private the operator owns"
|
|
75
|
+
"hoard_root","$YMIR_HOARD → <home>/hodd","docs · secrets · identity · tenants · memory"
|
|
76
|
+
"hoard_data_dir","$YMIR_DATA_DIR → <hoard>/data","this machine's records: operator, fleet, machines, the host profile"
|
|
77
|
+
"hoard_state_dir","$YMIR_STATE_DIR → <home>/state","runtime state: pids, logs, locks, caches"
|
|
78
|
+
"hoard_settings_dir","$YMIR_SETTINGS_DIR → <home>/config","settings: agents.yaml, cron.yaml, tailscale-sync, the wedge channel"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Plus `hoard_local_env` → `$YMIR_HOME/.env.local`: the operator's **credentials**
|
|
82
|
+
(`HLIDSKJALF_AUTH`, OAuth keys, tokens), never in the tree.
|
|
83
|
+
|
|
84
|
+
**The home is chosen, not assumed.** A real interactive install asks once
|
|
85
|
+
(`step_home`), records the answer as machine state under `~/.config/ymir/home`
|
|
86
|
+
(the same place `engram-python` and `accounts.json` live), and every later script
|
|
87
|
+
resolves it through `bin/hoard-lib.sh`. `--check` never writes; `--yes` takes what
|
|
88
|
+
is recorded, else the documented default.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
bin/hoard-lib.sh # the lib (source-safe; functions only)
|
|
92
|
+
ymir_home_root HOME # → the home
|
|
93
|
+
hoard_settings_dir SETTINGS # → <home>/config
|
|
94
|
+
hoard_local_env ENVFILE # → <home>/.env.local
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Rule for new code:** never write `$ROOT/data`, `$ROOT/state`, `$ROOT/config`,
|
|
98
|
+
`$ROOT/.env.local` or `$ROOT/workspace`. Resolve the root through the lib. A script
|
|
99
|
+
that points an operator's thing into the tree is the bug the `purity` row exists to
|
|
100
|
+
catch.
|
|
101
|
+
|
|
102
|
+
### Carrying an existing tree home — migration 0005
|
|
103
|
+
|
|
104
|
+
Every *writer* resolves the home now, but an installation made before this change
|
|
105
|
+
still holds the operator's things in the tree. `.agents/migrations/0005-roots-out-of-tree.sh`
|
|
106
|
+
carries them:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
what moves from to
|
|
110
|
+
------------------ --------------------- ----------------------------
|
|
111
|
+
this machine's data/ <hoard>/data
|
|
112
|
+
records
|
|
113
|
+
runtime state state/ <home>/state
|
|
114
|
+
(pids · logs · (including the (running services keep their open
|
|
115
|
+
locks · the applied-migrations fds across the move — `mv` keeps
|
|
116
|
+
applied-marker) marker) the inode)
|
|
117
|
+
credentials the local env file $YMIR_HOME/.env.local (0600)
|
|
118
|
+
settings .agents/config/* <home>/config
|
|
119
|
+
that git does NOT track
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
One name, two files — the migration decides by evidence, never by assumption:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
collision[3]{case,what_happens,nothing_lost}:
|
|
126
|
+
"identical content","the tree's copy is removed","the content is provably at home already"
|
|
127
|
+
"different content","the home's keeps the name; the tree's is carried beside it as <name>.stale-<UTC>","both are real, so both are kept — never merged, never discarded"
|
|
128
|
+
"not a plain file","left in place and reported","a directory is not silently swallowed"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Templates and defaults never move: `*.example` (and `*.example.*`), `.gitkeep`, and
|
|
132
|
+
any settings file **git tracks** — that is the distro's shipped default, not the
|
|
133
|
+
operator's. The plan's `purity` row applies the same rule, asking git about the
|
|
134
|
+
real path (the tree's `config` is a symlink into `.agents/config`, and git tracks
|
|
135
|
+
what the index holds, not the link). Idempotent: a second run changes nothing.
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
bin/ymir-migrate.sh status # pending / applied
|
|
139
|
+
bin/ymir-migrate.sh apply --dry-run # name the migration, touch nothing
|
|
140
|
+
bin/ymir-migrate.sh apply # carry it
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Stop the runtime first if you want no stale pid files; nothing is lost either way.
|
|
144
|
+
|
|
145
|
+
## The app packages — how the four surfaces arrive
|
|
146
|
+
|
|
147
|
+
The distro depends on the surfaces as their own npm packages, so one
|
|
148
|
+
`npm install -g @zerwiz/ymir` fetches them into the tree:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
app_packages[4]{package,repo,what}:
|
|
152
|
+
"@zerwiz/hlidskjalf","zerwiz/hlidskjalf","the control plane — dist/ ships built, served on :3888"
|
|
153
|
+
"@zerwiz/odrerir","zerwiz/odrerir","the live hall — dist/ ships built"
|
|
154
|
+
"@zerwiz/sessrumnir","zerwiz/sessrumnir","the seat-hall desktop — out/ ships built (a fork of pi-desktop)"
|
|
155
|
+
"@zerwiz/smidja-factory","zerwiz/smidja","the smithy and its visualizer — the factory plus the UI's source, built at install"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
They are **optionalDependencies**, deliberately: a broken app package must never
|
|
159
|
+
stop the CORE from installing, and a package not yet on the registry is skipped by
|
|
160
|
+
npm and starts arriving the moment it is published. The plan's phase-5 rows report
|
|
161
|
+
each surface separately — installed, declared-but-not-fetched, or no package at all
|
|
162
|
+
— so a silent skip cannot hide.
|
|
163
|
+
|
|
164
|
+
A global install nests them under the distro's own `node_modules`
|
|
165
|
+
(`<prefix>/lib/node_modules/@zerwiz/ymir/node_modules/@zerwiz/<app>`); a local one
|
|
166
|
+
hoists them to `node_modules/@zerwiz/<app>`. The plan checks both shapes.
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
bin/npm-publish.sh # the platform only
|
|
170
|
+
bin/npm-publish.sh --all # the platform + every app package
|
|
171
|
+
bin/npm-publish.sh --dry-run --all # what would go out, and from where
|
|
172
|
+
bin/npm-publish.sh --unpublish @zerwiz/ymir@0.1.5 # take ONE version back
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**A version can be taken back, and the window is short.** npm permits unpublishing
|
|
176
|
+
**one version for 72 hours** after it was published; past that it is npm support's
|
|
177
|
+
door. So `--unpublish` demands a spec that names the version — never a bare name —
|
|
178
|
+
and the row says where the CDN may still serve the tarball for a while afterwards.
|
|
179
|
+
Publishing a newer version is the other half of the repair: it moves the `latest`
|
|
180
|
+
tag off the bad build at once, even before the removal propagates.
|
|
181
|
+
|
|
182
|
+
**A `files[]` entry that names a directory overrides `.gitignore`.** This is how
|
|
183
|
+
`@zerwiz/ymir@0.1.5` shipped the memory well: `files: [".agents/"]` packed that
|
|
184
|
+
subtree *including* the gitignored stores, and the repo stayed clean while the
|
|
185
|
+
artefact did not. Name what ships, exclude what must not, and prove it with
|
|
186
|
+
`npm pack --dry-run` — the repo's cleanliness says nothing about the tarball.
|
|
187
|
+
|
|
188
|
+
The app repos are cloned into `apps/` by the install's `apps` step (from the
|
|
189
|
+
registry's `repo: apps/<path>` blocks), which is where `--all` reads their
|
|
190
|
+
manifests. The token comes from the hoard, never from `~/.npmrc`.
|
|
191
|
+
|
|
21
192
|
## The steps
|
|
22
193
|
|
|
23
194
|
```
|
|
24
|
-
install[
|
|
195
|
+
install[23]{step,what,self-heals}:
|
|
25
196
|
"panes","the run shown in a herdr pane","bin/herdr-run.sh sits a pane beside the caller when inside herdr; inline otherwise — a pane that cannot be raised never loses the work"
|
|
26
197
|
"prereqs","git python3 bun docker|podman gh · mcp<2","bin/prereq-ensure.sh installs bun+uv+mcp in user space; engram is an honest optional SKIP"
|
|
27
198
|
"memory-well","the engram engine (Mimirsbrunn)","optional; reported with the exact next command, never a fake fix"
|
|
28
|
-
"
|
|
199
|
+
"home","the home the operator CHOOSES, recorded under ~/.config/ymir/home","asks once, records the answer; --check never writes, --yes takes what is recorded, else the documented default"
|
|
200
|
+
"tree","workspace/{work,personal}/<domains>, companies/, workspaces.yaml, projects.yaml, and the hoard OUTSIDE the repo (secrets/ · docs/ · identity/ · tenants/ at the hoard root under the chosen home)","creates if missing; hoard_root resolves through bin/hoard-lib.sh so no script can point the hoard inside the checkout (Rule 04), and an empty secrets/platform.env (0600) is seeded so bin/hodd.sh emit resolves"
|
|
201
|
+
"apps","the app repos (the app split) — hlidskjalf · hlidskjalf-mobile · odrerir · sessrumnir · smidja","reads $HOARD/identity/projects.yaml (never guesses a remote); clones a missing apps/<path> from its registered git{} block, fast-forwards a present one, and stamps the smithy engine (apps/smidja) from the cloned factory's templates"
|
|
29
202
|
"engines","treehouse · sandcastle · no-mistakes","installs treehouse + no-mistakes from their installers"
|
|
30
203
|
"hermes","the Nous Research agent runtime","installs via bin/hermes-ensure.sh when absent"
|
|
31
|
-
"sessrumnir","the Sessrúmnir desktop GUI (
|
|
204
|
+
"sessrumnir","the Sessrúmnir desktop GUI (its own repo; lands via the `apps` step at apps/sessrumnir)","bin/sessrumnir-ensure.sh installs deps + builds on first run (deps are never committed); launch via bin/sessrumnir.sh"
|
|
32
205
|
"backend","Þjazi — herdr (protocol 14+) or tmux","bin/herdr-ensure.sh detects/tests version, installs via the pinned installer or falls back to tmux"
|
|
33
|
-
"host","this machine —
|
|
206
|
+
"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"
|
|
34
207
|
"sandbox","utgard-runner:latest image","builds via bin/utgard.sh build on Docker or rootless Podman; distinguishes an unreachable engine from a build failure"
|
|
35
208
|
"memory","engram store + harness MCP registrations","raises the bridge; reports MCP coverage"
|
|
36
209
|
"smidja","smidja/smidja_data/smidja.db","bin/smidja-bootstrap.sh creates it from the tracer schema + a bootstrap session"
|
|
37
210
|
"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"
|
|
38
211
|
"loaders","agents/skills into the harnesses","runs bin/valknut-load.sh"
|
|
39
212
|
"gates","the git delivery gates — secret-guard (pre-commit), branch-guard + changelog-guard (pre-push)","bin/secret-guard.sh --install and bin/changelog-guard.sh --install seat the versioned guards into .git/hooks, so the gate is live from the first commit of a fresh clone; idempotent"
|
|
213
|
+
"marks","each app's rune icon + .desktop entry into the operator's own desktop, and the Ymir contract into pi's agent home","bin/design-icon.sh mint --all + install writes to $HOME/.local/share (never a session sandbox), so every app is dockable and pinnable; the contract symlink means every pi session, in ANY folder, loads Brokk"
|
|
40
214
|
"invite","the way in for anyone else — an invite code","bin/ymir-invite.sh ensure mints one only when nothing is live, so the step is idempotent; the code is printed at the end of the run and again in workspace/INSTALL.md"
|
|
41
215
|
"register","workspace/INSTALL.md","writes the record"
|
|
42
216
|
"services","gate API, SPA, Nornir, bridges, visualizer","raises via scripts/start.sh (which builds the visualizer UI when ./dist is absent)"
|
|
@@ -44,7 +218,7 @@ install[20]{step,what,self-heals}:
|
|
|
44
218
|
"validate","the running system","bin/ymir-validate.sh — live port/store/process checks"
|
|
45
219
|
```
|
|
46
220
|
|
|
47
|
-
**
|
|
221
|
+
**25** `step_*` functions are defined (`home` asks, `tree` builds). A step is not a row: one step may emit
|
|
48
222
|
several. `prereqs` also emits `memory-well`, `host` also emits `agents-config`,
|
|
49
223
|
`smidja` also emits `visualizer`, and `spa` also emits `hlidskjalf`. `--check`
|
|
50
224
|
skips the runtime-only steps (`services`, `desktop`, `validate`), which have
|
|
@@ -94,8 +268,10 @@ now build it when absent:
|
|
|
94
268
|
(cd .agents/skills/smidja-factory/apps/visualizer && bun run build) # vue-tsc + vite
|
|
95
269
|
```
|
|
96
270
|
|
|
97
|
-
`bin/ymir-validate.sh` reports `visualizer` FAIL when `./dist` is missing
|
|
98
|
-
|
|
271
|
+
`bin/ymir-validate.sh` reports `visualizer` FAIL when `./dist` is missing **and**
|
|
272
|
+
when the build exists but nothing is listening on `:8437`. A PASS means the UI is
|
|
273
|
+
built *and* the API is up — so a built-but-dead visualizer (a bad `CMD_DB`, a
|
|
274
|
+
crashed API) can no longer read as green.
|
|
99
275
|
|
|
100
276
|
## Desktop placement (Omarchy desktops, not monitors)
|
|
101
277
|
|
|
@@ -163,13 +339,20 @@ non-interactive callers; without it a non-interactive `add` refuses with exit 3)
|
|
|
163
339
|
The installer only *offers*.
|
|
164
340
|
|
|
165
341
|
## Consent
|
|
166
|
-
A real install prints
|
|
167
|
-
(exit 3). `--check`
|
|
168
|
-
refused rather than silently
|
|
342
|
+
A real install prints **the plan it computed** (`bin/ymir-plan.sh`) and waits for
|
|
343
|
+
`[y/N]`. Declining changes nothing (exit 3). `--check` and `--plan` never prompt.
|
|
344
|
+
A non-interactive caller without `--yes` is refused rather than silently
|
|
345
|
+
proceeding.
|
|
346
|
+
|
|
347
|
+
The plan names every step with its state and the reason for it — including the
|
|
348
|
+
home the operator is asked to choose, the four app surfaces and whether each can
|
|
349
|
+
be installed at all, the terminal backend, and what will be skipped and why. The
|
|
350
|
+
state vocabulary is `DO · SKIP · INFO · BLOCKED · CONSENT`.
|
|
169
351
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
352
|
+
`--check` writes nothing — and that includes the migrations. `bin/ymir-migrate.sh
|
|
353
|
+
apply` **moves private data**, so the step chain runs it only on a real run;
|
|
354
|
+
a preview leaves the home exactly as it found it. (It used to apply them even
|
|
355
|
+
under `--check`, which moved a home during a "report only" pass.)
|
|
173
356
|
|
|
174
357
|
## The operator's way in (auth) — `bin/ymir-setup-auth.sh`
|
|
175
358
|
|
|
@@ -225,7 +408,7 @@ part is off. `--json` for machine consumption.
|
|
|
225
408
|
| **sandcastle** (`mattpocock/sandcastle`) | Utgard | Docker/Podman/Vercel sandboxes |
|
|
226
409
|
| **no-mistakes** (`kunchenguid/no-mistakes`) | Mjollnir · Glitnir | clean-PR validation gate |
|
|
227
410
|
| **Hermes** (`NousResearch/hermes-agent`, MIT) | — (product name) | worker agent runtime: own brain, memory, skills, subagents, sandbox backends |
|
|
228
|
-
| **pi-desktop** (`FaqFirebase/pi-desktop`, Apache-2.0) | **Sessrúmnir** (
|
|
411
|
+
| **pi-desktop** (`FaqFirebase/pi-desktop`, Apache-2.0) | **Sessrúmnir** (cloned from its own repo to `apps/sessrumnir` at install) | desktop GUI for the Pi/OMP coding agents — the seat-hall, themed with the Ymir way-of palette |
|
|
229
412
|
|
|
230
413
|
## Missing dependencies
|
|
231
414
|
|
|
@@ -298,14 +481,16 @@ company is the operator's to name; Ymir ships no default.
|
|
|
298
481
|
bin/ymir-install.sh --check # all steps OK/WARN
|
|
299
482
|
bin/ymir-validate.sh # the running system actually works
|
|
300
483
|
bin/herdr-ensure.sh status # the Þjazi backend and its protocol floor
|
|
301
|
-
bin/
|
|
484
|
+
bin/host-sense.sh # sense THIS machine (any host)
|
|
485
|
+
bin/omarchy-sense.sh status # the Omarchy recording (Omarchy hosts)
|
|
302
486
|
bin/saga-session-start.sh # the session digest
|
|
303
487
|
bash .agents/skills/galdr-ymirsystem/scripts/compliance-check.sh
|
|
304
488
|
```
|
|
305
489
|
|
|
306
|
-
On
|
|
307
|
-
(`bin/omarchy-sense.sh`)
|
|
308
|
-
|
|
490
|
+
On **every** host the installer senses the machine with `bin/host-sense.sh`. On
|
|
491
|
+
an **Omarchy** host the layer also *records* it (`bin/omarchy-sense.sh observe`)
|
|
492
|
+
and installs a `post-update` hook so Ymir re-learns it every time Omarchy
|
|
493
|
+
updates. On a non-Omarchy host that layer step is a clean SKIP.
|
|
309
494
|
|
|
310
495
|
Rule: the installer is **idempotent** — running it again changes nothing but
|
|
311
496
|
fills gaps. It never overwrites real user data.
|
|
@@ -470,7 +655,7 @@ machines may run the runtime.
|
|
|
470
655
|
| Layer | Runs on | What it owns |
|
|
471
656
|
|---|---|---|
|
|
472
657
|
| **Portable core** | Linux, macOS, Windows (WSL2; MSYS best-effort) | the runtime — session digest, lock, watch, cron, skills — the installer's user-space prerequisites, the capability shim, generated machine config |
|
|
473
|
-
| **Omarchy layer** | Omarchy only |
|
|
658
|
+
| **Omarchy layer** | Omarchy only | recording the host (`omarchy-sense observe`), placing each app on its own numbered Hyprland desktop (`desktop-place`), the launcher entries (`.desktop`), the suggested shell plugins, the post-update hook |
|
|
474
659
|
|
|
475
660
|
The core never grows a Hyprland branch, and the Omarchy layer is never stretched
|
|
476
661
|
into pretending it is portable. An Omarchy-specific step is gated on the host and
|
|
@@ -480,8 +665,15 @@ reports a clean skip anywhere else:
|
|
|
480
665
|
[ -d /usr/share/omarchy ] && ... || add host OK "... (not an Omarchy host)"
|
|
481
666
|
```
|
|
482
667
|
|
|
483
|
-
That is why
|
|
484
|
-
|
|
668
|
+
That is why the only Omarchy branches left in the core installer are the ones
|
|
669
|
+
that call the layer (`step_omarchy`) and desktop placement (`step_desktop`):
|
|
670
|
+
`step_host` senses the host portably with `host-sense`, and everywhere else the
|
|
671
|
+
same code path runs on any host.
|
|
672
|
+
|
|
673
|
+
The **consent preamble** the installer prints before it acts says the same thing —
|
|
674
|
+
*"learn this machine (OS, desktop, packages, configs, monitors, scale — Omarchy
|
|
675
|
+
hosts recorded first-class)"* — so the operator is told what will happen in the
|
|
676
|
+
portable terms the code now uses, not the Omarchy-only terms it used before.
|
|
485
677
|
|
|
486
678
|
### What the Omarchy layer installs
|
|
487
679
|
|
|
@@ -154,7 +154,9 @@ hardcoded timeline is gone.
|
|
|
154
154
|
- **First `observe` slow (~20–30 s)** → the embedding model is warming; later
|
|
155
155
|
writes are instant.
|
|
156
156
|
- **Bridge down / `COLD`** → `bin/mimir-bridge.sh --start`; check
|
|
157
|
-
|
|
157
|
+
`$YMIR_STATE_DIR/mimir-bridge.log` — runtime state lives in the home the
|
|
158
|
+
operator chose (`hoard_state_dir` via `bin/hoard-lib.sh`), never in the code
|
|
159
|
+
tree: a packaged install replaces its tree on upgrade.
|
|
158
160
|
|
|
159
161
|
**Portability.** The bridge signals processes through `ymir_kill_matching` from
|
|
160
162
|
`bin/ymir-platform.sh` rather than calling `pkill` directly, because `pkill` is
|
|
@@ -62,7 +62,7 @@ same day. That is deliberate: cron is idempotent-by-date, not retrying-by-failur
|
|
|
62
62
|
|---|---|---|
|
|
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
|
-
| `BROKK_STATE_OVERRIDE` | `$
|
|
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
66
|
| `BROKK_CONFIG_OVERRIDE` | `$BROKK_HOME/config` | Where `cron.yaml` lives. |
|
|
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`). |
|
|
@@ -153,6 +153,44 @@ removed and the failure is reported plainly.
|
|
|
153
153
|
| `BROKK_MEMORY_PRUNE` | `0` (disabled) |
|
|
154
154
|
| `BROKK_MEMORY_PRUNE_DAYS` | `7` |
|
|
155
155
|
|
|
156
|
+
### 3.5 Óðrerir — Live Hall snapshot (`bin/nornir-job-hall-snapshot.sh`, 08:00)
|
|
157
|
+
|
|
158
|
+
The Live Hall is a glass: it reads `apps/odrerir/public/livehall.json`
|
|
159
|
+
(same-origin, `cache: no-store`). This job writes that snapshot from real state
|
|
160
|
+
via `bin/hall-snapshot.sh` — runes, the project registry, the cron gauge, the
|
|
161
|
+
wake queue, standing smiths, armed `when-` sources, and the landed errands —
|
|
162
|
+
then carves Rune `odrerir / hall.snapshot`. Scheduled at 08:00 so it follows
|
|
163
|
+
the 06:00 observer and the 07:00 briefing: the morning board carries the day's
|
|
164
|
+
fresh runes.
|
|
165
|
+
|
|
166
|
+
| Reads | Writes |
|
|
167
|
+
|---|---|
|
|
168
|
+
| runes ledger · `hodd/identity/projects.yaml` · `config/cron.yaml` · `state/.wake-queue` · herdr agent list · armed when-sources · `state/eindri-reports/archive/` | `apps/odrerir/public/livehall.json` (gitignored runtime) · Rune `odrerir / hall.snapshot` |
|
|
169
|
+
|
|
170
|
+
- The snapshot is **runtime, never repo**: `apps/odrerir/public/livehall.json`
|
|
171
|
+
is gitignored, so the job never dirties a branch.
|
|
172
|
+
- Absent `livehall.json` on the Hall is *not* a build failure — the page paints
|
|
173
|
+
the saga's own count and says so. This job is what makes the board true.
|
|
174
|
+
- Idempotent by nature: each run rewrites the same snapshot from the same
|
|
175
|
+
inputs; the cron date-guard suppresses repeat dispatch within a day.
|
|
176
|
+
|
|
177
|
+
### 3.6 Tyr — NSR compliance round (`bin/nornir-job-nsr-compliance.sh`, 02:30)
|
|
178
|
+
|
|
179
|
+
The NorthStar deterministic gate, run nightly in the quiet hours so sunrise
|
|
180
|
+
finds the doors mended or the Rune already says which broke. Runs every
|
|
181
|
+
`.compliance/gates/check_*.sh` (danger · env · paths · platform · wiring)
|
|
182
|
+
and carves one Rune with the verdict — `nornir / nsr.compliance` on a clean
|
|
183
|
+
round, `nornir / nsr.compliance.failed` (exit 1) naming the failed gates.
|
|
184
|
+
|
|
185
|
+
| Reads | Writes |
|
|
186
|
+
|---|---|
|
|
187
|
+
| `.compliance/gates/check_*.sh` (deterministic, no network) | Rune `nornir / nsr.compliance[.failed]` · `state/last` line |
|
|
188
|
+
|
|
189
|
+
- The morning briefing reads the ledger, so a FAIL is seen at 07:00, not
|
|
190
|
+
found by accident.
|
|
191
|
+
- Idempotent: gates are pure checks; the cron date-guard suppresses repeat
|
|
192
|
+
dispatch within a day; safe to invoke by hand (`bash bin/nornir-job-nsr-compliance.sh`).
|
|
193
|
+
|
|
156
194
|
### 3.4 Yggdrasil — git sync (`bin/nornir-job-git-sync.sh`, 00:00)
|
|
157
195
|
|
|
158
196
|
The world-tree kept in order. Two modes, both non-destructive:
|
|
@@ -110,6 +110,10 @@ snapshot[1]{command,out}:
|
|
|
110
110
|
- **Ports are sacred:** `:4322` is Óðrerir's alone. Do not move it into a
|
|
111
111
|
Hlidskjalf route or a launcher call — its door is a plain anchor in a new tab
|
|
112
112
|
(`.hall-btn`, rune **ᛟ**, "To the Hall") and its own window.
|
|
113
|
+
- **`.astro/dev.json` is runtime state, never tracked.** Astro rewrites it on
|
|
114
|
+
every start with the live `pid` and the host's own addresses (LAN + tailnet),
|
|
115
|
+
so committing it leaks a private IP per run. It is gitignored; the generated
|
|
116
|
+
types beside it (`content.d.ts`, `types.d.ts`) stay tracked.
|
|
113
117
|
|
|
114
118
|
## 5. Files you will touch
|
|
115
119
|
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
# PI Profile —
|
|
1
|
+
# PI Profile — the SHAPE of the Brokk harness profile, not a machine's values.
|
|
2
|
+
#
|
|
3
|
+
# Rule 07A: a model id is the USER's, not the repo's. Every operator's differ, so
|
|
4
|
+
# this template carries a placeholder; the live values come from the user's own
|
|
5
|
+
# roster at $YMIR_HOME/hodd/config/agents.yaml, resolved through
|
|
6
|
+
# bin/agents-config.sh. Never commit a real model id here.
|
|
2
7
|
|
|
3
8
|
profile:
|
|
4
9
|
name: "pi"
|
|
@@ -6,7 +11,7 @@ profile:
|
|
|
6
11
|
version: "1.0.0"
|
|
7
12
|
|
|
8
13
|
agent:
|
|
9
|
-
model: "
|
|
14
|
+
model: "<your-model-id>" # resolved from $YMIR_HOME/hodd/config/agents.yaml
|
|
10
15
|
temperature: 0.7
|
|
11
16
|
max_tokens: 8192
|
|
12
17
|
system_prompt: "BROKK — SYSTEM OPERATING MANUAL (see .opencode/agents/brokk.md)"
|
|
@@ -292,7 +292,7 @@ The house law lives in `RULES/`; Galdr must know it (Rule 01/02/03):
|
|
|
292
292
|
|
|
293
293
|
- **Eindri are the specialists** (marketer, builder, researcher, planner,
|
|
294
294
|
reviewer, documenter, scout, …); each names its **domain** and its **craft**.
|
|
295
|
-
- **Agents live only in `.agents/agents/*.md`.** `.opencode/
|
|
295
|
+
- **Agents live only in `.agents/agents/*.md`.** `.opencode/agents` and
|
|
296
296
|
`.pi/agents` are **symlinks** to the canonical profiles — never edit them;
|
|
297
297
|
edit `.agents/agents/<profile>.md` and run `bin/valknut-load.sh --all`.
|
|
298
298
|
- **No mock agents.** Ids, names, domains, models, status are real and sourced;
|
|
@@ -32,7 +32,7 @@ siblings of this file (`eindri-orchestration.md`, `nornir-jobs.md`). The runtime
|
|
|
32
32
|
| 11 | Secrets never committed | secret scan + ignore audit | No secret literal; ignore rules cover env files. |
|
|
33
33
|
| 12 | Governed assets current | `compliance-check.sh` (`assets` check) | A governed path changed in the working tree has its owning asset changed too. |
|
|
34
34
|
| 13 | **Governed paths resolve** | `compliance-check.sh` (`governed` check) | Every path in `AGENTS.md`'s `governed[]` table exists (or its glob matches something). |
|
|
35
|
-
| 14 | **Harness surfaces resolve** | `compliance-check.sh` (`harnesses` check) | Every link in `.claude/agents`, `.codex/agents`, `.cursor/agents`, `.pi/agents`, `.opencode/
|
|
35
|
+
| 14 | **Harness surfaces resolve** | `compliance-check.sh` (`harnesses` check) | Every link in `.claude/agents`, `.codex/agents`, `.cursor/agents`, `.pi/agents`, `.opencode/agents` lands (one hop) in `.agents/agents/`, and no nested `SKILL.md` carries frontmatter — a phantom skill. |
|
|
36
36
|
| 15 | **Skill index true** | `compliance-check.sh` (`skillindex` check) | Every real skill dir is named in `.agents/skills/README.md`, and every `.agents/skills/<name>` path the assets cite exists. |
|
|
37
37
|
|
|
38
38
|
### Governed paths — load the asset before you edit
|
|
@@ -88,7 +88,7 @@ Two failures hide in the harness layer, and neither is visible from the code:
|
|
|
88
88
|
|
|
89
89
|
1. **A symlink that no longer resolves.** Rule 02 says `.agents/agents` is
|
|
90
90
|
canonical and every harness dir (`.claude/agents`, `.codex/agents`,
|
|
91
|
-
`.cursor/agents`, `.pi/agents`, `.opencode/
|
|
91
|
+
`.cursor/agents`, `.pi/agents`, `.opencode/agents`) is a link into it. The
|
|
92
92
|
`galdr-cli` → `galdr-ymirsystem` rename left `.agents/agents/galdr.md`
|
|
93
93
|
dangling, so Galdr's agent surface did not exist in *any* harness — and
|
|
94
94
|
nothing failed loudly; the harness simply had no such agent.
|
|
@@ -18,7 +18,10 @@ Ymir itself the instance lives at `apps/smidja/`** — it moved out of the repo
|
|
|
18
18
|
so the smithy sits with the other apps, and its runtime data
|
|
19
19
|
(`apps/smidja/smidja_data/`, gitignored) may also live at `$YMIR_HOME/smidja/`,
|
|
20
20
|
which the runtime prefers when it exists. Every path in *this* repo points at
|
|
21
|
-
`apps/smidja/`.
|
|
21
|
+
`apps/smidja/`. The monorepo tracks neither the factory nor the engine: the
|
|
22
|
+
factory is cloned from `zerwiz/smidja` into `apps/smidja-factory` by the
|
|
23
|
+
installer's `apps` step, and the engine is stamped into `apps/smidja` from that
|
|
24
|
+
clone's `templates/smidja` — exactly as `install.py` does for a target repo.
|
|
22
25
|
|
|
23
26
|
## What it is
|
|
24
27
|
|
|
@@ -84,10 +87,10 @@ installed on this machine) — do not reintroduce `sqlite3`.
|
|
|
84
87
|
|
|
85
88
|
## The trace
|
|
86
89
|
|
|
87
|
-
- DB:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
- DB: **`$YMIR_HOME/smidja/smidja.db`** (WAL; read-only readers never block a run).
|
|
91
|
+
`0003-private-data-separation` moved it out of the checkout; an in-repo
|
|
92
|
+
`apps/smidja/smidja_data/smidja.db` is the fallback. Created at the first run
|
|
93
|
+
(`bin/smidja-bootstrap.sh`); `scripts/start.sh` resolves the same pair.
|
|
91
94
|
- Tables: `sessions` (`smidja_id, smidja_name, request, status, engineer,
|
|
92
95
|
started_at, ended_at, total_tokens, total_cost, archived`), `phases`
|
|
93
96
|
(`phase_id, smidja_id, seq, name, kind, owner, description, status, attempt,
|
|
@@ -111,8 +114,8 @@ installed on this machine) — do not reintroduce `sqlite3`.
|
|
|
111
114
|
saved `neutral` from an older build resolves to fensalir. The categorical
|
|
112
115
|
palettes (event dots, agent lanes in `src/lib/events.ts`) are data, not chrome,
|
|
113
116
|
and were re-cut onto the cloth while staying mutually distinct.
|
|
114
|
-
- `scripts/start.sh` raises it (`CMD_DB
|
|
115
|
-
`PORT=8437`); `scripts/stop.sh` lowers it. Port overrides:
|
|
117
|
+
- `scripts/start.sh` raises it (`CMD_DB=$YMIR_HOME/smidja/smidja.db`, else the
|
|
118
|
+
in-repo fallback; `PORT=8437`); `scripts/stop.sh` lowers it. Port overrides:
|
|
116
119
|
`SMIDJA_VIZ_API_PORT`.
|
|
117
120
|
- Served under Hlidskjalf's **Sessions** gate via **Open visualizer**
|
|
118
121
|
(`VITE_VISUALIZER_URL`, default `http://127.0.0.1:8437`).
|
|
@@ -142,7 +145,7 @@ every 5s, so a finished run appears without a reload.
|
|
|
142
145
|
|
|
143
146
|
`bin/nornir-job-observer.sh` runs on the Nornir schedule (06:00). It reads **only
|
|
144
147
|
Ymir's own runtime** — `docs/masterplan.md`, `.agents/agents`, `.agents/memory/well`,
|
|
145
|
-
`workspace/memory/runes_audit.md`,
|
|
148
|
+
`workspace/memory/runes_audit.md`, **`$YMIR_HOME/smidja/smidja.db`**, and the
|
|
146
149
|
read-only external worktree root — and writes only `state/observer.log` + Runes.
|
|
147
150
|
There is **no `~/command` connection** anywhere in Ymir. Rune sources:
|
|
148
151
|
`ymir.orders · ymir.agents · ymir.well · ymir.runes · smidja.runs ·
|
|
@@ -167,9 +170,11 @@ Expected: `2/2 phases passed`, a `smidja_id`, and the DB written. Then
|
|
|
167
170
|
`llama-cpp/<id>`; LM Studio `:1234` may be down. Confirm with `pi --list-models`.
|
|
168
171
|
3. **The visualizer's local `node_modules` may be a partial bun install** — the API
|
|
169
172
|
still serves the prebuilt `dist/`, so open `:8437`, not `:8438`.
|
|
170
|
-
4. **Never edit `smidja/smidja_data/sessions/`** — it is the run record.
|
|
171
|
-
5. **Protected files** (`smidja/smidja_modules/`, `smidja/smidja_*.py`, the config)
|
|
173
|
+
4. **Never edit `apps/smidja/smidja_data/sessions/`** — it is the run record.
|
|
174
|
+
5. **Protected files** (`apps/smidja/smidja_modules/`, `apps/smidja/smidja_*.py`, the config)
|
|
172
175
|
are enforced by `smidja_modules/permissions.py`; agents roll back unauthorized
|
|
173
|
-
changes.
|
|
176
|
+
changes. The smithy moved from the repo root `smidja/` to `apps/smidja/`
|
|
177
|
+
(Amendment C); `bin/smidja-bootstrap.sh` searches both so a stale layout cannot
|
|
178
|
+
break the DB seed again.
|
|
174
179
|
6. New skills synthesized for the smithy are validated in Utgard (Gungnir, W0007)
|
|
175
180
|
before production.
|