@zerwiz/ymir 0.1.0 → 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.
Files changed (2) hide show
  1. package/README.md +563 -21
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,41 +1,583 @@
1
- # Ymir — official download
1
+ # @zerwiz/ymir
2
2
 
3
- The **front door** to the Ymir distro: one command to install it locally on your
4
- own machine. No hosting, no accounts — a local install first.
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
- curl -fsSL https://get.ymir.sh | bash
18
+ curl -fsSL https://raw.githubusercontent.com/zerwiz/ymir-release/main/install.sh | bash
9
19
 
10
20
  # npm
11
- npx ymir init
21
+ npx @zerwiz/ymir # add --check to see the plan, --yes to run unattended
22
+ ```
23
+
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
+ ![Ymir — the single-tenant agent OS](assets/ymir-banner-03.png)
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.
43
+
44
+ ---
45
+
46
+ ## The Allfather's Chain
47
+
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.
51
+
52
+ ---
53
+
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 |
68
+ |---|---|
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
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
297
+ ```
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)
12
320
  ```
13
321
 
14
- Both run the **same** thing: fetch the distro, then run its installer
15
- (`bin/ymir-install.sh`), which stands the whole system up and validates it.
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.
16
327
 
17
- ## What it does
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.
18
332
 
19
333
  ```
20
- 1. checks prereqs (git, curl) and clones/updates the distro into $YMIR_HOME (default ~/.ymir)
21
- 2. runs bash ~/.ymir/bin/ymir-install.sh "$@"
22
- 3. the installer is idempotent: it asks before it writes, self-heals what it can,
23
- and reports honestly what it cannot
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"
24
338
  ```
25
339
 
26
- ## Environment
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).
27
387
 
28
388
  ```
29
- YMIR_HOME where the distro lives (default: ~/.ymir)
30
- YMIR_REPO the distro git remote (default: https://github.com/zerwiz/ymir.git)
31
- YMIR_BRANCH the branch to track (default: main)
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:
451
+
452
+ ```bash
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
32
456
  ```
33
457
 
34
- ## The distro
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**:
489
+
490
+ ```sh
491
+ YMIR_SERVER_URL=https://your.server npx cap sync android
492
+ ```
493
+
494
+ Default target is `https://<your-host>` (`capacitor.config.ts`).
495
+
496
+ - **PWA.** Open the tunnel URL on a phone and “Add to Home Screen” — the manifest
497
+ ships in `apps/hlidskjalf/public/manifest.webmanifest`.
498
+
499
+ ---
500
+
501
+ ## Naming Law
502
+
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).
508
+
509
+ ---
510
+
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
521
+
522
+ ---
523
+
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 |
35
573
 
36
- This repo only carries the **bootstrap** (`install.sh` + the `ymir` npm bin). The
37
- system itself lives in [`zerwiz/ymir`](https://github.com/zerwiz/ymir).
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.
38
578
 
39
- ## License
579
+ Thank you all. The forge is hot because you lit it.
40
580
 
41
- Apache-2.0see [LICENSE](LICENSE).
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._
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zerwiz/ymir",
3
- "version": "0.1.0",
4
- "description": "Ymir \u2014 the official local installer (curl | bash, or npx ymir)",
3
+ "version": "0.1.2",
4
+ "description": "Ymir the official local installer (curl | bash, or npx ymir)",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "ymir": "bin/ymir.js"