@zerwiz/ymir 0.1.1 → 0.1.2
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/README.md +545 -49
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,87 +1,583 @@
|
|
|
1
1
|
# @zerwiz/ymir
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<p align="center">
|
|
7
|
+
<strong>created by zerwiz</strong> · <a href="https://zerwiz.org">https://zerwiz.org</a> · whynotproductions<br>
|
|
8
|
+
<em>a hobby project, made for the love of the craft. use it, fork it, enjoy it.</em>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
> **The front door to Ymir** — a single-operator, self-hosted, multi-agent AI runtime.
|
|
14
|
+
> One command stands it up on your own machine. No hosting, no accounts.
|
|
5
15
|
|
|
6
16
|
```bash
|
|
7
17
|
# curl
|
|
8
18
|
curl -fsSL https://raw.githubusercontent.com/zerwiz/ymir-release/main/install.sh | bash
|
|
9
19
|
|
|
10
20
|
# npm
|
|
11
|
-
npx @zerwiz/ymir
|
|
21
|
+
npx @zerwiz/ymir # add --check to see the plan, --yes to run unattended
|
|
12
22
|
```
|
|
13
23
|
|
|
14
|
-
|
|
15
|
-
|
|
24
|
+
This npm package is only the **bootstrap** (install.sh + a thin `ymir` bin): it
|
|
25
|
+
fetches the Ymir distro and runs its installer, which provisions, self-heals and
|
|
26
|
+
**validates** what it claims is running. It carries no secrets.
|
|
27
|
+
|
|
28
|
+
> **Alpha** — the forge is hot and the anvil works, but expect rough edges, and do
|
|
29
|
+
> not expose it as a public service yet.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# YMIR — The Single-Tenant Agent Operating System
|
|
34
|
+
|
|
35
|
+
> **One operator. One repo. A whole business, run by a Norse-named agent fleet.**
|
|
36
|
+
|
|
37
|
+

