71 lines
5.0 KiB
Markdown
71 lines
5.0 KiB
Markdown
# Brief: several Mosaic Stack instances on one host
|
|
|
|
Sage, 2026-10-20, for Mos's order mos-0974 (MVP, DECISIONS Q176-Q178, Vikunja #414). Gitea #1688. T1 item 1. Owner
|
|
Darkwing, reviewer Filbert, gate owner Sage. Base: refactor at the brief commit. This row blocks both MVP
|
|
cases: Case 1 (Jason's software factory) and Case 2 (Melanie's creative writing hub) run as two instances
|
|
on one homelab host, beside the current mosaic-stack test instance.
|
|
|
|
Design first. The first deliverable is `agents/darkwing/work/queue-190/DESIGN.md`. Filbert reviews it
|
|
before any code, as Q175 did. Then the build follows the design, with tests and mutants.
|
|
|
|
## The goal
|
|
|
|
Two or more instances run side by side on dragon-lin. Each one has its own config file, data root (store,
|
|
broker.sock, host.lock, state, runs, sessions, workspaces), businesses, bus unit, Console unit and port,
|
|
tester port, Discord unit, Claude session env file, stack-active pointer and activation log. No instance's
|
|
commands, units or tools address another instance's state by default or by mistake. On one uid this is
|
|
addressing only, not a security boundary: a same-uid process can still read another instance's files.
|
|
Isolation against that is row 190b (#1693, mos-0986), one Linux user per instance. The current instance keeps working unchanged: its
|
|
config path, data root, unit names and ports stay as they are, and no re-pin is needed for it.
|
|
|
|
## Known single-instance points (GAP-MAP.md, measured at 9ae8c73ac)
|
|
|
|
The design starts with a full inventory. Grep every script and package, not only these:
|
|
|
|
- `packages/cli/systemd/mosaic-bus.service.in`: `mosaic-bus@<business>` sets no `MOSAIC_CONFIG` and reads the
|
|
fixed `EnvironmentFile=-%h/.config/mosaic-dev/secrets/claude-session.env`.
|
|
- `packages/webui/systemd/mosaic-webui.service.in` and `scripts/webui-service.sh`: one `mosaic-webui.service`.
|
|
- `packages/discord/systemd/[email protected]` and `scripts/discord-service.sh`.
|
|
- `scripts/stack-copy.sh:8` hardcodes `BUSINESS=mosaic-stack`, and `:95` reads `mosaic-webui.service`.
|
|
- `scripts/stack-release.sh`: unit names, the Console port and the tester port default, `COPIES` (:28), the
|
|
pointer under `$DATA/state` (:1474), and `rehearse`.
|
|
- `scripts/mosaic-config.mjs`, `scripts/bootstrap.sh`, `scripts/reset.sh`, `scripts/land-work.sh`,
|
|
`packages/webui/src/cli.mjs`, `packages/business/src/{business,vars}.mjs`, and
|
|
`packages/conversation/src/guard.mjs` each name the default config path or data root.
|
|
|
|
## What the design must settle
|
|
|
|
1. Instance identity. How a name maps to its config file and how every tool picks the instance (an
|
|
`--instance NAME` flag, `MOSAIC_CONFIG`, or both), and what happens with neither (the current default,
|
|
unchanged). Name rules, and refusal of a name that collides.
|
|
2. Config canon. AGENTS.md invariant 2 says `~/.config/mosaic-dev/config.json` is the sole system config,
|
|
created only by `scripts/bootstrap.sh`. Several instances mean several config files. The design proposes
|
|
the exact wording change and how bootstrap creates an instance config without overwriting one. Mos rules
|
|
on the canon change before the build.
|
|
3. Unit names and templates. The bus, Console and Discord units per instance, how `MOSAIC_CONFIG` and the
|
|
Claude env file reach each unit, and how the current unit names stay valid for the default instance.
|
|
4. Ports. Each instance's Console and tester ports, with a refusal when two instances claim the same port.
|
|
5. Stack copies and the pointer. Whether copies are shared between instances (read-only trees, so sharing
|
|
may be fine) and how the pointer, activation log, backups and `flags_drift` stay per instance.
|
|
`stack-release.sh` and `stack-copy.sh` take the instance.
|
|
6. Secrets. The per-instance Claude session env file and the secrets slot root, resolved from the instance's
|
|
config dir (the Q175 design resolves its slot the same way: `<configDir>/secrets/mosaic-stack/<slot>`).
|
|
7. Isolation proof. What the tests show: two instances started side by side on stand-in units and scratch
|
|
roots, each reads only its own config and data root, a command aimed at one never touches the other, and
|
|
the default instance's paths and unit names are byte-identical to today.
|
|
|
|
## Boundaries
|
|
|
|
- No test touches `~/.mosaic-dev`, `~/.config/mosaic-dev`, the live units or a slot file. Use the stand-in
|
|
systemctl, units and scratch roots that `packages/cli/tests/stack-release.test.mjs` already builds.
|
|
- Standing up a real second instance on dragon-lin is a later window under Q173, with a backup first and a
|
|
STATE report after. Exposing a new Console through the tunnel or Traefik changes who can reach it from
|
|
outside, so it waits for Jason. SSO (Q175, #412) comes first for any instance a second user can reach.
|
|
- Merge-chaining (Q177): rows that need instances (human users, kill switch, lifecycle) may build on this
|
|
row's candidate. This row keeps its own review and gate.
|
|
|
|
## Gate
|
|
|
|
Filbert approves DESIGN.md, then the manifest. The cli suite and every `scripts/test-*.sh` are green on
|
|
Sage's gate, and the design's mutants are killed.
|