@zerwiz/ymir 0.1.5 → 0.1.8
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 +290 -24
- 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 +1362 -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 +156 -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/einherjar-spawn.sh +9 -3
- package/bin/eir-doctor.sh +89 -1
- package/bin/electron-lib.sh +34 -0
- 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-board.sh +136 -0
- package/bin/smidja-bootstrap.sh +5 -1
- package/bin/smidja-lib.sh +49 -0
- 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 +257 -57
- package/bin/ymir-plan.sh +390 -0
- package/bin/ymir-say.sh +14 -1
- package/bin/ymir-setup-auth.sh +12 -1
- package/bin/ymir-style.sh +108 -0
- package/bin/ymir-validate.sh +64 -11
- package/bin/ymir.js +82 -34
- package/docs/design.md +2 -2
- 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 +65 -3
- 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
package/bin/ymir.js
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* ymir — the CLI the npm package publishes.
|
|
3
|
+
* ymir — the CLI the npm package publishes, and the operator's front door.
|
|
4
4
|
*
|
|
5
5
|
* It is a thin, honest wrapper: the real work lives in the shell scripts under
|
|
6
|
-
* bin
|
|
7
|
-
* npm needs a Node entry point (`bin: ymir`) and because
|
|
8
|
-
*
|
|
6
|
+
* bin/ and scripts/ — the same scripts a git clone runs. This file exists
|
|
7
|
+
* because npm needs a Node entry point (`bin: ymir`) and because an operator
|
|
8
|
+
* should never have to know where the package landed.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* ymir
|
|
10
|
+
* The doors are named for the figure whose work they do (the naming law):
|
|
11
|
+
* Eir heals, Gróa renews, Heimdall keeps the way in, Smíðja is the smithy and
|
|
12
|
+
* its board, Hlidskjalf the high seat, Sessrúmnir the seat-hall, Mímir the well.
|
|
13
|
+
*
|
|
14
|
+
* ymir first setup (the same as `ymir install`)
|
|
15
|
+
* ymir install [...] first setup, idempotent and self-healing
|
|
16
|
+
* ymir raise / lower lift the hall, or lay it down
|
|
17
|
+
* ymir eir what stands, and mend what does not
|
|
18
|
+
* ymir groa take the latest, and mend this home forward
|
|
19
|
+
* ymir heimdall the way in: your credential, and invites
|
|
20
|
+
* ymir smidja the smithy's board (:8437) — build · start · stop · status
|
|
21
|
+
* ymir hlidskjalf the high seat's window
|
|
22
|
+
* ymir sessrumnir the seat-hall's window
|
|
23
|
+
* ymir mimir the memory well
|
|
24
|
+
* ymir sense what THIS machine is
|
|
15
25
|
* ymir --version
|
|
16
26
|
*
|
|
27
|
+
* Colour appears only where a human is watching (a TTY, no NO_COLOR); the data
|
|
28
|
+
* on stdout is always plain TOON.
|
|
29
|
+
*
|
|
17
30
|
* Exit codes follow the scripts: 0 ok, 1 error, 2 usage.
|
|
18
31
|
*/
|
|
19
32
|
'use strict';
|
|
@@ -27,32 +40,65 @@ const pkg = (() => {
|
|
|
27
40
|
try { return require(path.join(ROOT, 'package.json')); } catch { return { version: '0.0.0' }; }
|
|
28
41
|
})();
|
|
29
42
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
// ── the cloth (the same palette as bin/ymir-style.sh, cut from the tokens) ───
|
|
44
|
+
const colour = process.stderr.isTTY && !process.env.NO_COLOR && process.env.TERM !== 'dumb';
|
|
45
|
+
const wrap = (code) => (s) => (colour ? `\u001b[${code}m${s}\u001b[0m` : `${s}`);
|
|
46
|
+
const bone = wrap('38;2;207;195;169');
|
|
47
|
+
const bronze = wrap('38;2;201;151;79');
|
|
48
|
+
const faint = wrap('38;2;107;98;80');
|
|
49
|
+
const blood = wrap('38;2;194;88;74');
|
|
50
|
+
const bold = wrap('1');
|
|
51
|
+
|
|
52
|
+
// ── the doors ────────────────────────────────────────────────────────────────
|
|
53
|
+
// verb → { script, args } — args are prepended to whatever the operator passes,
|
|
54
|
+
// so a verb can be a doorway to a sub-verb of a script that has several.
|
|
55
|
+
const DOORS = {
|
|
56
|
+
install: { script: 'bin/ymir-install.sh', about: 'first setup (idempotent, self-healing)' },
|
|
57
|
+
raise: { script: 'scripts/start.sh', about: 'lift the hall — SPA, gate API, Nornir, bridges, the board' },
|
|
58
|
+
lower: { script: 'scripts/stop.sh', about: 'lay the hall down' },
|
|
59
|
+
eir: { script: 'bin/eir-doctor.sh', about: 'diagnose every surface; mend what is broken' },
|
|
60
|
+
groa: { script: 'bin/groa-update.sh', about: 'take the latest, then mend this home forward' },
|
|
61
|
+
heimdall: { script: 'bin/ymir-setup-auth.sh', about: 'the way in — your credential (status · set · github)' },
|
|
62
|
+
invite: { script: 'bin/ymir-invite.sh', about: 'let someone else in (mint · list · revoke)' },
|
|
63
|
+
smidja: { script: 'bin/smidja-board.sh', about: "the smithy's board on :8437 (build · start · stop · status)" },
|
|
64
|
+
hlidskjalf: { script: 'scripts/electron.sh', about: "the high seat's window", args: ['start', '--view', 'hlidskjalf'] },
|
|
65
|
+
sessrumnir: { script: 'scripts/electron.sh', about: "the seat-hall's window", args: ['start', '--view', 'sessrumnir'] },
|
|
66
|
+
mimir: { script: 'bin/mimir.sh', about: 'the memory well' },
|
|
67
|
+
sense: { script: 'bin/host-sense.sh', about: 'what THIS machine is' },
|
|
68
|
+
plan: { script: 'bin/ymir-plan.sh', about: 'what an install would do here — writes nothing' },
|
|
69
|
+
migrate: { script: 'bin/ymir-migrate.sh', about: "heal this home's structure forward (Gr\u00f3a's mend)" },
|
|
70
|
+
validate: { script: 'bin/ymir-validate.sh', about: 'alias of `ymir eir`' },
|
|
35
71
|
};
|
|
36
72
|
|
|
73
|
+
// Names the law has not given a home are kept for a while, so a muscle memory
|
|
74
|
+
// built yesterday still works — and says what to type instead.
|
|
75
|
+
const RENAMED = { validate: 'eir', auth: 'heimdall', desktop: 'hlidskjalf', doctor: 'eir', update: 'groa' };
|
|
76
|
+
|
|
37
77
|
function usage() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
);
|
|
78
|
+
const lines = [];
|
|
79
|
+
lines.push('');
|
|
80
|
+
lines.push(` ${bronze('\u16c9')} ${bold('Ymir')} ${faint(pkg.version)}`);
|
|
81
|
+
lines.push(` ${faint('the single-tenant agent operating system')}`);
|
|
82
|
+
lines.push('');
|
|
83
|
+
lines.push(bold(' The doors'));
|
|
84
|
+
for (const [verb, d] of Object.entries(DOORS)) {
|
|
85
|
+
lines.push(` ${bronze(verb.padEnd(11))} ${faint(d.about)}`);
|
|
86
|
+
}
|
|
87
|
+
lines.push('');
|
|
88
|
+
lines.push(bold(' Composed by hand'));
|
|
89
|
+
lines.push(` ${bronze('ymir groa migrate'.padEnd(11))} ${faint("heal this home's structure (run by groa / install)")}`);
|
|
90
|
+
lines.push(` ${bronze('ymir heimdall set'.padEnd(11))} ${faint('set the operator password (or `github`)')}`);
|
|
91
|
+
lines.push('');
|
|
92
|
+
lines.push(faint(' A bare `ymir` runs the first setup. Output is TOON; colour only on a TTY.'));
|
|
93
|
+
lines.push('');
|
|
94
|
+
process.stdout.write(lines.join('\n') + '\n');
|
|
49
95
|
}
|
|
50
96
|
|
|
51
97
|
function run(script, args) {
|
|
52
|
-
const file = path.join(ROOT,
|
|
98
|
+
const file = path.join(ROOT, script);
|
|
53
99
|
if (!fs.existsSync(file)) {
|
|
54
|
-
process.stderr.write(
|
|
55
|
-
process.stderr.write('help: reinstall — npm i -g @zerwiz/ymir, or git clone the distro\n
|
|
100
|
+
process.stderr.write(`${blood('error:')} ${script} is missing from this install\n`);
|
|
101
|
+
process.stderr.write(`${faint('help: reinstall — npm i -g @zerwiz/ymir, or git clone the distro')}\n`);
|
|
56
102
|
process.exit(1);
|
|
57
103
|
}
|
|
58
104
|
const r = spawnSync('bash', [file, ...args], { stdio: 'inherit' });
|
|
@@ -62,17 +108,19 @@ function run(script, args) {
|
|
|
62
108
|
const argv = process.argv.slice(2);
|
|
63
109
|
const first = argv[0];
|
|
64
110
|
|
|
65
|
-
if (!first) run(
|
|
111
|
+
if (!first) run(DOORS.install.script, []);
|
|
66
112
|
if (first === '--version' || first === '-v' || first === '-V') {
|
|
67
113
|
process.stdout.write(`${pkg.version}\n`);
|
|
68
114
|
process.exit(0);
|
|
69
115
|
}
|
|
70
116
|
if (first === '--help' || first === '-h' || first === 'help') { usage(); process.exit(0); }
|
|
71
117
|
|
|
72
|
-
|
|
73
|
-
if (!
|
|
74
|
-
|
|
75
|
-
process.stderr.write('
|
|
118
|
+
let door = DOORS[first];
|
|
119
|
+
if (!door) {
|
|
120
|
+
const replacement = RENAMED[first];
|
|
121
|
+
process.stderr.write(`${blood('error:')} unknown door ${bold(first)}\n`);
|
|
122
|
+
if (replacement) process.stderr.write(`${faint(`help: the door is named \`ymir ${replacement}\` now (the naming law — a figure does the work)`)}\n`);
|
|
123
|
+
process.stderr.write(`${faint('help: `ymir --help` lists every door')}\n`);
|
|
76
124
|
process.exit(2);
|
|
77
125
|
}
|
|
78
|
-
run(script, argv.slice(1));
|
|
126
|
+
run(door.script, [...(door.args || []), ...argv.slice(1)]);
|
package/docs/design.md
CHANGED
|
@@ -226,7 +226,7 @@ everywhere; never put bronze text on bronze.
|
|
|
226
226
|
- **Runecoded, not emoji.** A minimal, hand-drawn-style rune set replaces emoji
|
|
227
227
|
in all UI: 16×16 and 24×24 grid, 2px stroke, chisel bevel on primary.
|
|
228
228
|
- System subsystems each carry one rune-glyph (reuse Algiz-family geometry:
|
|
229
|
-
Bifrost gate, Ratatoskr squirrel, the Well). Map is in `midgard/design-system/icons.md`
|
|
229
|
+
Bifrost gate, Ratatoskr squirrel, the Well). Map is in `midgard/design-system/icons.md` and the library in `midgard/design-system/runes.md`.
|
|
230
230
|
- Status dot: filled rune ring (ok) / half-ring (warn) / broken ring (danger), never color-only.
|
|
231
231
|
|
|
232
232
|
### 4.5 Surface & texture
|
|
@@ -345,7 +345,7 @@ All components read tokens from `tokens.css`; color-only states are forbidden
|
|
|
345
345
|
|
|
346
346
|
- `docs/design.md` — this document (master).
|
|
347
347
|
- `midgard/design-system/tokens.css` — the consumable design tokens.
|
|
348
|
-
- `midgard/design-system/icons.md` — rune-glyph map (
|
|
348
|
+
- `midgard/design-system/icons.md` — rune-glyph map (21 glyphs, drawn in `icons/*.svg`).
|
|
349
349
|
- `docs/ymir-rut.md` Part 3 — the original Rut design-system specification this
|
|
350
350
|
document implements.
|
|
351
351
|
- `docs/lore.md` §VI — house lineage behind the house accents.
|
package/docs/lore.md
CHANGED
|
@@ -818,9 +818,13 @@ what belongs to all houses, nothing to one.
|
|
|
818
818
|
| Path | What it holds |
|
|
819
819
|
|------|---------------|
|
|
820
820
|
| `midgard/design-system/` | Theme tokens, icons, rune glyphs, component rules |
|
|
821
|
-
| `midgard/company_wiki/` | Cross-tenant company knowledge |
|
|
822
821
|
| `midgard/github_org_repos/` | GitHub organization repo inventory |
|
|
823
822
|
| `midgard/shared-packages/` | Shared npm/Python packages |
|
|
823
|
+
|
|
824
|
+
Midgard holds **public-by-design** cross-tenant assets only. Company knowledge —
|
|
825
|
+
policies, vision, specs, client names — is **tenant data** and lives at
|
|
826
|
+
`$YMIR_HOME/hodd/identity/companies/`. A company wiki here would publish that
|
|
827
|
+
company's internals in a public repo.
|
|
824
828
|
| `midgard/infrastructure/` | DB schemas, Caddyfile, cloudflared, oauth2-proxy |
|
|
825
829
|
|
|
826
830
|
**Rule:** Midgard is shared. No realm may mutate another realm's Midgard assets.
|
package/docs/runbooks/agents.md
CHANGED
|
@@ -6,7 +6,7 @@ symlinked into each harness.
|
|
|
6
6
|
## Where agents live
|
|
7
7
|
|
|
8
8
|
- **Canonical:** `.agents/agents/<name>-<craft>.md` (edit these only).
|
|
9
|
-
- **Bindings:** `.opencode/
|
|
9
|
+
- **Bindings:** `.opencode/agents/*.md` and `.pi/agents/*.md` are symlinks.
|
|
10
10
|
|
|
11
11
|
Rebind after any change:
|
|
12
12
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerwiz/ymir",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Ymir \u2014 the single-tenant agent operating system. Omarchy-first, host-aware, self-healing.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/zerwiz/ymir",
|
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
"bin/",
|
|
30
30
|
".agents/",
|
|
31
31
|
"scripts/",
|
|
32
|
-
"config/",
|
|
33
32
|
"RULES/",
|
|
34
33
|
"docs/",
|
|
35
34
|
"packaging/",
|
|
@@ -38,7 +37,12 @@
|
|
|
38
37
|
"CHANGELOG.md",
|
|
39
38
|
"LICENSE",
|
|
40
39
|
"NOTICE",
|
|
41
|
-
"!**/node_modules/**"
|
|
40
|
+
"!**/node_modules/**",
|
|
41
|
+
"!.agents/memory/kaia.engram*",
|
|
42
|
+
"!.agents/memory/well/*.jsonl",
|
|
43
|
+
"!.agents/memory/*.db",
|
|
44
|
+
"!**/__pycache__/",
|
|
45
|
+
"!**/*.pyc"
|
|
42
46
|
],
|
|
43
47
|
"engines": {
|
|
44
48
|
"node": ">=20"
|
|
@@ -53,5 +57,11 @@
|
|
|
53
57
|
"scripts": {
|
|
54
58
|
"test": "bash .agents/skills/galdr-ymirsystem/scripts/compliance-check.sh",
|
|
55
59
|
"compliance": "bash .agents/skills/galdr-ymirsystem/scripts/compliance-check.sh"
|
|
60
|
+
},
|
|
61
|
+
"optionalDependencies": {
|
|
62
|
+
"@zerwiz/hlidskjalf": "^0.1.0",
|
|
63
|
+
"@zerwiz/odrerir": "^0.1.0",
|
|
64
|
+
"@zerwiz/sessrumnir": "^0.1.8-alpha",
|
|
65
|
+
"@zerwiz/smidja-factory": "^0.1.0"
|
|
56
66
|
}
|
|
57
67
|
}
|
package/scripts/electron.sh
CHANGED
|
@@ -26,6 +26,19 @@ fi
|
|
|
26
26
|
VERSION="1.1.0"
|
|
27
27
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
28
28
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
29
|
+
|
|
30
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
31
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
32
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
33
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
34
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
35
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
36
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
37
|
+
done
|
|
38
|
+
unset _yr _yc
|
|
39
|
+
fi
|
|
40
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
41
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
29
42
|
APP="$ROOT/apps/hlidskjalf"
|
|
30
43
|
Odrerir_app="$ROOT/apps/odrerir"
|
|
31
44
|
NO_INSTALL=0
|
|
@@ -85,6 +98,23 @@ pid_of() {
|
|
|
85
98
|
printf '%s' "$(printf '%s\n' "$pids" | head -1)"
|
|
86
99
|
}
|
|
87
100
|
|
|
101
|
+
stop_view() { # stop ONE view's pids - and only that view's
|
|
102
|
+
local v="$1" pids
|
|
103
|
+
pids="$(view_pids "$v")"
|
|
104
|
+
if [ -z "$pids" ]; then
|
|
105
|
+
printf 'electron: %s already stopped\n' "$v"
|
|
106
|
+
rm -f "$(pid_file "$v")"
|
|
107
|
+
return 0
|
|
108
|
+
fi
|
|
109
|
+
local list; list="$(printf '%s' "$pids" | tr '\n' ',')"
|
|
110
|
+
printf '%s\n' "$pids" | xargs -r kill 2>/dev/null || true
|
|
111
|
+
sleep 0.5
|
|
112
|
+
local left; left="$(view_pids "$v")"
|
|
113
|
+
[ -z "$left" ] || printf '%s\n' "$left" | xargs -r kill -KILL 2>/dev/null || true
|
|
114
|
+
rm -f "$(pid_file "$v")"
|
|
115
|
+
printf 'electron: stopped %s pid(s)=%s\n' "$v" "${list%,}"
|
|
116
|
+
}
|
|
117
|
+
|
|
88
118
|
case "$ACTION" in
|
|
89
119
|
status)
|
|
90
120
|
printf 'electron[%s]{view,state,pid}:\n' "${#VIEWS[@]}"
|
|
@@ -93,15 +123,13 @@ case "$ACTION" in
|
|
|
93
123
|
done
|
|
94
124
|
exit 0 ;;
|
|
95
125
|
stop)
|
|
96
|
-
for
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
rm -f "$(pid_file "$v")"
|
|
104
|
-
done
|
|
126
|
+
# ONLY the view asked for. Walking every view here is why `stop --view odrerir`
|
|
127
|
+
# used to take the smithy's window down with it.
|
|
128
|
+
if [ "$VIEW" = both ]; then
|
|
129
|
+
for v in "${VIEWS[@]}"; do stop_view "$v"; done
|
|
130
|
+
else
|
|
131
|
+
stop_view "$VIEW"
|
|
132
|
+
fi
|
|
105
133
|
printf 'electron: stopped\n'
|
|
106
134
|
exit 0 ;;
|
|
107
135
|
start|hlidskjalf|smidja|odrerir) [ "$ACTION" = smidja ] && VIEW=smidja; [ "$ACTION" = odrerir ] && VIEW=odrerir ;;
|
|
@@ -109,7 +137,7 @@ case "$ACTION" in
|
|
|
109
137
|
esac
|
|
110
138
|
|
|
111
139
|
command -v npm >/dev/null 2>&1 || { printf 'error: npm not found\nhelp: install node/npm to run the desktop shell\n' >&2; exit 1; }
|
|
112
|
-
mkdir -p "$
|
|
140
|
+
mkdir -p "$YMIR_STATE_DIR"
|
|
113
141
|
|
|
114
142
|
if [ ! -x "$APP/node_modules/.bin/electron" ]; then
|
|
115
143
|
if [ "$NO_INSTALL" = 1 ]; then
|
|
@@ -151,14 +179,39 @@ fi
|
|
|
151
179
|
app_dir() { case "$1" in odrerir) printf '%s' "$Odrerir_app" ;; *) printf '%s' "$APP" ;; esac; }
|
|
152
180
|
view_host() { case "$1" in smidja) printf '%s' 'http://127.0.0.1:8437/' ;; odrerir) printf '%s' 'http://127.0.0.1:4322/' ;; *) printf '%s' 'http://127.0.0.1:3888/' ;; esac; }
|
|
153
181
|
|
|
182
|
+
service_up() { curl -s -o /dev/null --max-time 3 "$1" 2>/dev/null; }
|
|
183
|
+
wait_for_service() {
|
|
184
|
+
local u="$1" i
|
|
185
|
+
for i in $(seq 1 120); do service_up "$u" && return 0; sleep 0.5; done
|
|
186
|
+
return 1
|
|
187
|
+
}
|
|
188
|
+
# Does the compositor hold a window of this class at all? A process with no window
|
|
189
|
+
# cannot be focused, and focusing nothing is exactly the silence a click must not get.
|
|
190
|
+
window_present() {
|
|
191
|
+
command -v hyprctl >/dev/null 2>&1 || return 0 # no compositor to ask: assume yes
|
|
192
|
+
hyprctl clients 2>/dev/null | grep -qi "$1"
|
|
193
|
+
}
|
|
194
|
+
|
|
154
195
|
start_one() {
|
|
155
196
|
local v="$1" f l
|
|
156
197
|
f="$(pid_file "$v")"; l="$(log_file "$v")"
|
|
198
|
+
# THE SYSTEM FIRST. A shell whose backing service is down draws an empty window,
|
|
199
|
+
# and a window that never mapped cannot be focused. Clicking an icon must raise
|
|
200
|
+
# THE SYSTEM, so the service is converged before the window is judged.
|
|
201
|
+
local host; host="$(view_host "$v")"
|
|
202
|
+
if ! service_up "$host"; then
|
|
203
|
+
printf 'electron: %s has no service at %s — raising the system\n' "$v" "$host" >&2
|
|
204
|
+
( nohup bash "$ROOT/scripts/start.sh" >/dev/null 2>&1 </dev/null & )
|
|
205
|
+
if ! wait_for_service "$host"; then
|
|
206
|
+
printf 'electron: %s still does not answer at %s — see $YMIR_STATE_DIR/\n' "$v" "$host" >&2
|
|
207
|
+
fi
|
|
208
|
+
# A process that lived through the outage is windowless; it must be reborn.
|
|
209
|
+
if is_running "$v"; then stop_view "$v"; fi
|
|
210
|
+
fi
|
|
157
211
|
if is_running "$v"; then
|
|
158
|
-
# A
|
|
212
|
+
# A bound key must RAISE the app, never report that it is already up. The
|
|
159
213
|
# window lives on its own numbered desktop by design, so "nothing happens"
|
|
160
|
-
# is exactly what a
|
|
161
|
-
# desktop when the window is elsewhere.
|
|
214
|
+
# is exactly what a click must not do. focuswindow also switches desktops.
|
|
162
215
|
local cls state=already-up
|
|
163
216
|
cls="$(view_mark "$v")" # the window class, from the one place that defines it
|
|
164
217
|
if command -v hyprctl >/dev/null 2>&1; then
|
|
@@ -167,8 +220,14 @@ start_one() {
|
|
|
167
220
|
# string form is a syntax error there. This is the working idiom.
|
|
168
221
|
hyprctl dispatch "hl.dsp.focus({window=\"class:^${cls}\$\"})" >/dev/null 2>&1 && state=raised
|
|
169
222
|
fi
|
|
170
|
-
|
|
171
|
-
|
|
223
|
+
# A process whose window is gone cannot be focused — reborn, not silent.
|
|
224
|
+
if [ "$state" = already-up ] && ! window_present "$cls"; then
|
|
225
|
+
printf 'electron: %s is running without a window — restarting it\n' "$v" >&2
|
|
226
|
+
stop_view "$v"
|
|
227
|
+
else
|
|
228
|
+
printf 'electron[1]{view,state,pid}:\n "%s","%s",%s\n' "$v" "$state" "$(pid_of "$v")"
|
|
229
|
+
return 0
|
|
230
|
+
fi
|
|
172
231
|
fi
|
|
173
232
|
# Launch the REAL Electron binary, not the .bin node shim, so the recorded pid
|
|
174
233
|
# is the app itself (the shim spawns and would leave a stale/incorrect pid).
|
package/scripts/lower.sh
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# lower.sh — the whole house in one word: the windows first, then the web.
|
|
3
|
+
#
|
|
4
|
+
# The shells are lowered BEFORE the services, so no window is left watching a
|
|
5
|
+
# port that has just gone away. That order is the whole point of owning both
|
|
6
|
+
# lifecycles in one place.
|
|
7
|
+
#
|
|
8
|
+
# scripts/lower.sh # every shell + the services
|
|
9
|
+
# scripts/lower.sh --desktop # the shells only
|
|
10
|
+
# scripts/lower.sh --web # the services only
|
|
11
|
+
set -u
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
15
|
+
|
|
16
|
+
WHAT="all"
|
|
17
|
+
case "${1-}" in
|
|
18
|
+
--web) WHAT=web ;;
|
|
19
|
+
--desktop) WHAT=desktop ;;
|
|
20
|
+
-h|--help|"") sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
21
|
+
esac
|
|
22
|
+
|
|
23
|
+
if [ "$WHAT" != "web" ]; then
|
|
24
|
+
printf '\n— the windows —\n'
|
|
25
|
+
if [ -x "$ROOT/bin/sessrumnir.sh" ]; then
|
|
26
|
+
"$ROOT/bin/sessrumnir.sh" stop || printf 'lower: sessrumnir did not stop cleanly\n' >&2
|
|
27
|
+
fi
|
|
28
|
+
"$ROOT/scripts/electron.sh" stop || printf 'lower: electron.sh stop reported errors\n' >&2
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
if [ "$WHAT" != "desktop" ]; then
|
|
32
|
+
printf '\n— the web —\n'
|
|
33
|
+
"$ROOT/scripts/stop.sh" || printf 'lower: stop.sh reported errors\n' >&2
|
|
34
|
+
fi
|
package/scripts/raise.sh
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# raise.sh — the whole house in one word: the web AND the windows.
|
|
3
|
+
#
|
|
4
|
+
# scripts/start.sh raises the services; scripts/electron.sh raises the desktop
|
|
5
|
+
# shells. Two lifecycles that never met — which is why "the electrons are not
|
|
6
|
+
# running" was true while 28 processes stood, and why a web restart left the
|
|
7
|
+
# shells pointing at a dead port. This is the pair of hands.
|
|
8
|
+
#
|
|
9
|
+
# scripts/raise.sh # services + every desktop shell
|
|
10
|
+
# scripts/raise.sh --web # the services only
|
|
11
|
+
# scripts/raise.sh --desktop # the shells only
|
|
12
|
+
set -u
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
16
|
+
|
|
17
|
+
WHAT="all"
|
|
18
|
+
case "${1-}" in
|
|
19
|
+
--web) WHAT=web ;;
|
|
20
|
+
--desktop) WHAT=desktop ;;
|
|
21
|
+
-h|--help|"") sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
22
|
+
esac
|
|
23
|
+
|
|
24
|
+
if [ "$WHAT" != "desktop" ]; then
|
|
25
|
+
printf '\n— the web —\n'
|
|
26
|
+
"$ROOT/scripts/start.sh" || printf 'raise: start.sh reported errors\n' >&2
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
if [ "$WHAT" != "web" ]; then
|
|
30
|
+
printf '\n— the windows —\n'
|
|
31
|
+
# Every shell, by name: hlidskjalf is the default view; smidja and odrerir need
|
|
32
|
+
# their own start; sessrumnir is its own app.
|
|
33
|
+
"$ROOT/scripts/electron.sh" start || printf 'raise: hlidskjalf failed\n' >&2
|
|
34
|
+
for v in smidja odrerir; do
|
|
35
|
+
"$ROOT/scripts/electron.sh" start --view "$v" || printf 'raise: %s failed\n' "$v" >&2
|
|
36
|
+
done
|
|
37
|
+
if [ -x "$ROOT/bin/sessrumnir.sh" ]; then
|
|
38
|
+
"$ROOT/bin/sessrumnir.sh" start || printf 'raise: sessrumnir failed\n' >&2
|
|
39
|
+
fi
|
|
40
|
+
printf '\n'
|
|
41
|
+
"$ROOT/scripts/electron.sh" status
|
|
42
|
+
fi
|
package/scripts/start.sh
CHANGED
|
@@ -17,10 +17,57 @@ if [ -z "${YMIR_PLATFORM_LOADED:-}" ]; then
|
|
|
17
17
|
fi
|
|
18
18
|
|
|
19
19
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
20
|
+
# Where the smithy's parts live: apps/smidja-factory in a clone, or the
|
|
21
|
+
# @zerwiz/smidja-factory package in an npm install (bin/smidja-lib.sh).
|
|
22
|
+
if [ -z "${YMIR_SMIDJA_LIB_LOADED:-}" ]; then
|
|
23
|
+
_ys="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
24
|
+
for _yc in "$_ys/smidja-lib.sh" "$(dirname "$_ys")/bin/smidja-lib.sh"; do
|
|
25
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_SMIDJA_LIB_LOADED=1; break; }
|
|
26
|
+
done
|
|
27
|
+
unset _ys _yc
|
|
28
|
+
fi
|
|
29
|
+
smidja_visualizer_dir SMIDJA_VIZ
|
|
30
|
+
smidja_factory_dir SMIDJA_FACTORY
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# The operator's settings and secrets live in the home they chose, never in the
|
|
34
|
+
# code tree — a packaged install replaces its tree on upgrade, and a credential
|
|
35
|
+
# must never sit in a tree that ships (Rule 04).
|
|
36
|
+
if [ -z "${YMIR_HOARD_LIB_LOADED:-}" ]; then
|
|
37
|
+
_yr="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
38
|
+
for _yc in "$_yr/hoard-lib.sh" "$(dirname "$_yr")/bin/hoard-lib.sh"; do
|
|
39
|
+
[ -r "$_yc" ] && { . "$_yc"; YMIR_HOARD_LIB_LOADED=1; break; }
|
|
40
|
+
done
|
|
41
|
+
unset _yr _yc
|
|
42
|
+
fi
|
|
43
|
+
hoard_settings_dir YMIR_SETTINGS_DIR
|
|
44
|
+
hoard_local_env YMIR_ENV_FILE
|
|
45
|
+
hoard_state_dir YMIR_STATE_DIR
|
|
46
|
+
hoard_data_dir YMIR_DATA_DIR
|
|
47
|
+
|
|
48
|
+
# The roots that live OUTSIDE the code tree: this machine's records and the
|
|
49
|
+
# runtime state belong to the home the operator chose at installation, never in
|
|
50
|
+
# the tree — a packaged install replaces its tree on upgrade (Rule 04).
|
|
20
51
|
APP="$ROOT/apps/hlidskjalf"
|
|
21
52
|
RUN="$ROOT/.run"
|
|
22
53
|
PID_FILE="$RUN/hlidskjalf.pid"
|
|
23
54
|
LOG="$RUN/hlidskjalf.log"
|
|
55
|
+
|
|
56
|
+
# Load the platform env once (Rule 04): the gate, the Bifrost bridge and Mimir
|
|
57
|
+
# all read their credentials from .env.local — 0600, gitignored, never printed.
|
|
58
|
+
# The bun gate reads process.env, and nothing loaded the file for it, so a
|
|
59
|
+
# credential set by bin/ymir-setup-auth.sh never reached it — and the gate treats
|
|
60
|
+
# an empty GATE_AUTH as "open". Loaded before the ports below so those may be
|
|
61
|
+
# overridden from it too.
|
|
62
|
+
if [ -r "$YMIR_ENV_FILE" ]; then
|
|
63
|
+
set +eu
|
|
64
|
+
set -a
|
|
65
|
+
# shellcheck disable=SC1090,SC1091
|
|
66
|
+
. "$YMIR_ENV_FILE" || true
|
|
67
|
+
set +a
|
|
68
|
+
set -eu
|
|
69
|
+
fi
|
|
70
|
+
|
|
24
71
|
PORT="${HLIDSKJALF_PORT:-3888}"
|
|
25
72
|
|
|
26
73
|
mkdir -p "$RUN"
|
|
@@ -43,6 +90,11 @@ fi
|
|
|
43
90
|
# Raise the gate API (real runtime data) when bun is available. Demo mode works
|
|
44
91
|
# without it; live data needs it.
|
|
45
92
|
API_PORT="${HLIDSKJALF_API_PORT:-3889}"
|
|
93
|
+
# The public hostnames the gate fronts (written by bin/gjallarhorn-expose.sh):
|
|
94
|
+
# without them the gate cannot route a host to its app, and the login page for
|
|
95
|
+
# that app would never be reached.
|
|
96
|
+
[ -r "$YMIR_STATE_DIR/gjallarhorn-hosts.env" ] && . "$YMIR_STATE_DIR/gjallarhorn-hosts.env" && \
|
|
97
|
+
export SMIDJA_HOST ODRERIR_HOST YMIR_PRIMARY_HOST
|
|
46
98
|
API_PID_FILE="$RUN/hlidskjalf-api.pid"
|
|
47
99
|
API_LOG="$RUN/hlidskjalf-api.log"
|
|
48
100
|
if command -v bun >/dev/null 2>&1; then
|
|
@@ -66,7 +118,7 @@ if [ -x "$ROOT/bin/nornir-cron-start.sh" ]; then
|
|
|
66
118
|
if "$ROOT/bin/nornir-cron-start.sh" >/dev/null 2>&1; then echo "Nornir cron: started"; else echo "Nornir cron: start failed" >&2; fi
|
|
67
119
|
fi
|
|
68
120
|
if [ -x "$ROOT/bin/bifrost-bridge.sh" ]; then
|
|
69
|
-
if BROKK_ENV_FILE="$
|
|
121
|
+
if BROKK_ENV_FILE="$YMIR_ENV_FILE" "$ROOT/bin/bifrost-bridge.sh" --start >/dev/null 2>&1; then echo "Bifrost bridge: up"; else echo "Bifrost bridge: not up (needs OPENCODE_GO_API_KEY)" >&2; fi
|
|
70
122
|
fi
|
|
71
123
|
# The well — Mimirsbrunn (engram) on :4602; the gate API and mimir.sh drink here.
|
|
72
124
|
if [ -x "$ROOT/bin/mimir-bridge.sh" ]; then
|
|
@@ -76,12 +128,22 @@ fi
|
|
|
76
128
|
# Smíðja's eye — the Vue trace visualizer (API :8437, UI :8438). Reads the repo's
|
|
77
129
|
# own smidja.db and exposes the Sessions/Trace/Decisions/Stats views behind the
|
|
78
130
|
# Hlidskjalf Sessions gate's "Open visualizer" button.
|
|
79
|
-
VIZ_DIR="$
|
|
131
|
+
VIZ_DIR="${SMIDJA_VIZ:-}"
|
|
80
132
|
VIZ_API_PORT="${SMIDJA_VIZ_API_PORT:-8437}"
|
|
81
133
|
VIZ_UI_PORT="${SMIDJA_VIZ_UI_PORT:-8438}"
|
|
82
134
|
VIZ_API_PID_FILE="$RUN/smidja-viz-api.pid"
|
|
83
135
|
VIZ_UI_PID_FILE="$RUN/smidja-viz-ui.pid"
|
|
84
|
-
SMIDJA_DB_PATH="${SMIDJA_DB
|
|
136
|
+
SMIDJA_DB_PATH="${SMIDJA_DB:-}"
|
|
137
|
+
# The smithy DB follows the HOME: 0003-private-data-separation moved it to
|
|
138
|
+
# $YMIR_HOME/smidja/smidja.db. Prefer an existing DB there, then an in-repo copy
|
|
139
|
+
# for a checkout that keeps its own; SMIDJA_DB overrides either.
|
|
140
|
+
if [ -z "$SMIDJA_DB_PATH" ]; then
|
|
141
|
+
for _db in "${YMIR_HOME:-$HOME/Documents/Ymir}/smidja/smidja.db" \
|
|
142
|
+
"$ROOT/apps/smidja/smidja_data/smidja.db"; do
|
|
143
|
+
[ -f "$_db" ] && { SMIDJA_DB_PATH="$_db"; break; }
|
|
144
|
+
done
|
|
145
|
+
SMIDJA_DB_PATH="${SMIDJA_DB_PATH:-${YMIR_HOME:-$HOME/Documents/Ymir}/smidja/smidja.db}"
|
|
146
|
+
fi
|
|
85
147
|
if command -v bun >/dev/null 2>&1 && [ -d "$VIZ_DIR" ]; then
|
|
86
148
|
[ -d "$VIZ_DIR/node_modules" ] || (cd "$VIZ_DIR" && bun install >/dev/null 2>&1 || true)
|
|
87
149
|
# The API serves the UI from ./dist. Without a build it answers the API but
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# config/agents.yaml — the Allfather's own combination of smiths and models.
|
|
2
|
-
#
|
|
3
|
-
# THIS IS YOUR FILE. Edit it, then run: bin/agents-config.sh apply
|
|
4
|
-
# No other Ymir file hardcodes a model for you; this YAML is the one place.
|
|
5
|
-
# Any agent without its own `model:` inherits `default_model`.
|
|
6
|
-
|
|
7
|
-
version: 1
|
|
8
|
-
|
|
9
|
-
# The harness is chosen by where the model lives — local through pi, online
|
|
10
|
-
# through opencode. An agent may still name `harness:` to override the rule.
|
|
11
|
-
harness:
|
|
12
|
-
local: pi # a model on a local provider runs through pi
|
|
13
|
-
online: opencode # a hosted model runs through opencode
|
|
14
|
-
local_providers: [llama.cpp, llama-cpp, lmstudio]
|
|
15
|
-
# The same local server is named differently per harness; translate on the way.
|
|
16
|
-
providers:
|
|
17
|
-
llama.cpp: { pi: llama-cpp }
|
|
18
|
-
|
|
19
|
-
# The fallback smith for any agent that does not name a model.
|
|
20
|
-
default_model: llama.cpp/qwen3.6-35b-a3b@q2_k_xl
|
|
21
|
-
|
|
22
|
-
# Local, keyless model servers. `apply` writes these into the project harness
|
|
23
|
-
# config (opencode.json) so a model listed here is immediately usable. A bare
|
|
24
|
-
# alias (no @quant) is auto-resolved against the server's /v1/models.
|
|
25
|
-
providers:
|
|
26
|
-
llama.cpp:
|
|
27
|
-
npm: "@ai-sdk/openai-compatible"
|
|
28
|
-
name: "llama-server (local)"
|
|
29
|
-
base_url: "http://127.0.0.1:8080/v1"
|
|
30
|
-
models:
|
|
31
|
-
# A local llama.cpp router needs the EXACT served id (the @quant suffix);
|
|
32
|
-
# `apply` resolves the bare alias below to the id the server reports.
|
|
33
|
-
- frontend-design-expert-8b
|
|
34
|
-
|
|
35
|
-
# agent name -> { model, harness?, primary? }. Omit model to inherit
|
|
36
|
-
# default_model. Omit harness to follow the local/online rule above.
|
|
37
|
-
# `primary: true` marks the agent runnable directly (mode: all), not only
|
|
38
|
-
# dispatchable by another agent.
|
|
39
|
-
agents:
|
|
40
|
-
brokk: { model: llama.cpp/qwen3.6-35b-a3b@q2_k_xl }
|
|
41
|
-
# Hnoss the Shaper runs local (no cloud key) -> pi, and is directly runnable.
|
|
42
|
-
hnoss: { model: "llama.cpp/qwen3.6-35b-a3b@q2_k_xl", primary: true }
|
|
43
|
-
sindri: { model: llama.cpp/qwen3.6-35b-a3b@q2_k_xl }
|
|
44
|
-
bragi: { model: llama.cpp/qwen3.6-35b-a3b@q2_k_xl }
|
|
45
|
-
huginn: { model: llama.cpp/qwen3.6-35b-a3b@q2_k_xl }
|
|
46
|
-
kvasir: { model: llama.cpp/qwen3.6-35b-a3b@q2_k_xl }
|
|
47
|
-
mimir: { model: llama.cpp/qwen3.6-35b-a3b@q2_k_xl }
|
|
48
|
-
snotra: { model: llama.cpp/qwen3.6-35b-a3b@q2_k_xl }
|
|
49
|
-
forseti: { model: llama.cpp/qwen3.6-35b-a3b@q2_k_xl }
|
|
50
|
-
galdr: { model: llama.cpp/qwen3.6-35b-a3b@q2_k_xl }
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# config/tailscale-sync.example.yaml — TEMPLATE for the Allfather's machine mesh.
|
|
2
|
-
#
|
|
3
|
-
# Copies to the private, gitignored config/tailscale-sync.yaml on install, or
|
|
4
|
-
# run: bin/tailscale-sync.sh init
|
|
5
|
-
# Override the path with YMIR_TAILSCALE_SYNC.
|
|
6
|
-
#
|
|
7
|
-
# Sync is peer-to-peer over Tailscale (rsync over ssh, addressed by MagicDNS).
|
|
8
|
-
# There is no central server and no relay unless the Allfather adds one.
|
|
9
|
-
|
|
10
|
-
machine: zerwiz
|
|
11
|
-
|
|
12
|
-
# The allowlist: only these tailnet hosts may be synced with. Use the MagicDNS
|
|
13
|
-
# name (e.g. `ymir-desktop`) or the tailnet IP.
|
|
14
|
-
peers:
|
|
15
|
-
- host: omarchy-1
|
|
16
|
-
- host: zerwizserver
|
|
17
|
-
|
|
18
|
-
# What may move. Paths are on both ends; ~ expands on each machine.
|
|
19
|
-
paths:
|
|
20
|
-
- ~/.pi/agent/models.json
|
|
21
|
-
- ~/.pi/agent/models-store.json
|
|
22
|
-
- ~/.pi/agent/settings.json
|
|
23
|
-
- ~/.pi/agent/trust.json
|
|
24
|
-
|
|
25
|
-
# auth.json holds live credentials. Leave false unless the Allfather trusts
|
|
26
|
-
# every listed peer to hold them; Tailscale encrypts the wire, not the trust.
|
|
27
|
-
include_auth: false
|
|
Binary file
|
|
Binary file
|
|
Binary file
|