@sigrun/sigrun 0.0.0-stage → 0.1.0

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 (130) hide show
  1. package/CHANGELOG.md +204 -0
  2. package/CONTEXT.md +163 -0
  3. package/LICENSE +21 -0
  4. package/README.md +691 -2
  5. package/THIRD_PARTY_NOTICES.md +28 -0
  6. package/dist/backup/marker.js +80 -0
  7. package/dist/backup/run-backup.js +339 -0
  8. package/dist/cli.js +952 -0
  9. package/dist/commands/expand.js +245 -0
  10. package/dist/commands/templates.js +272 -0
  11. package/dist/config.js +1146 -0
  12. package/dist/extension.d.ts +431 -0
  13. package/dist/harness/activity.js +42 -0
  14. package/dist/harness/ambient.js +261 -0
  15. package/dist/harness/auth.js +130 -0
  16. package/dist/harness/boot.js +865 -0
  17. package/dist/harness/builtins.js +191 -0
  18. package/dist/harness/event-bus.js +1203 -0
  19. package/dist/harness/health.js +30 -0
  20. package/dist/harness/identity/index.js +37 -0
  21. package/dist/harness/identity/invites.js +94 -0
  22. package/dist/harness/identity/json-store.js +108 -0
  23. package/dist/harness/identity/setup-code.js +81 -0
  24. package/dist/harness/identity/tokens.js +101 -0
  25. package/dist/harness/identity/users.js +93 -0
  26. package/dist/harness/interactions.js +283 -0
  27. package/dist/harness/loader.js +1236 -0
  28. package/dist/harness/memory-default.js +35 -0
  29. package/dist/harness/naming.js +193 -0
  30. package/dist/harness/packages.js +1002 -0
  31. package/dist/harness/providers/auth-bridge.js +60 -0
  32. package/dist/harness/providers/index.js +277 -0
  33. package/dist/harness/providers/models-store.js +105 -0
  34. package/dist/harness/providers/refresh.js +161 -0
  35. package/dist/harness/providers/scheduler.js +89 -0
  36. package/dist/harness/registry.js +9 -0
  37. package/dist/harness/reserved-sections.js +24 -0
  38. package/dist/harness/seam-host.js +239 -0
  39. package/dist/harness/sections/context-files.js +78 -0
  40. package/dist/harness/sections/model-guidance.js +77 -0
  41. package/dist/harness/settings.js +1053 -0
  42. package/dist/harness/stores.js +450 -0
  43. package/dist/harness/tools.js +500 -0
  44. package/dist/harness/workspace.js +73 -0
  45. package/dist/index.js +39 -0
  46. package/dist/jobs/docs.js +257 -0
  47. package/dist/jobs/fire.js +342 -0
  48. package/dist/jobs/index.js +228 -0
  49. package/dist/jobs/observe.js +165 -0
  50. package/dist/jobs/reconcile.js +245 -0
  51. package/dist/jobs/schedule.js +77 -0
  52. package/dist/jobs/spec.js +248 -0
  53. package/dist/jobs/task.js +190 -0
  54. package/dist/jobs/transfer.js +53 -0
  55. package/dist/serve.js +164 -0
  56. package/dist/server/auth/claim-lock.js +28 -0
  57. package/dist/server/auth/ip.js +51 -0
  58. package/dist/server/auth/login-limiter.js +52 -0
  59. package/dist/server/auth/loopback.js +47 -0
  60. package/dist/server/auth/pipeline.js +330 -0
  61. package/dist/server/auth/principal.js +26 -0
  62. package/dist/server/commands.js +198 -0
  63. package/dist/server/content-parts.js +142 -0
  64. package/dist/server/context.js +13 -0
  65. package/dist/server/conversation-handler.js +61 -0
  66. package/dist/server/conversation-ops.js +310 -0
  67. package/dist/server/events/hub.js +39 -0
  68. package/dist/server/events/types.js +8 -0
  69. package/dist/server/helpers.js +351 -0
  70. package/dist/server/host-bridge.js +131 -0
  71. package/dist/server/index.js +232 -0
  72. package/dist/server/notifications.js +185 -0
  73. package/dist/server/ownership.js +67 -0
  74. package/dist/server/readiness.js +36 -0
  75. package/dist/server/routes/auth.js +172 -0
  76. package/dist/server/routes/conversations.js +341 -0
  77. package/dist/server/routes/events.js +161 -0
  78. package/dist/server/routes/extension-routes.js +127 -0
  79. package/dist/server/routes/extensions.js +168 -0
  80. package/dist/server/routes/files.js +308 -0
  81. package/dist/server/routes/interactions.js +260 -0
  82. package/dist/server/routes/jobs.js +271 -0
  83. package/dist/server/routes/meta.js +146 -0
  84. package/dist/server/routes/metrics.js +219 -0
  85. package/dist/server/routes/onboarding.js +268 -0
  86. package/dist/server/routes/probes.js +53 -0
  87. package/dist/server/routes/providers.js +198 -0
  88. package/dist/server/routes/settings.js +48 -0
  89. package/dist/server/routes/stream.js +131 -0
  90. package/dist/server/routes/submissions.js +317 -0
  91. package/dist/server/routes/users.js +169 -0
  92. package/dist/server/schema-fixture.js +950 -0
  93. package/dist/server/session-meta.js +247 -0
  94. package/dist/server/static.js +169 -0
  95. package/dist/server/views.js +71 -0
  96. package/dist/skills/index.js +418 -0
  97. package/node_modules/@sigrun/shared/CHANGELOG.md +16 -0
  98. package/node_modules/@sigrun/shared/LICENSE +21 -0
  99. package/node_modules/@sigrun/shared/README.md +10 -0
  100. package/node_modules/@sigrun/shared/dist/access.d.ts +55 -0
  101. package/node_modules/@sigrun/shared/dist/access.js +72 -0
  102. package/node_modules/@sigrun/shared/dist/ambient.d.ts +111 -0
  103. package/node_modules/@sigrun/shared/dist/ambient.js +23 -0
  104. package/node_modules/@sigrun/shared/dist/commands.d.ts +75 -0
  105. package/node_modules/@sigrun/shared/dist/commands.js +25 -0
  106. package/node_modules/@sigrun/shared/dist/conversations.d.ts +31 -0
  107. package/node_modules/@sigrun/shared/dist/conversations.js +94 -0
  108. package/node_modules/@sigrun/shared/dist/interactions.d.ts +91 -0
  109. package/node_modules/@sigrun/shared/dist/interactions.js +21 -0
  110. package/node_modules/@sigrun/shared/dist/jobs.d.ts +100 -0
  111. package/node_modules/@sigrun/shared/dist/jobs.js +19 -0
  112. package/node_modules/@sigrun/shared/dist/json.d.ts +20 -0
  113. package/node_modules/@sigrun/shared/dist/json.js +13 -0
  114. package/node_modules/@sigrun/shared/dist/session-meta.d.ts +103 -0
  115. package/node_modules/@sigrun/shared/dist/session-meta.js +13 -0
  116. package/node_modules/@sigrun/shared/dist/settings.d.ts +401 -0
  117. package/node_modules/@sigrun/shared/dist/settings.js +19 -0
  118. package/node_modules/@sigrun/shared/dist/themes.d.ts +50 -0
  119. package/node_modules/@sigrun/shared/dist/themes.js +156 -0
  120. package/node_modules/@sigrun/shared/dist/turns.d.ts +102 -0
  121. package/node_modules/@sigrun/shared/dist/turns.js +166 -0
  122. package/node_modules/@sigrun/shared/dist/view-delta.d.ts +54 -0
  123. package/node_modules/@sigrun/shared/dist/view-delta.js +135 -0
  124. package/node_modules/@sigrun/shared/dist/views.d.ts +742 -0
  125. package/node_modules/@sigrun/shared/dist/views.js +38 -0
  126. package/node_modules/@sigrun/shared/package.json +83 -0
  127. package/package.json +90 -5
  128. package/webui/dist/assets/index-Rl0KhCLa.css +1 -0
  129. package/webui/dist/assets/index-rOiARZLF.js +50 -0
  130. package/webui/dist/index.html +37 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,204 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-10-21
