@sigrun/sigrun 0.0.0-stage → 0.1.1

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 +214 -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 +89 -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,214 @@
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.1] - 2026-10-22
11
+ ### Fixed
12
+ - `@sigrun/sigrun@0.1.0` shipped a correct tarball but a dev-shape packument
13
+ (the `file:../sigrun-ext-*` specifiers reached the registry's manifest):
14
+ clean installs resolved no built-in extensions and quarantined them at
15
+ boot. The publish-deps restore now runs in `postpublish` only — npm 11
16
+ runs pack → postpack → packument submission, so the old `postpack`
17
+ restore raced the manifest write. Version bumped so the registry gets a
18
+ clean packument; 0.1.0's tarball was byte-correct and remains installable
19
+ by direct tarball URL.
20
+ ## [0.1.0] - 2026-10-21
21
+ ### Added (server)
22
+ - Conversation list fields: name, last-activity, parent (fork lineage),
23
+ archived and pinned on the list payload — the per-conversation meta
24
+ N+1 is gone; fork trees sort by newest activity anywhere in the tree.
25
+ - Automatic conversation naming: a one-shot naming call driven by the
26
+ `namingModel` setting (a model id, or `false` to disable; defaults to
27
+ the server default model with thinking off). Forks of named
28
+ conversations inherit `"<name> (fork)"`.
29
+
30
+ ### Added (tui)
31
+ - Fullscreen alt-screen UI with mouse support: per-keymap themes,
32
+ status bar, and a turn-grouped transcript with foldable turns.
33
+ - Action layer with configurable keymaps (standard / vim / emacs):
34
+ turn-aware search, prompt-jump and picker actions replace the
35
+ alt-screen built-ins; vim mode has real insert / normal / command
36
+ modes with `v` opening the prompt in vim.
37
+ - Key reference overlay (`?` in standard/emacs, `g?` in vim).
38
+
39
+ ### Added (webui)
40
+ - Theme system: palette / accent / mode, applied across the rail,
41
+ header and right-panel shell; visual design adapted from hermes-webui
42
+ by nesquena and contributors (credited in THIRD_PARTY_NOTICES).
43
+ - Sidebar: named, grouped, searchable conversation list with pin and
44
+ archive.
45
+ - Transcript: turn-grouped rendering with an activity line per turn
46
+ ("Thinking · 2 tools"), markdown everywhere, filterable tables
47
+ (filter bar above > 6 data rows), copy buttons on code blocks, a
48
+ transcript outline, and a scroll fade.
49
+ - Composer model and thinking pickers.
50
+
51
+ - Thinking blocks: `thinking` content blocks render as collapsible
52
+ `<details>` before each assistant message's text — expanded + pulsing
53
+ while the generation streams (`pi.live.generation.message` partials
54
+ render as a provisional entry), collapsed at rest, hidden entirely by
55
+ the new Interface setting.
56
+ - A "working…" indicator (three pulsing dots) driven by `steer.busy`,
57
+ reading "compacting…" while a compaction task is live, plus a persistent
58
+ compaction-failure alert from `pi.live.compactionFailure`.
59
+ - Submit chords: Ctrl+Enter / Cmd+Enter submit; the Interface setting's
60
+ "enter sends the prompt" adds plain-Enter submit (Shift+Enter stays a
61
+ newline).
62
+ - Settings sections: the panel gains a left nav (General / Tools /
63
+ Interface / Advanced). Interface holds the new client-only prefs
64
+ (`enterToSend`, `showThinking`) — localStorage-backed (`sigrun.prefs`),
65
+ applied live, never sent to the server.
66
+ - Workspace drawer: below 1000px the workspace panel opens as a right-side
67
+ overlay drawer (top-bar toggle, backdrop click / in-panel ✕ to close)
68
+ instead of being hidden.
69
+
70
+ ### Changed (webui)
71
+ - Tool-call-only assistant messages render nothing — the empty bubble
72
+ above a tool card is gone.
73
+ - The Compact button is removed (compaction is automatic server-side;
74
+ `/compact` remains a slash command). Composer controls sit in one row
75
+ (Attach · usage ring · Send) and the textarea matches their height.
76
+ - The settings gear is larger; the top bar wraps badges instead of
77
+ overflowing horizontally at narrow widths.
78
+
79
+ ### Fixed (webui)
80
+ - The Tools section's checkboxes collapsed into a vertical column with the
81
+ explanatory note clipped off the right edge (a `flex-direction` leak from
82
+ the `.settings-field` base), forcing a horizontal scrollbar.
83
+ - `pi.live` doc narrowing gained the `generation`/`compactions`/
84
+ `compactionFailure` shapes the new consumers read.
85
+ - Unified `extensions` list (install-and-load): one settings.json array
86
+ covers npm specifiers, `file:`/path checkouts, and git sources
87
+ (`git:host/path[@ref]` cloned into `<config-dir>/git/` with fetch/reconcile
88
+ + entry discovery: sigrun manifest > pi-compat manifest > dist/index.js >
89
+ index.ts). `{enabled: false}` = present-but-not-loaded. The separate
90
+ `packages` list is gone; `SIGRUN_EXTENSIONS` accepts the same grammar
91
+ per CSV chunk (JSON-object entries included).
92
+ ### Added
93
+ - pi-style extension packages: the settings file's top-level `packages`
94
+ array (file-only — no `SIGRUN_PACKAGES`) declares npm specifiers boot
95
+ installs into `<config-dir>/packages/` (a real npm root: synthetic
96
+ private `package.json` + `node_modules/`, pi's `~/.pi/agent/npm` shape),
97
+ pruning undeclared entries, with a no-subprocess fast path when the dir
98
+ already matches. The loader resolves each `extensions` name against the
99
+ packages dir FIRST (deployment-installed wins), then bare import
100
+ resolution (paths, `file://` URLs, dev checkouts, image-bundled
101
+ packages). Install failure/timeout (120s) fails the boot naming the
102
+ specifier. Deployments declare extensions in `settings.json` and
103
+ restart — no image rebuild. Compose mounts the config dir on the data
104
+ volume (`SIGRUN_CONFIG_DIR=/data/config`); the chart defaults
105
+ `SIGRUN_CONFIG_DIR=/data/config` onto the same PVC as the database.
106
+ - `server.webui` settings section (the webui channel surface):
107
+ `enabled` (default `true`; `false` is a positively API-only deploy —
108
+ nothing mounts even when a bundle is present) and `bundle` (the
109
+ selector — a value matching `^[a-z][a-z0-9_-]*$` is a contributed-bundle
110
+ NAME, a path-shaped value is a directory). `SIGRUN_WEBUI` is the strict
111
+ env gate (`true`/`false`, anything else fails loud);
112
+ `SIGRUN_WEBUI_BUNDLE` remains the env selector form.
113
+ `PATCH {server:{webui:{…}}}` sub-merges per key (a partial update no
114
+ longer drops a previously set `bundle`); a defaulted first boot
115
+ persists no webui keys at all.
116
+ - Extension-contributed webui bundles: a factory result may carry
117
+ `webuiBundles: [{name, dir}]` (contract in `docs/extending.md`) — `dir`
118
+ resolves against the extension entry file's directory (the bundle lives
119
+ in the extension's package, never the server cwd), the server owns the
120
+ `index.html` check at serve time (a missing index is a boot error naming
121
+ the extension), and name collisions are last-registered-wins with a
122
+ warn. Selection by name via `server.webui.bundle`; the selected
123
+ bundle mounts exactly like the built-in one and
124
+ `capabilities.channels` reports its name (`"webui"` for the built-in
125
+ default).
126
+ - `/v1/meta` gains a `collisions` field (`webui` + `providers`):
127
+ boot-merge collision records surfaced for operator visibility — the
128
+ provider collision sink was retained since the provider plan but never
129
+ readable until now.
130
+
131
+ ### Deprecated
132
+ - `server.webuiBundle` — the legacy flat key reads as a deprecated alias
133
+ for `server.webui.bundle` for one release (accepted with a deprecation
134
+ warn). Selector precedence: `SIGRUN_WEBUI_BUNDLE` >
135
+ `server.webui.bundle` > legacy `server.webuiBundle` > the built-in
136
+ default. Bootstrap never writes the legacy key; migrate to
137
+ `server.webui.bundle`.
138
+
139
+ ### Changed
140
+ - `charts/sigrun` is rewritten as a bjw-s common library (app-template
141
+ 5.2.1) wrapper: the hand-written Deployment/Service/PVC/CronJob/
142
+ ServiceMonitor templates are replaced by
143
+ `templates/common.yaml` (loader init + generate) over a 5.2.1-schema
144
+ values.yaml (`controllers`/`service`/`persistence`/`serviceMonitor`).
145
+ The PrometheusRule stays a small hand template (the library has no
146
+ PrometheusRule class), gated independently on
147
+ `monitoring.prometheusRule.enabled`. The backup CronJob and the
148
+ ServiceMonitor are now opt-in defaults (public portable shape); the
149
+ Deployment's Recreate strategy, /healthz + /readyz probes, sigrun-env
150
+ envFrom secret, and the RWO sigrun-data PVC at /data are unchanged
151
+ contracts. test/manifests.test.ts asserts against the new render.
152
+ - **BREAKING** (packaging): `@sigrun/tui` is a spawned package, not an
153
+ in-process import — `sigrun run`/`attach` spawn the `sigrun-tui` bin
154
+ (`tui/dist/launch.js`) as a child process; the agent-dies-with-the-TUI
155
+ lifecycle is preserved by the parent watching the child's exit. The
156
+ tui declares its own runtime deps (`@earendil-works/pi-tui` plus the
157
+ new `@sigrun/shared` leaf package carrying the theme tokens and shared
158
+ primitives) and core lists it as an optional dependency: `serve` needs
159
+ no tui, and a missing tui degrades `run`/`attach` with an actionable
160
+ "install @sigrun/tui" message instead of a module-not-found crash.
161
+ - The CLI is buildable and installable: `npm run build` compiles
162
+ `@sigrun/shared` + `src` → `dist` (sourcemaps off; the `sigrun` bin is
163
+ `dist/cli.js` under plain node — the tsx shebang is gone); `tsx` moves
164
+ to devDependencies (dev `start`/`tui` scripts keep it); `prepublishOnly`
165
+ builds core + webui. Deploy entries run the built form — the Dockerfile
166
+ build stage gains `npm run build` with `CMD ["node", "dist/index.js"]`,
167
+ the chart's container command and backup CronJob are
168
+ `node dist/index.js` / `node /app/dist/backup/run-backup.js`, and
169
+ docker-compose runs `node dist/index.js` (no tsx in any deploy path).
170
+ - The default webui bundle anchors to the package root instead of the
171
+ process cwd — an installed `sigrun serve` finds the bundle it ships
172
+ from any working directory; explicit path selectors keep cwd-relative
173
+ semantics, and an absent default stays the supported API-only deploy.
174
+
175
+ ### Removed
176
+ - **BREAKING**: the extension-loader `.ts`-entry fallback. Extension
177
+ sources (`git:` and path checkouts) must ship a built `dist/index.js` —
178
+ a `.ts` entry no longer loads — it resolves only to quarantine at load
179
+ with a clear "build the package and ship its built entry
180
+ (dist/index.js)" error instead of riding the dev tree's tsx loader
181
+ (whose behavior under plain node depends on the host's
182
+ type-stripping flags). npm packages were never affected.
183
+
184
+ ### Changed (packaging)
185
+ - Published as `@sigrun/sigrun` (CLI command stays `sigrun`) with
186
+ `@sigrun/shared` and `@sigrun/tui` as workspace-published companions —
187
+ exact intra-family pins (`0.1.0`), `publishConfig` access/provenance,
188
+ `repository.directory` for the workspace packages, and a manifest
189
+ hygiene suite (`test/package-manifest.test.ts`) pinning the published
190
+ shape. `webui` stays a private build input (its bundle ships inside
191
+ core's tarball as `webui/dist`).
192
+ - The npm tarball is the runnable package only: `files` narrows to
193
+ `dist`, `webui/dist`, and the docs files — deploy assets (`scripts/`,
194
+ `docker/`, `charts/`, `Dockerfile`) live in the GitHub repo.
195
+ - The three built-in extensions (`codemode`, MCP, tool search) ship as
196
+ core dependencies under their published names `@sigrun/ext-codemode`,
197
+ `@sigrun/ext-mcp`, `@sigrun/ext-tool-search` — the working tree keeps
198
+ `file:` dev links until the family publishes (Task 8).
199
+ - The extension contract surface is `@sigrun/sigrun/extension`
200
+ (types-only subpath; every import, doc, and the consumer fixture
201
+ re-keyed).
202
+ - The deprecated `createMemory` named-export loader bridge is DELETED
203
+ (release-0.1): packages must export the factory as default —
204
+ `@sigrun/memory-markdown` 0.1.0 does. The named `extension`
205
+ export bridge remains deprecated (loads with one warning).
206
+
207
+ ### Added
208
+ - Durable personal assistant on pi-durable 1.2.0: the Harness (durable sessions,
209
+ tasks, compaction, settings store), the §5 server + webui, the skills/search
210
+ tool surface, extension loader (quarantine-on-failure), deploy manifests
211
+ (base + homelab overlay), and the pi-parity feature set (approvals, memory
212
+ surface, settings panel, command surface).
213
+ - pi-durable upgraded 1.0.2 → 1.2.0: ToolExecutionResult `output` rename across
214
+ 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.