|
|
38
|
+
|
|
39
|
+
Ymir is a lean, single-operator agentic OS. You are the **Allfather**; **Brokk** is
|
|
40
|
+
your primary agent; **Eindri** are the isolated workers it dispatches. Everything —
|
|
41
|
+
development, marketing, business strategy, life — runs from one repository, with an
|
|
42
|
+
audit ledger, a memory well, one tenant and its workspaces, and a control plane you actually look at.
|
|
16
43
|
|
|
17
44
|
---
|
|
18
45
|
|
|
19
|
-
##
|
|
46
|
+
## The Allfather's Chain
|
|
20
47
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
audit ledger, and an anti-hallucination gate — all on hardware you own.
|
|
48
|
+
The Allfather holds the only chain. If the Allfather does not draw it, Ymir walks
|
|
49
|
+
the machine as the Allfather walks it — no gate between the agent and the tools,
|
|
50
|
+
no second master but the Allfather's own hand.
|
|
25
51
|
|
|
26
|
-
|
|
52
|
+
---
|
|
27
53
|
|
|
28
|
-
|
|
54
|
+
## The Lore (short version)
|
|
55
|
+
|
|
56
|
+
Ymir is not a theme — the myths are **load-bearing allegory**. Every subsystem is
|
|
57
|
+
named for the figure whose role matches the machine's job:
|
|
58
|
+
|
|
59
|
+
The platform is the primordial giant **Ymir**, from whose body the worlds were
|
|
60
|
+
carved. The smiths are **Brokk** (the bellows-smith, your primary agent) and
|
|
61
|
+
**Eindri** (the workers who out-forged the gods). Memory is **Mimirsbrunn**, the
|
|
62
|
+
well at the root of **Yggdrasil**, and **Kaia** is the oracle who speaks from it.
|
|
63
|
+
Every significant action is carved into **Runes**, an append-only ledger. Work
|
|
64
|
+
passes the **seven gates** and is built on **borrowed anvils** — validated open
|
|
65
|
+
source first, always. The full tale: [`docs/lore.md`](docs/lore.md).
|
|
66
|
+
|
|
67
|
+
| Component | Role |
|
|
29
68
|
|---|---|
|
|
30
|
-
| **Ymir** | the
|
|
31
|
-
| **Brokk** | the primary agent
|
|
32
|
-
| **Eindri** | isolated
|
|
33
|
-
| **
|
|
34
|
-
| **Yggdrasil** | git worktrees —
|
|
35
|
-
| **
|
|
36
|
-
| **
|
|
37
|
-
| **
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
##
|
|
69
|
+
| **Ymir** | the platform / host daemon |
|
|
70
|
+
| **Brokk** | the primary autonomous agent |
|
|
71
|
+
| **Eindri** | isolated workers — Sindri, Bragi, Huginn, Mímir, Forseti, Snotra, Kvasir |
|
|
72
|
+
| **Mimirsbrunn** | the memory well (engram) + Kaia's bridge |
|
|
73
|
+
| **Yggdrasil** | git worktrees — zero-collision parallelism |
|
|
74
|
+
| **Utgard** | ephemeral Docker sandboxes — the execution barrier |
|
|
75
|
+
| **Runes** | the append-only audit ledger |
|
|
76
|
+
| **Hlidskjalf** | the control plane / observability |
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## What it is
|
|
81
|
+
|
|
82
|
+
- **A distro, not an app.** Launch a supported harness in the repo and you take the
|
|
83
|
+
high seat: context is injected before your first turn, the model bridge is raised,
|
|
84
|
+
the scheduled jobs start.
|
|
85
|
+
- **Isolation by default.** Complex work runs in **Yggdrasil** worktrees sealed by
|
|
86
|
+
**Utgard** sandboxes; a failed run never touches main.
|
|
87
|
+
- **Audit everything.** **Runes** is an append-only, checksum-chained ledger.
|
|
88
|
+
- **Memory that grounds.** **Mimirsbrunn** (engram) is drunk from before dispatch and
|
|
89
|
+
watered after; a dry well never blocks.
|
|
90
|
+
- **Humans in the loop.** **Mjollnir** opens PRs; nothing force-merges.
|
|
91
|
+
- **Open source first.** Ymir owns only three things — the UI, the runtime, and
|
|
92
|
+
A2A collaboration. Everything else wears a Norse name over a validated engine.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Host platforms — three first-class identities
|
|
97
|
+
|
|
98
|
+
Ymir is not portable-in-theory; it is **native** to the machine it runs on. Three
|
|
99
|
+
platforms are first-class, and each one is detected, used, and learned rather than
|
|
100
|
+
merely tolerated.
|
|
101
|
+
|
|
102
|
+
| Identity | What it means | Where it lives |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| **Omarchy-native** | The host desktop is Omarchy (Arch + Hyprland). Ymir reads monitors/scale, lets Hyprland own window placement, mitigates the amdgpu GPU crash, and **learns the user's setup** — packages, configs, Omarchy version — re-learning after every `omarchy update` via a `post-update` hook. | `bin/omarchy-sense.sh`, `bin/omarchy-hook-install.sh`, skill `ymir` |
|
|
105
|
+
| **herdr-first (Þjazi)** | Agent panes need a terminal backend. **herdr** is preferred (Þjazi protocol **14+**; presentation spaces at **0.8.0+**), **tmux** is the accepted reference backend. A missing backend is reported, never silently degraded. | `bin/herdr-ensure.sh`, skill `ymir` |
|
|
106
|
+
| **pi-native** | The [pi](https://pi.dev) coding harness is a first-class surface: extensions, skills, prompt templates, themes, custom providers, and **pi packages** (npm/git) are all live. This is where Ymir gains reach — a new capability can be a pi extension or a packaged bundle, not just a shell script. | `.pi/extensions/`, `.pi/settings.json`, `.pi/mcp.json` |
|
|
107
|
+
|
|
108
|
+
**Why this matters.** The freedom runs both ways: because Ymir is pi-native it can
|
|
109
|
+
ship **pi packages** — bundling extensions, skills, prompt templates, and themes
|
|
110
|
+
for others to `pi install` — and because it is Omarchy-native it can help an
|
|
111
|
+
Omarchy user set up and tune the whole machine, not just the repo.
|
|
112
|
+
|
|
113
|
+
On a non-Omarchy host the Omarchy steps are a clean `SKIP`; Ymir still runs. On a
|
|
114
|
+
host without herdr, tmux carries the panes. On a harness that is not pi, the
|
|
115
|
+
runtime adapts through the harness adapters (see `hamr`).
|
|
116
|
+
|
|
117
|
+
### Omarchy-native
|
|
118
|
+
|
|
119
|
+
Ymir treats the host desktop as part of itself. It **detects** Omarchy
|
|
120
|
+
(`/usr/share/omarchy`), **reads** the real layout (`hyprctl monitors -j` — physical
|
|
121
|
+
size *and* scale, because a 1920×1200 panel at scale 1.5 is a 1280×800 logical
|
|
122
|
+
desktop, and mixing the two is the classic placement bug), and **lets Hyprland own
|
|
123
|
+
placement** rather than fighting the compositor.
|
|
124
|
+
|
|
125
|
+
- **Desktop placement.** On Omarchy the numbered **desktops** (`1 2 3 4 5 …`) are
|
|
126
|
+
the operator's "screens". `bin/desktop-place.sh` gives each Ymir app its **own
|
|
127
|
+
desktop, preferring an empty one**, via Omarchy's own rule idiom
|
|
128
|
+
(`o.window({ class = "^ymir-hlidskjalf$" }, { workspace = "2" })`), and never
|
|
129
|
+
edits `/usr/share/omarchy/`.
|
|
130
|
+
- **It learns the machine.** `bin/omarchy-sense.sh` records a comparable snapshot
|
|
131
|
+
(Omarchy version, explicit packages, config files, monitors, scale) and **diffs**
|
|
132
|
+
it, so Ymir can advise on *this* setup. `bin/omarchy-hook-install.sh` installs a
|
|
133
|
+
`post-update.d` hook, so **every `omarchy update` re-teaches it**.
|
|
134
|
+
- **It survives the hardware.** On a small-VRAM iGPU the Wayland GPU process can
|
|
135
|
+
die with `amdgpu: Not enough memory for command submission` (SIGSEGV, not an OOM);
|
|
136
|
+
`YMIR_DESKTOP_DISABLE_GPU=1` runs the dashboards on software rendering.
|
|
137
|
+
|
|
138
|
+
Full reference: the `ymir` skill. Omarchy's own skill is authoritative for
|
|
139
|
+
Omarchy itself; ours adds the Ymir integration.
|
|
140
|
+
|
|
141
|
+
### herdr-first (Þjazi)
|
|
142
|
+
|
|
143
|
+
Every Eindri worker lives in a terminal pane, so the backend matters. Ymir prefers
|
|
144
|
+
**herdr** and accepts **tmux** — and never degrades silently.
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
backend_priority[3]{rank,backend,note}:
|
|
148
|
+
"1","herdr","preferred; protocol 14+ for panes, 0.8.0+ for presentation spaces"
|
|
149
|
+
"2","tmux","verified reference backend"
|
|
150
|
+
"3","none","spawn is refused with a plain reason"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`bin/herdr-ensure.sh` verifies the *version* (not just presence) and installs via
|
|
154
|
+
the pinned, SHA-256-verified installer when herdr is absent. Selection order:
|
|
155
|
+
`config/backend` → `BROKK_BACKEND` → `HERDR_ENV=1` → else tmux. Full reference:
|
|
156
|
+
the `ymir` skill.
|
|
157
|
+
|
|
158
|
+
### pi-native
|
|
159
|
+
|
|
160
|
+
[pi](https://pi.dev) is the harness Ymir runs in, and Ymir uses that fully rather
|
|
161
|
+
than treating it as a shell to be wrapped:
|
|
162
|
+
|
|
163
|
+
- **Extensions** — `.pi/extensions/` carries live behaviour (the watcher arm, the
|
|
164
|
+
turn-end guard, the Ró presentation preference, the agent-state surface).
|
|
165
|
+
- **Packages** — `pi install npm:<pkg>` / `git:<repo>` bundles extensions, skills,
|
|
166
|
+
prompt templates, and themes. Ymir can **ship its own**, so a Ymir capability can
|
|
167
|
+
be distributed and installed like any pi package, not only as a shell script.
|
|
168
|
+
- **Model providers** — pi resolves models from `~/.pi/agent/models.json`, whose
|
|
169
|
+
shape is `{"providers": {...}}`. Local servers (LM Studio, Ollama, vLLM) and the
|
|
170
|
+
Bifrost bridge are configured the same way, so the fleet runs on local or cloud
|
|
171
|
+
models by the operator's choice.
|
|
172
|
+
|
|
173
|
+
This is the freedom you gain from being pi-native: a new capability has three
|
|
174
|
+
possible homes — a shell script, a skill, or a **pi package** — and the last one is
|
|
175
|
+
installable by anyone running pi.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## System Map
|
|
180
|
+
|
|
181
|
+
| Subsystem | Norse Name | Role |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| Platform root | **Ymir** | master daemon / host OS |
|
|
184
|
+
| Primary agent | **Brokk** | the autonomous operator's hand |
|
|
185
|
+
| Sub-agent workers | **Eindri** | isolated sandboxed workers |
|
|
186
|
+
| Git worktrees | **Yggdrasil** | zero-collision parallel edits |
|
|
187
|
+
| Docker sandbox | **Utgard** | ephemeral execution barrier |
|
|
188
|
+
| Gateway | **Bifrost** | reverse proxy / HTTP routing |
|
|
189
|
+
| Model bridge | **Bifrost bridge** | local OpenAI-compatible endpoint for the fleet |
|
|
190
|
+
| OAuth guard | **Heimdall** | GitHub OAuth / JWT |
|
|
191
|
+
| Tunnel | **Gjallarhorn** | Cloudflare outbound tunnel |
|
|
192
|
+
| Dashboard | **Hlidskjalf** | observability & control plane |
|
|
193
|
+
| File browser | **Skrymir** | web file explorer |
|
|
194
|
+
| Workspaces | **workspace/** | personal & work scopes over domains |
|
|
195
|
+
| Shared space | **Midgard** | shared assets & repos |
|
|
196
|
+
| Message bus | **Ratatoskr** | A2A 1.0 backbone (cards, lifecycle, Redis) |
|
|
197
|
+
| Vector memory | **Mimirsbrunn** | engram store + Kaia's bridge (`:4602`) |
|
|
198
|
+
| Audit ledger | **Runes** | append-only system log |
|
|
199
|
+
| Issue→PR | **Mjollnir** | autonomous fixes & PRs |
|
|
200
|
+
| Process monitor | **Valhalla** | PM2/Docker supervision |
|
|
201
|
+
| Skill synthesis | **Gungnir** | dynamic skill creation |
|
|
202
|
+
| Session digest | **Sága** | the context injected at session open |
|
|
203
|
+
| Watch / supervision | **Sýn** | watcher, guard, seat continuity |
|
|
204
|
+
| Session lock | **Gleipnir** | one live session per home |
|
|
205
|
+
| Scheduled jobs | **Nornir** | the fates who govern time |
|
|
206
|
+
| Host desktop (Omarchy) | **Omarchy** | the machine Ymir runs on: monitors, scale, themes, hooks |
|
|
207
|
+
| Terminal backend | **Þjazi** | agent panes — herdr (protocol 14+) or tmux |
|
|
208
|
+
| Harness surface | **pi** | extensions, skills, prompt templates, packages |
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Skills
|
|
213
|
+
|
|
214
|
+
Every reusable capability is a skill in [`.agents/skills/`](.agents/skills/), each
|
|
215
|
+
named for the figure whose role matches the work (the Gungnir naming law). Galdr is
|
|
216
|
+
the master builder; Tyr judges compliance.
|
|
217
|
+
|
|
218
|
+
| Skill | Norse | Purpose |
|
|
219
|
+
|---|---|---|
|
|
220
|
+
| `galdr` | Galdr | agent-CLI ergonomics + master builder/maintainer of the runtime |
|
|
221
|
+
| `tyr-check` | Tyr | the judge — validates tools/skills/docs against the 10 principles |
|
|
222
|
+
| `smidja` | Smiðja | the smithy: roster + bounded phases + typed envelopes |
|
|
223
|
+
| `hvild-afk` | Hvíld | away-mode supervision: routine wakes self-handled, escalations batched |
|
|
224
|
+
| `saga` | Sága | session bearings: fleet digest (/bearings) + recap (/ahoy) |
|
|
225
|
+
| `muninn-stow` | Muninn | session-knowledge curation, routing, and persistence |
|
|
226
|
+
| `jord-projects` | Jörð | project registry + delivery posture |
|
|
227
|
+
| `urdh` | Urðr | Allfather-hold lifecycle |
|
|
228
|
+
| `frigg-consent` | Frigg | consent / ask-user authority gate |
|
|
229
|
+
| `vor-diagnostics` | Vör | bootstrap + diagnostic reasoning |
|
|
230
|
+
| `nornir` | Nornir | fate & schedule: events + quota |
|
|
231
|
+
| `gjallarhorn-relay` | Gjallarhorn | public relay replies (X / Discord) |
|
|
232
|
+
| `eindri-homes` | Eindri | isolated worker homes |
|
|
233
|
+
| `syn-recovery` | Sýn | stuck-worker recovery playbook |
|
|
234
|
+
| `ymir` | Ymir | operate the host: update · Omarchy · Þjazi |
|
|
235
|
+
| `hamr` | Hamr | per-harness adapter reference (OpenCode, Pi, Claude, Cursor, Codex) |
|
|
236
|
+
|
|
237
|
+
The Galdr family enforces the 10 ergonomic principles (TOON output, minimal schemas,
|
|
238
|
+
self-correcting errors) and the runtime acceptance gates; run
|
|
239
|
+
`bash .agents/skills/galdr-cli/scripts/compliance-check.sh` before claiming done.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Agents
|
|
244
|
+
|
|
245
|
+
The **Eindri** take a mythic name whose craft matches the job, and each runs in an
|
|
246
|
+
Utgard sandbox on a Yggdrasil worktree.
|
|
247
|
+
|
|
248
|
+
| Eindri | Figure | Craft | Speciality |
|
|
249
|
+
|---|---|---|---|
|
|
250
|
+
| **Sindri** | the smith | developer | code synthesis, refactoring, tests, CLIs |
|
|
251
|
+
| **Bragi** | the skald | marketer | content, SEO, social, campaigns |
|
|
252
|
+
| **Huginn** | the sage | researcher | RAG, web search, analysis |
|
|
253
|
+
| **Mímir** | the wise | planner | architecture, sequencing, risk |
|
|
254
|
+
| **Forseti** | the just | reviewer | review, QA, acceptance — changes nothing |
|
|
255
|
+
| **Snotra** | the wise-woman | documenter | docs, write-ups, changelogs |
|
|
256
|
+
| **Kvasir** | the knowing | scout | reconnaissance — changes nothing |
|
|
257
|
+
|
|
258
|
+
Profiles live in [`.agents/agents/`](.agents/agents/) and are bound to each tool by
|
|
259
|
+
`bin/valknut-load.sh` (OpenCode reads `.opencode/agent/`; Pi links resolve under
|
|
260
|
+
`.pi/agents/`).
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## The Runtime — taking the seat
|
|
265
|
+
|
|
266
|
+
When a harness opens in the repo, **Sága** speaks before the first turn: the seat is
|
|
267
|
+
bound by **Gleipnir**, the model bridge is raised, the **Nornir** jobs start, and
|
|
268
|
+
the fleet context is injected (hidden, by design). Run-tier harnesses run the digest
|
|
269
|
+
and inject it; nudge-tier harnesses are asked.
|
|
270
|
+
|
|
271
|
+
| Harness | Session-start surface |
|
|
272
|
+
|---|---|
|
|
273
|
+
| **OpenCode** | `.opencode/plugins/{saga-sessionstart,syn-watch-arm,syn-turnend-guard}.js` |
|
|
274
|
+
| **Pi** | `.pi/extensions/{syn-turnend-guard,gna-pi-watch,ro,skuld-branch-supervision}.ts` |
|
|
275
|
+
| **Claude Code** | `.claude/settings.json` — `SessionStart` + `Stop` |
|
|
276
|
+
| **Cursor** | `.cursor/hooks.json` — `sessionStart` + `stop` + `preToolUse` |
|
|
277
|
+
| **Codex** | `.codex/hooks.json` — `SessionStart` + `PreToolUse` + `Stop` |
|
|
278
|
+
|
|
279
|
+
- **Seat:** `bin/saga-session-start.sh` — the one ordered digest.
|
|
280
|
+
- **Lock:** `bin/gleipnir-lock-lib.sh` — bound to the live session pid.
|
|
281
|
+
- **Bridge:** `bin/bifrost-bridge.sh` — raises the local model endpoint.
|
|
282
|
+
- **Jobs:** `bin/nornir-cron-start.sh` — daily briefing 07:00, observer, housekeeping, git sync.
|
|
283
|
+
- **Watch:** `bin/syn-watch-arm.sh` + the harness adapter.
|
|
284
|
+
|
|
285
|
+
Details: [`docs/session-start.md`](docs/session-start.md).
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## The Control Plane — Hlidskjalf
|
|
42
290
|
|
|
291
|
+
[`apps/hlidskjalf`](apps/hlidskjalf) is the dashboard. It runs **live** against a
|
|
292
|
+
small local gate API that reads the runtime, or in **demo mode** on seeded data.
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
scripts/start.sh # raises the gate API (:3889) + the SPA (:3888)
|
|
296
|
+
scripts/stop.sh
|
|
43
297
|
```
|
|
44
|
-
|
|
45
|
-
|
|
298
|
+
|
|
299
|
+
Views: Fleet · Tasks · Well · Runes · Reviews · Processes · Files · OmniChat ·
|
|
300
|
+
Runtime · Cron · Forge · Profile. OmniChat speaks to **Kaia** for real (recall from
|
|
301
|
+
the well, replies via the local model bridge). Press **Enter demo mode** on the sign-in
|
|
302
|
+
screen to explore without the runtime.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Quick Start
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
git clone <this-repo> ~/Ymir && cd ~/Ymir
|
|
310
|
+
cp .env.example .env.local # fill in your keys (never committed)
|
|
311
|
+
|
|
312
|
+
# 1) First setup — prints a plan, asks you to accept, then validates itself
|
|
313
|
+
bin/ymir-install.sh # add --yes for non-interactive, or --check to preview
|
|
314
|
+
|
|
315
|
+
# 2) The control plane (live data)
|
|
316
|
+
scripts/start.sh # → http://127.0.0.1:3888/
|
|
317
|
+
|
|
318
|
+
# 3) The agent seat (any supported harness)
|
|
319
|
+
bin/saga-session-start.sh # the digest (auto-runs on harness open)
|
|
46
320
|
```
|
|
47
321
|
|
|
322
|
+
The installer is idempotent and self-healing: it provisions what it can in user
|
|
323
|
+
space (`bun`, `uv`, `mcp`, the Þjazi backend), installs the OSS engines, learns
|
|
324
|
+
the machine, places the desktop apps, and — on an **Omarchy** host — sets the
|
|
325
|
+
update hook that re-teaches it after every `omarchy update`. It ends by opening
|
|
326
|
+
both desktop apps and running `bin/ymir-validate.sh` to prove what stands.
|
|
327
|
+
|
|
328
|
+
### What each platform buys you
|
|
329
|
+
|
|
330
|
+
The installer serves all three of Ymir's native homes on **every** run — a
|
|
331
|
+
non-Omarchy host loses only the Omarchy-specific hook, never the logic.
|
|
332
|
+
|
|
48
333
|
```
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
334
|
+
platform_gifts[3]{platform,what_the_install_does,what_you_gain}:
|
|
335
|
+
"Omarchy","detects the host, reads hyprctl monitors+scale, writes o.window desktop rules, snapshots the setup, installs the post-update hook","your dashboards land on their own numbered desktops; Ymir knows THIS machine and relearns it when Omarchy moves"
|
|
336
|
+
"herdr (Þjazi)","bin/herdr-ensure.sh verifies the version against the floors and installs via the pinned, SHA-verified installer; tmux is the accepted reference","every Eindri worker gets a real pane in a real terminal; presentation spaces at 0.8.0+, panes at protocol 14+"
|
|
337
|
+
"pi","registers the harness surfaces, the MCP servers, and the model providers (local LM Studio / Ollama or the Bifrost bridge)","extensions, skills, prompt templates, themes, and pi PACKAGES are all live — a new Ymir capability can ship as an installable pi package"
|
|
52
338
|
```
|
|
53
339
|
|
|
54
|
-
|
|
340
|
+
A new capability therefore has three possible homes — a shell script, a skill, or
|
|
341
|
+
a **pi package** — and on Omarchy it can also reach the desktop itself. That is the
|
|
342
|
+
freedom of being native to all three rather than portable to none.
|
|
343
|
+
|
|
344
|
+
Point a harness (OpenCode, Pi, Claude Code, Cursor, Codex) at the repo and it takes
|
|
345
|
+
the seat as **Brokk**. Read [`AGENTS.md`](AGENTS.md) for the operating laws and
|
|
346
|
+
[`docs/masterplan.md`](docs/masterplan.md) for the forge orders.
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Stack — Today vs Target
|
|
351
|
+
|
|
352
|
+
| Layer | Today (agent-proficient) |
|
|
353
|
+
|---|---|
|
|
354
|
+
| Control plane & daemons | **TypeScript** (Node 22) / **Bun** |
|
|
355
|
+
| Agent orchestration | **Python 3.12+** + TypeScript |
|
|
356
|
+
| UI / UX | **React + Vite** (Hlidskjalf) |
|
|
357
|
+
| Inter-agent | **A2A 1.0** (JSON-RPC 2.0 / SSE) + **Redis** |
|
|
358
|
+
| Memory | **engram** — the Mimirsbrunn well |
|
|
359
|
+
| Gateway / Auth / Tunnel | Traefik/Caddy · OAuth2-proxy · cloudflared |
|
|
360
|
+
| Sandbox | Docker (rootless, network-none) |
|
|
361
|
+
| Runtime backend | Pi / OpenCode harnesses; herdr/tmux panes |
|
|
362
|
+
|
|
363
|
+
**Target (Ymir Rut v2.6 — re-forged later, never redesigned):** Rust (Edition 2024) +
|
|
364
|
+
Tokio · NATS JetStream · gRPC/Protobuf · libgit2 · cgroups v2 / seccomp · PostgreSQL
|
|
365
|
+
16 · MinIO/S3. See [`docs/ymir-rut.md`](docs/ymir-rut.md).
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Design Language
|
|
370
|
+
|
|
371
|
+
**Carved, not skinned.** Cinzel (rune headings) · JetBrains Mono (code & telemetry) ·
|
|
372
|
+
Inter (body). Canvas: obsidian slate; accents: electric cyan for Bifrost, violet for
|
|
373
|
+
the realms. Emblem: the Algiz rune over a blacksmith's anvil. Tokens are the single
|
|
374
|
+
source of truth in [`midgard/design-system/tokens.css`](midgard/design-system/tokens.css);
|
|
375
|
+
full spec in [`docs/design.md`](docs/design.md).
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Folder Structure
|
|
380
|
+
|
|
381
|
+
> **Single tenant.** One operator (the Allfather), many **workspaces**
|
|
382
|
+
> (personal · work) over knowledge **domains** (company · marketing ·
|
|
383
|
+
> development · life · me). Houses (Ymir Labs, Brokk Forge, …) are brands, not
|
|
384
|
+
> isolation. OSS engines under Norse shells: **treehouse** → Yggdrasil
|
|
385
|
+
> (worktrees), **sandcastle** → Utgard (sandboxes), **no-mistakes** →
|
|
386
|
+
> Mjollnir/Glitnir (clean-PR gate).
|
|
387
|
+
|
|
388
|
+
```
|
|
389
|
+
ymir/
|
|
390
|
+
├── AGENTS.md # the always-loaded contract (Brokk)
|
|
391
|
+
├── bin/ # Norse runtime: saga, syn, rodd, gleipnir, nornir, einherjar,
|
|
392
|
+
│ # yggdrasil (treehouse), utgard (sandcastle), mimir-bridge,
|
|
393
|
+
│ # ymir-install, workspace-provision, project-git, mjollnir,
|
|
394
|
+
│ # hermes-ensure (provision the Hermes worker runtime)
|
|
395
|
+
├── .agents/
|
|
396
|
+
│ ├── agents/ # Brokk + the Eindri profiles (and Galdr)
|
|
397
|
+
│ ├── skills/ # Gungnir skills (galdr, tyr-check, hvild-afk, …)
|
|
398
|
+
│ ├── backend/ # vendored fleet backend
|
|
399
|
+
│ ├── config/ # ro, cron.yaml, eindri-dispatch, eindri-harness
|
|
400
|
+
│ ├── memory/ # Mimirsbrunn well — kaia.engram + episodes.jsonl
|
|
401
|
+
│ ├── sandbox/ # Utgard barrier (Dockerfile.utgard, utgard.config.json)
|
|
402
|
+
│ └── bus/ # Ratatoskr (A2A) protocol
|
|
403
|
+
├── .pi/extensions/ .pi/mcp.json # Pi adapters (Sýn, Gná, Ró, Skuld) + engram MCP
|
|
404
|
+
├── .opencode/plugins/ # OpenCode adapters (Sága, Sýn, Rödd)
|
|
405
|
+
├── apps/hlidskjalf/ # the control plane (React + Vite + Bun gate API)
|
|
406
|
+
├── midgard/ # shared assets, design tokens, icons
|
|
407
|
+
├── svartalfaheim/ # company container root (zerwiz) — future multi-user
|
|
408
|
+
├── workspace/ # THE SINGLE TENANT: work/ · personal/ · companies/ ·
|
|
409
|
+
│ # workspaces.yaml · projects.yaml · memory/ · INSTALL.md
|
|
410
|
+
├── smidja/ # the smithy engine + smidja.db (runs, stats, trace)
|
|
411
|
+
├── state/ # runtime state: lock, chat/, bridges, cron
|
|
412
|
+
├── scripts/start.sh stop.sh # raise/lower the whole system
|
|
413
|
+
├── assets/ # art, the OS diagram, reference material
|
|
414
|
+
└── docs/ # lore, architecture, masterplan, plans, session-start
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## Key combinations
|
|
420
|
+
|
|
421
|
+
Every key Ymir binds. On Omarchy they live in
|
|
422
|
+
`~/.config/hypr/ymir-launchers.lua` (generated by `bin/desktop-place.sh apply`)
|
|
423
|
+
and are required from `hyprland.lua`. See what is live with
|
|
424
|
+
`omarchy menu keybindings --print`.
|
|
425
|
+
|
|
426
|
+
| Key | What it does | Declared by |
|
|
427
|
+
|---|---|---|
|
|
428
|
+
| **SUPER + Y** | raise **Hlidskjalf** — the control plane | `bin/desktop-place.sh` → `~/.config/hypr/ymir-launchers.lua` |
|
|
429
|
+
| **SUPER + M** | raise **Smiðja** — the visualizer | same file |
|
|
430
|
+
| **ctrl + shift + e** | open the **file picker** over the working directory | `.pi/extensions/open-editor.ts` |
|
|
431
|
+
|
|
432
|
+
Each app window opens on **its own numbered desktop** (the placement rules in
|
|
433
|
+
`bin/desktop-place.sh` send it there), so a speed-start both raises the app and
|
|
434
|
+
keeps it off the desktop you are working on. `/edit [path]` is the same editor
|
|
435
|
+
surface as a slash command, with tab-completion over the directory.
|
|
436
|
+
|
|
437
|
+
Each app also offers the same speed-start **in its own UI** (`POST /api/desktop`),
|
|
438
|
+
so the keyboard is a convenience for the operator's hands, not the only way in.
|
|
439
|
+
|
|
440
|
+
> The editor is the Allfather's own surface: it registers no LLM tool, because
|
|
441
|
+
> agents already have `read` and `edit`. Name it when he would reach for it;
|
|
442
|
+
> never try to drive it.
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## Inviting someone else in
|
|
447
|
+
|
|
448
|
+
Ymir is single-operator by design: one person directs the fleet. Someone else can
|
|
449
|
+
try yours without being handed your account. The installer mints an **invite
|
|
450
|
+
code** and prints it at the end of the run:
|
|
55
451
|
|
|
56
452
|
```bash
|
|
57
|
-
|
|
58
|
-
|
|
453
|
+
bin/ymir-invite.sh mint --limit 3 # a code that admits 3 accounts
|
|
454
|
+
bin/ymir-invite.sh list # every code, what is spent, who is in
|
|
455
|
+
bin/ymir-invite.sh revoke CODE # take one back, now
|
|
59
456
|
```
|
|
60
457
|
|
|
61
|
-
|
|
62
|
-
|
|
458
|
+
They open the gate and choose **“I have an invite code”**, then pick their own
|
|
459
|
+
username and password. Registration stays **closed** unless a live code exists,
|
|
460
|
+
and each code stops admitting accounts once its ceiling is spent — so an instance
|
|
461
|
+
is never accidentally open, and a link that leaks is not a door.
|
|
462
|
+
|
|
463
|
+
Accounts live in `~/.config/ymir/accounts.json` (mode `0600`) as argon2id
|
|
464
|
+
hashes; no plaintext password is ever written, and nothing about them enters the
|
|
465
|
+
repo. Your own credentials stay `HLIDSKJALF_AUTH` in `.env.local`.
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Desktop & Mobile
|
|
470
|
+
|
|
471
|
+
- **Desktop (Electron).** `scripts/electron.sh start` (or `npm run desktop` in
|
|
472
|
+
`apps/hlidskjalf`) opens Hlidskjalf + Smiðja as a native window — app icon and
|
|
473
|
+
a stable “Ymir · Hlidskjalf” title. It raises the stack if it is down.
|
|
474
|
+
|
|
475
|
+
- **Android APK (Capacitor).** A thin native shell over the Hlidskjalf web app —
|
|
476
|
+
one codebase, pointed at your tunnel.
|
|
477
|
+
|
|
478
|
+
```sh
|
|
479
|
+
cd apps/hlidskjalf
|
|
480
|
+
npm install
|
|
481
|
+
npm run build
|
|
482
|
+
npx cap sync android
|
|
483
|
+
cd android
|
|
484
|
+
JAVA_HOME=<jdk-17> ANDROID_HOME=<android-sdk> ./gradlew assembleDebug
|
|
485
|
+
# → android/app/build/outputs/apk/debug/app-debug.apk
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Change the server later **without touching code**:
|
|
63
489
|
|
|
64
|
-
|
|
490
|
+
```sh
|
|
491
|
+
YMIR_SERVER_URL=https://your.server npx cap sync android
|
|
492
|
+
```
|
|
65
493
|
|
|
66
|
-
|
|
67
|
-
edges — and do not run it as a public service yet (auth hardens with Heimdall).
|
|
494
|
+
Default target is `https://<your-host>` (`capacitor.config.ts`).
|
|
68
495
|
|
|
69
|
-
|
|
496
|
+
- **PWA.** Open the tunnel URL on a phone and “Add to Home Screen” — the manifest
|
|
497
|
+
ships in `apps/hlidskjalf/public/manifest.webmanifest`.
|
|
70
498
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## Naming Law
|
|
74
502
|
|
|
75
|
-
|
|
503
|
+
Every subsystem, component, and process is named for the figure whose role matches
|
|
504
|
+
its work; the operator is the **Allfather** (Odin). The house voice is Norse-natural;
|
|
505
|
+
flavor may season a line, but an imported term never names a subsystem. The full
|
|
506
|
+
component map lives in
|
|
507
|
+
[`.agents/skills/galdr-cli/assets/norse-naming.md`](.agents/skills/galdr-cli/assets/norse-naming.md).
|
|
76
508
|
|
|
77
|
-
|
|
78
|
-
we did not build the engines, we built the hall around them, and we name them
|
|
79
|
-
proudly: **treehouse · sandcastle · no-mistakes · pi · oh-my-pi · hermes-agent ·
|
|
80
|
-
pi-desktop · A2A**, and the kunchenguid family (**firstmate · axi · lavish-axi**).
|
|
509
|
+
---
|
|
81
510
|
|
|
82
|
-
|
|
511
|
+
## Docs
|
|
512
|
+
|
|
513
|
+
- [`docs/lore.md`](docs/lore.md) — the mythos, realm by realm
|
|
514
|
+
- [`docs/session-start.md`](docs/session-start.md) — how the seat is taken
|
|
515
|
+
- [`docs/Architecture.md`](docs/Architecture.md) — the 7 realms, A2A, memory, migration
|
|
516
|
+
- [`docs/masterplan.md`](docs/masterplan.md) — the append-only forge orders
|
|
517
|
+
- [`docs/plans/README.md`](docs/plans/README.md) — the feature plan index
|
|
518
|
+
- [`docs/design.md`](docs/design.md) — the design system
|
|
519
|
+
- [`docs/ymir-rut.md`](docs/ymir-rut.md) — the Rust re-forging spec
|
|
520
|
+
- [`AGENTS.md`](AGENTS.md) — Brokk's always-loaded operating contract
|
|
83
521
|
|
|
84
522
|
---
|
|
85
523
|
|
|
86
|
-
|
|
87
|
-
|
|
524
|
+
> *“A webhook hits Bifrost and is queued on Ratatoskr. Ymir allocates resources and
|
|
525
|
+
> launches Brokk. Brokk drinks from Mimirsbrunn, cuts a branch via Yggdrasil inside
|
|
526
|
+
> Svartalfaheim, and hands execution to an Eindri inside Utgard. Tests pass, Mjollnir
|
|
527
|
+
> raises the PR, the outcome is observed back into the well, Runes carves the entry,
|
|
528
|
+
> and Hlidskjalf renders the state.”*
|
|
529
|
+
|
|
530
|
+
*The bellows feed the flame; the smith reads the metal; the well remembers every blow.*
|
|
531
|
+
|
|
532
|
+
## What was wrought — 2026-09-14
|
|
533
|
+
|
|
534
|
+
One day, one loom. Everything below lives in this main and in the world:
|
|
535
|
+
|
|
536
|
+
- **The cloth** — Hlidskjalf, Smiðja and Sessrúmnir wear one carved look (stone,
|
|
537
|
+
bronze, bone, blood; Cormorant · Newsreader · IBM Plex Mono); Smiðja's default
|
|
538
|
+
theme is **Fensalir**; text highlighting is carved amber — the blue is dead.
|
|
539
|
+
- **Óðrerir, the Live Hall** — the landing's live board: a dealt slate pile, a
|
|
540
|
+
carved ledger (underway · landed · charted), and a planning glass fed by real
|
|
541
|
+
machine state. See it at the landing repo: `zerwiz/ymir-homepage` (local:
|
|
542
|
+
`:4321`), with the `To the Hall` rune in every app's chrome.
|
|
543
|
+
- **The wake bridge** — every smith's finish files a saga and wakes the
|
|
544
|
+
primary; the echo-guard keeps the wire honest.
|
|
545
|
+
- **The mark** — recoloured into the cloth, and the anvil-bars bug found and
|
|
546
|
+
fixed (the metal was always there; now it is seen).
|
|
547
|
+
|
|
548
|
+
The lore runs to **XXXI — The Weaving of the Halls**; the masterplan carries
|
|
549
|
+
the full day's ledger.
|
|
550
|
+
|
|
551
|
+
---
|
|
552
|
+
|
|
553
|
+
## With gratitude — the people we stand on
|
|
554
|
+
|
|
555
|
+
Ymir is a Norse shell over other people's excellent work. We did not build the
|
|
556
|
+
engines; we built the hall around them. Every project below is theirs, kept under
|
|
557
|
+
their own licence, and we are glad to name them. Go and look at what they made —
|
|
558
|
+
follow them, star them, learn from them.
|
|
559
|
+
|
|
560
|
+
| Project | Who made it | Licence | What it powers in Ymir |
|
|
561
|
+
|---|---|---|---|
|
|
562
|
+
| [treehouse](https://github.com/kunchenguid/treehouse) | kunchenguid | MIT | Yggdrasil — git worktrees |
|
|
563
|
+
| [sandcastle](https://github.com/mattpocock/sandcastle) | [Matt Pocock](https://www.youtube.com/@mattpocockuk) | MIT | Utgard — sealed sandboxes |
|
|
564
|
+
| [no-mistakes](https://github.com/kunchenguid/no-mistakes) | kunchenguid | MIT | the clean-PR gate |
|
|
565
|
+
| [pi](https://github.com/earendil-works/pi) | Earendil Works | MIT | the coding harness |
|
|
566
|
+
| [oh-my-pi](https://github.com/can1357/oh-my-pi) | can1357 | MIT | prior art for the pi surface |
|
|
567
|
+
| [hermes-agent](https://github.com/NousResearch/hermes-agent) | Nous Research | MIT | the Hermes worker runtime |
|
|
568
|
+
| [pi-desktop](https://github.com/FaqFirebase/pi-desktop) | FaqFirebase and the Pi Desktop contributors | Apache-2.0 | Sessrúmnir (our re-themed fork) |
|
|
569
|
+
| [A2A protocol](https://github.com/a2aproject/a2a) | the A2A project | Apache-2.0 | the agent-to-agent backbone |
|
|
570
|
+
| [firstmate](https://github.com/kunchenguid/firstmate) | kunchenguid | MIT | the fleet |
|
|
571
|
+
| [axi](https://github.com/kunchenguid/axi) | kunchenguid | MIT | agent-ergonomics principles |
|
|
572
|
+
| [lavish-axi](https://github.com/kunchenguid/lavish-axi) | kunchenguid | MIT | the HTML-artifact editor |
|
|
573
|
+
|
|
574
|
+
Their full licence texts are bundled in [THIRD-PARTY-LICENSES](THIRD-PARTY-LICENSES),
|
|
575
|
+
and the audit of every demand is in [docs/third-party-audit.md](docs/third-party-audit.md).
|
|
576
|
+
If we have benefited from your work and missed you here, tell us — we will fix it,
|
|
577
|
+
loudly.
|
|
578
|
+
|
|
579
|
+
Thank you all. The forge is hot because you lit it.
|
|
580
|
+
|
|
581
|
+
_Where a maker teaches on YouTube we link the channel — Matt Pocock's is
|
|
582
|
+
[youtube.com/@mattpocockuk](https://www.youtube.com/@mattpocockuk). If you make a
|
|
583
|
+
tutorial for a project we use, tell us and we will link yours too._
|