11
+ ### Added (server)
12
+ - Conversation list fields: name, last-activity, parent (fork lineage),
13
+ archived and pinned on the list payload — the per-conversation meta
14
+ N+1 is gone; fork trees sort by newest activity anywhere in the tree.
15
+ - Automatic conversation naming: a one-shot naming call driven by the
16
+ `namingModel` setting (a model id, or `false` to disable; defaults to
17
+ the server default model with thinking off). Forks of named
18
+ conversations inherit `"<name> (fork)"`.
19
+
20
+ ### Added (tui)
21
+ - Fullscreen alt-screen UI with mouse support: per-keymap themes,
22
+ status bar, and a turn-grouped transcript with foldable turns.
23
+ - Action layer with configurable keymaps (standard / vim / emacs):
24
+ turn-aware search, prompt-jump and picker actions replace the
25
+ alt-screen built-ins; vim mode has real insert / normal / command
26
+ modes with `v` opening the prompt in vim.
27
+ - Key reference overlay (`?` in standard/emacs, `g?` in vim).
28
+
29
+ ### Added (webui)
30
+ - Theme system: palette / accent / mode, applied across the rail,
31
+ header and right-panel shell; visual design adapted from hermes-webui
32
+ by nesquena and contributors (credited in THIRD_PARTY_NOTICES).
33
+ - Sidebar: named, grouped, searchable conversation list with pin and
34
+ archive.
35
+ - Transcript: turn-grouped rendering with an activity line per turn
36
+ ("Thinking · 2 tools"), markdown everywhere, filterable tables
37
+ (filter bar above > 6 data rows), copy buttons on code blocks, a
38
+ transcript outline, and a scroll fade.
39
+ - Composer model and thinking pickers.
40
+
41
+ - Thinking blocks: `thinking` content blocks render as collapsible
42
+ `<details>` before each assistant message's text — expanded + pulsing
43
+ while the generation streams (`pi.live.generation.message` partials
44
+ render as a provisional entry), collapsed at rest, hidden entirely by
45
+ the new Interface setting.
46
+ - A "working…" indicator (three pulsing dots) driven by `steer.busy`,
47
+ reading "compacting…" while a compaction task is live, plus a persistent
48
+ compaction-failure alert from `pi.live.compactionFailure`.
49
+ - Submit chords: Ctrl+Enter / Cmd+Enter submit; the Interface setting's
50
+ "enter sends the prompt" adds plain-Enter submit (Shift+Enter stays a
51
+ newline).
52
+ - Settings sections: the panel gains a left nav (General / Tools /
53
+ Interface / Advanced). Interface holds the new client-only prefs
54
+ (`enterToSend`, `showThinking`) — localStorage-backed (`sigrun.prefs`),
55
+ applied live, never sent to the server.
56
+ - Workspace drawer: below 1000px the workspace panel opens as a right-side
57
+ overlay drawer (top-bar toggle, backdrop click / in-panel ✕ to close)
58
+ instead of being hidden.
59
+
60
+ ### Changed (webui)
61
+ - Tool-call-only assistant messages render nothing — the empty bubble
62
+ above a tool card is gone.
63
+ - The Compact button is removed (compaction is automatic server-side;
64
+ `/compact` remains a slash command). Composer controls sit in one row
65
+ (Attach · usage ring · Send) and the textarea matches their height.
66
+ - The settings gear is larger; the top bar wraps badges instead of
67
+ overflowing horizontally at narrow widths.
68
+
69
+ ### Fixed (webui)
70
+ - The Tools section's checkboxes collapsed into a vertical column with the
71
+ explanatory note clipped off the right edge (a `flex-direction` leak from
72
+ the `.settings-field` base), forcing a horizontal scrollbar.
73
+ - `pi.live` doc narrowing gained the `generation`/`compactions`/
74
+ `compactionFailure` shapes the new consumers read.
75
+ - Unified `extensions` list (install-and-load): one settings.json array
76
+ covers npm specifiers, `file:`/path checkouts, and git sources
77
+ (`git:host/path[@ref]` cloned into `<config-dir>/git/` with fetch/reconcile
78
+ + entry discovery: sigrun manifest > pi-compat manifest > dist/index.js >
79
+ index.ts). `{enabled: false}` = present-but-not-loaded. The separate
80
+ `packages` list is gone; `SIGRUN_EXTENSIONS` accepts the same grammar
81
+ per CSV chunk (JSON-object entries included).
82
+ ### Added
83
+ - pi-style extension packages: the settings file's top-level `packages`
84
+ array (file-only — no `SIGRUN_PACKAGES`) declares npm specifiers boot
85
+ installs into `<config-dir>/packages/` (a real npm root: synthetic
86
+ private `package.json` + `node_modules/`, pi's `~/.pi/agent/npm` shape),
87
+ pruning undeclared entries, with a no-subprocess fast path when the dir
88
+ already matches. The loader resolves each `extensions` name against the
89
+ packages dir FIRST (deployment-installed wins), then bare import
90
+ resolution (paths, `file://` URLs, dev checkouts, image-bundled
91
+ packages). Install failure/timeout (120s) fails the boot naming the
92
+ specifier. Deployments declare extensions in `settings.json` and
93
+ restart — no image rebuild. Compose mounts the config dir on the data
94
+ volume (`SIGRUN_CONFIG_DIR=/data/config`); the chart defaults
95
+ `SIGRUN_CONFIG_DIR=/data/config` onto the same PVC as the database.
96
+ - `server.webui` settings section (the webui channel surface):
97
+ `enabled` (default `true`; `false` is a positively API-only deploy —
98
+ nothing mounts even when a bundle is present) and `bundle` (the
99
+ selector — a value matching `^[a-z][a-z0-9_-]*$` is a contributed-bundle
100
+ NAME, a path-shaped value is a directory). `SIGRUN_WEBUI` is the strict
101
+ env gate (`true`/`false`, anything else fails loud);
102
+ `SIGRUN_WEBUI_BUNDLE` remains the env selector form.
103
+ `PATCH {server:{webui:{…}}}` sub-merges per key (a partial update no
104
+ longer drops a previously set `bundle`); a defaulted first boot
105
+ persists no webui keys at all.
106
+ - Extension-contributed webui bundles: a factory result may carry
107
+ `webuiBundles: [{name, dir}]` (contract in `docs/extending.md`) — `dir`
108
+ resolves against the extension entry file's directory (the bundle lives
109
+ in the extension's package, never the server cwd), the server owns the
110
+ `index.html` check at serve time (a missing index is a boot error naming
111
+ the extension), and name collisions are last-registered-wins with a
112
+ warn. Selection by name via `server.webui.bundle`; the selected
113
+ bundle mounts exactly like the built-in one and
114
+ `capabilities.channels` reports its name (`"webui"` for the built-in
115
+ default).
116
+ - `/v1/meta` gains a `collisions` field (`webui` + `providers`):
117
+ boot-merge collision records surfaced for operator visibility — the
118
+ provider collision sink was retained since the provider plan but never
119
+ readable until now.
120
+
121
+ ### Deprecated
122
+ - `server.webuiBundle` — the legacy flat key reads as a deprecated alias
123
+ for `server.webui.bundle` for one release (accepted with a deprecation
124
+ warn). Selector precedence: `SIGRUN_WEBUI_BUNDLE` >
125
+ `server.webui.bundle` > legacy `server.webuiBundle` > the built-in
126
+ default. Bootstrap never writes the legacy key; migrate to
127
+ `server.webui.bundle`.
128
+
129
+ ### Changed
130
+ - `charts/sigrun` is rewritten as a bjw-s common library (app-template
131
+ 5.2.1) wrapper: the hand-written Deployment/Service/PVC/CronJob/
132
+ ServiceMonitor templates are replaced by
133
+ `templates/common.yaml` (loader init + generate) over a 5.2.1-schema
134
+ values.yaml (`controllers`/`service`/`persistence`/`serviceMonitor`).
135
+ The PrometheusRule stays a small hand template (the library has no
136
+ PrometheusRule class), gated independently on
137
+ `monitoring.prometheusRule.enabled`. The backup CronJob and the
138
+ ServiceMonitor are now opt-in defaults (public portable shape); the
139
+ Deployment's Recreate strategy, /healthz + /readyz probes, sigrun-env
140
+ envFrom secret, and the RWO sigrun-data PVC at /data are unchanged
141
+ contracts. test/manifests.test.ts asserts against the new render.
142
+ - **BREAKING** (packaging): `@sigrun/tui` is a spawned package, not an
143
+ in-process import — `sigrun run`/`attach` spawn the `sigrun-tui` bin
144
+ (`tui/dist/launch.js`) as a child process; the agent-dies-with-the-TUI
145
+ lifecycle is preserved by the parent watching the child's exit. The
146
+ tui declares its own runtime deps (`@earendil-works/pi-tui` plus the
147
+ new `@sigrun/shared` leaf package carrying the theme tokens and shared
148
+ primitives) and core lists it as an optional dependency: `serve` needs
149
+ no tui, and a missing tui degrades `run`/`attach` with an actionable
150
+ "install @sigrun/tui" message instead of a module-not-found crash.
151
+ - The CLI is buildable and installable: `npm run build` compiles
152
+ `@sigrun/shared` + `src` → `dist` (sourcemaps off; the `sigrun` bin is
153
+ `dist/cli.js` under plain node — the tsx shebang is gone); `tsx` moves
154
+ to devDependencies (dev `start`/`tui` scripts keep it); `prepublishOnly`
155
+ builds core + webui. Deploy entries run the built form — the Dockerfile
156
+ build stage gains `npm run build` with `CMD ["node", "dist/index.js"]`,
157
+ the chart's container command and backup CronJob are
158
+ `node dist/index.js` / `node /app/dist/backup/run-backup.js`, and
159
+ docker-compose runs `node dist/index.js` (no tsx in any deploy path).
160
+ - The default webui bundle anchors to the package root instead of the
161
+ process cwd — an installed `sigrun serve` finds the bundle it ships
162
+ from any working directory; explicit path selectors keep cwd-relative
163
+ semantics, and an absent default stays the supported API-only deploy.
164
+
165
+ ### Removed
166
+ - **BREAKING**: the extension-loader `.ts`-entry fallback. Extension
167
+ sources (`git:` and path checkouts) must ship a built `dist/index.js` —
168
+ a `.ts` entry no longer loads — it resolves only to quarantine at load
169
+ with a clear "build the package and ship its built entry
170
+ (dist/index.js)" error instead of riding the dev tree's tsx loader
171
+ (whose behavior under plain node depends on the host's
172
+ type-stripping flags). npm packages were never affected.
173
+
174
+ ### Changed (packaging)
175
+ - Published as `@sigrun/sigrun` (CLI command stays `sigrun`) with
176
+ `@sigrun/shared` and `@sigrun/tui` as workspace-published companions —
177
+ exact intra-family pins (`0.1.0`), `publishConfig` access/provenance,
178
+ `repository.directory` for the workspace packages, and a manifest
179
+ hygiene suite (`test/package-manifest.test.ts`) pinning the published
180
+ shape. `webui` stays a private build input (its bundle ships inside
181
+ core's tarball as `webui/dist`).
182
+ - The npm tarball is the runnable package only: `files` narrows to
183
+ `dist`, `webui/dist`, and the docs files — deploy assets (`scripts/`,
184
+ `docker/`, `charts/`, `Dockerfile`) live in the GitHub repo.
185
+ - The three built-in extensions (`codemode`, MCP, tool search) ship as
186
+ core dependencies under their published names `@sigrun/ext-codemode`,
187
+ `@sigrun/ext-mcp`, `@sigrun/ext-tool-search` — the working tree keeps
188
+ `file:` dev links until the family publishes (Task 8).
189
+ - The extension contract surface is `@sigrun/sigrun/extension`
190
+ (types-only subpath; every import, doc, and the consumer fixture
191
+ re-keyed).
192
+ - The deprecated `createMemory` named-export loader bridge is DELETED
193
+ (release-0.1): packages must export the factory as default —
194
+ `@sigrun/memory-markdown` 0.1.0 does. The named `extension`
195
+ export bridge remains deprecated (loads with one warning).
196
+
197
+ ### Added
198
+ - Durable personal assistant on pi-durable 1.2.0: the Harness (durable sessions,
199
+ tasks, compaction, settings store), the §5 server + webui, the skills/search
200
+ tool surface, extension loader (quarantine-on-failure), deploy manifests
201
+ (base + homelab overlay), and the pi-parity feature set (approvals, memory
202
+ surface, settings panel, command surface).
203
+ - pi-durable upgraded 1.0.2 → 1.2.0: ToolExecutionResult `output` rename across
204
+ core, registry-driven settings roster, `modelTools` two-layer filtering.
package/CONTEXT.md ADDED
@@ -0,0 +1,163 @@
1
+ # Context: why sigrun exists
2
+
3
+ > Companion to the sigrun specs in `docs/superpowers/specs/` (the *what*):
4
+ > `2026-10-04-sigrun-core.md` (core, zero external dependencies),
5
+ > `2026-10-04-sigrun-hermes-replacement.md` (parity extensions + cutover),
6
+ > `2026-10-04-sigrun-improvements.md` (post-hermes capabilities). The original
7
+ > `2026-10-02-sigrun.md` is superseded and retained as decision history (the numbered
8
+ > decision record, App B 1–23, lives there; its deployment §6 was carried into the core
9
+ > spec, so the three active specs stand alone).
10
+ > This document is the *why* — what the assistant is for, what it replaces, and
11
+ > the constraints that shaped it. Written 2026-10-02.
12
+
13
+ ---
14
+
15
+ ## 1. What sigrun replaces, and why
16
+
17
+ The user has run `hermes-agent` (in-cluster, via the `hermes-pantheon`
18
+ chart) plus `hermes-webui` as a personal assistant. The assistant is genuinely
19
+ useful — the memory system especially — but the software has become a bad fit:
20
+
21
+ - **It is heavy.** The local config is ~800 lines. After the 2026-09-25
22
+ gateway-only cleanup, the overwhelming majority of it is dead: bedrock
23
+ discovery, docker sandbox variants, personalities, Mixture-of-Agents presets,
24
+ per-provider fallback plumbing, image-generation providers. The features that
25
+ actually get used are a handful of tools, cron, memory, and the webui.
26
+ - **The webui runs a second agent loop.** hermes-webui imports the hermes code
27
+ and re-implements the agent loop independently of the primary CLI agent. Two
28
+ loops, two state paths, one codebase that has to keep them in sync.
29
+ - **The workspace went away.** When hermes ran locally in the same WSL instance
30
+ as pi and opencode, everything shared a filesystem, and code written by pi was
31
+ immediately visible to hermes. Moving hermes into the cluster bought
32
+ always-on availability and lost that adjacency.
33
+ - **It is not a good coding agent.** Attempts to use it as one produced poor
34
+ results. Coding stays in pi.
35
+
36
+ Sigrun keeps the parts that earn their place (memory, scheduled jobs,
37
+ agentic maintenance tools, web research, the webui as the primary surface)
38
+ and discards the rest by construction.
39
+
40
+ ---
41
+
42
+ ## 2. What the assistant is actually for
43
+
44
+ Stated by the user, in their words:
45
+
46
+ - **Research.** The most common use. "Go find out about X." Which naturally
47
+ escalates:
48
+ - **Research that turns into work.** If finding out about X reveals a tool to
49
+ build or software to update, the assistant should open a ticket in Forgejo and
50
+ hand the actual work to pi — not attempt the coding itself.
51
+ - **Steering coding work from away from the desk.** Not doing the work, but
52
+ being able to answer a pi session's questions or prompt it to continue while
53
+ on a phone or laptop. Heavy lifting stays in pi inside herdr.
54
+ - **Routine maintenance.** Existing cron jobs performing household and
55
+ self-hosted-service maintenance. The user wants *more* of this and keeps
56
+ not getting to it — calendar access, household context, and similar
57
+ assistant-ish chores.
58
+ - **Ambient awareness.** Ingesting data sources such as Discord logs so the user
59
+ can catch up on what they missed, gauge community impressions of new models,
60
+ and track events. Read-only to start.
61
+ - **Memory.** Honcho is described as "incredibly valuable." Parity with the
62
+ current honcho behavior is a v1 requirement, not an enhancement.
63
+ - **Household multi-user, eventually.** "An agent that can assist my entire
64
+ household has clear value," with guardrails around data sharing. Authelia is
65
+ already the IdP, so this is an SP problem, not an identity problem.
66
+
67
+ ---
68
+
69
+ ## 3. Constraints that shaped the design
70
+
71
+ ### 3.1 The workspace problem
72
+
73
+ The single most concrete complaint. A shared workspace between agents was
74
+ valuable and the cluster migration broke it. But running a whole-home assistant
75
+ from a personal workstation is not a good answer either — the workstation sleeps,
76
+ and the assistant should not.
77
+
78
+ Resolution: the assistant's *core* lives in-cluster (always on, durable), and the
79
+ *workspace* is resolved rather than fixed. Day one uses a static workspace
80
+ configuration; the swap to dynamic resolution is a wrapper change, not a
81
+ rewrite. The interaction surfaces (webui now, TUI and
82
+ audio later) attach to the in-cluster core from anywhere over the tailnet.
83
+
84
+ Precedent the user liked and lost: `opencode serve` on the workstation with
85
+ `opencode attach` from any of three machines, working over the tailnet. That
86
+ serve/attach model is exactly what a durable harness gives back — one long-lived
87
+ process owning state, thin clients attaching.
88
+
89
+ ### 3.2 pi-durable is the substrate
90
+
91
+ Chosen because it is the only option that makes the "second agent loop" problem
92
+ structurally impossible: the loop lives in the harness, and every surface
93
+ (webui, TUI, cron trigger, future channels) is a client submitting to and
94
+ watching conversations. It also brings crash survival and idempotent
95
+ submissions (requestId dedup — exactly-once-across-crash semantics are
96
+ pending M1 verification), which the current stack lacks.
97
+
98
+ Known constraints accepted at choice time:
99
+
100
+ - Experimental; the API changes between releases (`1.0.2` at spec time;
101
+ pinned exactly, with a captured-schema drift fixture and an upgrade drill
102
+ in the core spec).
103
+ - One process owns a storage file at a time; no cross-process locking. Matches
104
+ the single-harness design anyway.
105
+
106
+ Resolved since the choice (2026-10-04 probes against the pinned package):
107
+ image input **works** (base64 inline in submissions — verified live), and the
108
+ async-approval mechanism works across crash+restart (`beforeTool` + durable
109
+ memo — verified live). These were open questions at choice time; they are now
110
+ verified facts recorded in the core spec's Appendix C.
111
+
112
+ ### 3.3 Keep pi's philosophy
113
+
114
+ The user's stated preference: **minimal core, well-defined interfaces for
115
+ extensibility, and an ecosystem.** Their pi install is the proof it works — 19
116
+ packages, each doing one thing, composed into a workflow.
117
+
118
+ So sigrun is: a small harness, a webui, and a set of extensions that are
119
+ individually replaceable. Not a platform.
120
+
121
+ ### 3.4 The webui is the primary surface
122
+
123
+ Called out twice in the design conversation. The plan is to take hermes-webui's
124
+ UX shamelessly (three-panel layout, composer footer, tool cards, context ring)
125
+ while replacing everything beneath it with thin client calls to the harness API
126
+ — which is why the stack decision in the spec is *port the frontend, gated on a
127
+ 60% reuse measurement*, with a rebuild as the documented fallback.
128
+
129
+ ### 3.5 Cross-agent tools belong in the fabric, not the agent
130
+
131
+ Hard-won: the assistant needs a work ledger that spans repositories and
132
+ outlives any particular agent. If the kanban is a hermes plugin, moving to a
133
+ different assistant means re-doing the integration. So cards live in the
134
+ fabric's card system (skuld), and sigrun is just a client — as pi will be, as
135
+ anything else will be.
136
+
137
+ ---
138
+
139
+ ## 4. What sigrun deliberately does not do
140
+
141
+ - **Coding.** pi + herdr own that. Sigrun creates the ticket and the card.
142
+ - **Provider management.** Bifrost already routes models with virtual keys,
143
+ budgets, and failover chains. Sigrun points at one VK.
144
+ - **Multi-user UI in v1.** The `owner` field exists; the auth flow does not.
145
+ - **Write-side Discord, voice, generalized object memory.** Deferred, each with
146
+ a documented seam so it can be added without redesign.
147
+
148
+ ---
149
+
150
+ ## 5. Names
151
+
152
+ **sigrun** — a Norse valkyrie; a messenger/attendant figure. Chosen over:
153
+
154
+ - **iris** — reads as the lesser-known female counterpart to hermes; the user
155
+ disliked the implicit gender-flip construction.
156
+ - **argus** — the watcher; also the guy hermes slew, which is an odd name for
157
+ hermes's replacement.
158
+ - Various scribe/messenger deities (thoth, seshat, ogma, muninn) — all already
159
+ taken in the agent/AI space, several by direct competitors.
160
+ - Norse fits: the bifrost gateway already lives in that mythology.
161
+
162
+ **skuld** — held in reserve for the work-item side of the fabric ("that which
163
+ shall become").
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Michael MacLeod
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.