gosalyn: Case 2 design r9, the O4 model path (Q186): pi on zai glm-5.3 for both, hub key step 2d, Chet's Codex login to #428, C2-20 Hermes name count; C2-13 brief follows
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Case 2 design: the creative writing hub (r8)
|
||||
# Case 2 design: the creative writing hub (r9)
|
||||
|
||||
Gosalyn, 2026-10-20 (from `date -u`). Track T2 in jason-master-restart `projects/mosaic-mvp/PLAN.md`,
|
||||
Vikunja #416, DECISIONS Q176-Q178. The requirement is Jason's text in TARGET.md (addendum 2026-10-20).
|
||||
@@ -8,6 +8,25 @@ Base: `refactor` at 9ae8c73ac. r1 cited 5d019d876. `git diff --stat 5d019d876 9a
|
||||
adapters roles scripts` is empty (Mos in mos-0980, Webby in webby-0001), so every `file:line` holds at
|
||||
9ae8c73ac. Paths are relative to the repository root.
|
||||
|
||||
## Changes from r8
|
||||
|
||||
Jason's Q7 answer, "Q7: yes" (DECISIONS Q186, mos-1090, sage-1469). O4 is the model path.
|
||||
|
||||
- Model path (9). For 10-27, Bean and Chet both run harness pi with provider `zai` on `glm-5.3`. Pi
|
||||
reads the key from `ZAI_API_KEY`, and row A puts that name in `ENV_ALLOW`
|
||||
(`packages/seat/src/session.mjs:83-88`). Chet moves to his ChatGPT/Codex login after 10-27, in row B
|
||||
(Vikunja #428), which I design. Running a pi role still waits on #383.
|
||||
- 10 step 2. 2b no longer leaves "which model accounts" open. New 2d: Jason places the hub's own key on
|
||||
the existing Z.ai account, with a spend cap if the account offers one. Whose account it is stays his
|
||||
input. `melanie`'s sudo can read the key until #423 step 5.
|
||||
- Two consequences in C2-13. A pi launch has no credential check, so the precheck checks the key file
|
||||
by name and mode and never prints the value. The claude marker prompt now runs only when some
|
||||
creative instance's harness is claude-code, because with the model path above the host may have no
|
||||
Claude login. The unit template's `EnvironmentFile=` line is one of the fixed lines `case2-unit.sh`
|
||||
checks.
|
||||
- C2-20 (9.1). The dry run also counts lines naming a Hermes tool or channel, counts only (gosalyn-0030,
|
||||
mos-1087).
|
||||
|
||||
## Changes from r7
|
||||
|
||||
Webby's review (webby-0025, CHANGES, notes at agents/webby/work/case2-r7/REVIEW.md, 19bb3ae36).
|
||||
@@ -591,8 +610,9 @@ two copies come with that:
|
||||
as the prompt when the file doesn't exist (`:21`, `:30`, no warning) or can't be read (`:24-27`). So
|
||||
the adapter checks `[ -r ]` on the file first, which covers both, and refuses otherwise. Claude Code 2.1.304's `--help` names `--system-prompt-file`. I read the help
|
||||
but didn't run it, and the repo doesn't pin the claude version. C2-08's adapter tests check that argv
|
||||
holds the path and not a marker from the prompt. C2-13 runs one marker prompt through the host's claude
|
||||
with `--system-prompt-file` and checks that it replaces the default prompt rather than adding to it. If the
|
||||
holds the path and not a marker from the prompt. When some creative instance's harness is claude-code,
|
||||
C2-13 runs one marker prompt through the host's claude with `--system-prompt-file` and checks that it
|
||||
replaces the default prompt rather than adding to it. With the r9 model path, Bean and Chet run pi. If the
|
||||
host's claude lacks the flag, the argv copy is a residual for Jason, stated with that version.
|
||||
|
||||
Modes, from code. The writer creates the business file's candidate and `changes.jsonl` with mode 0600
|
||||
@@ -957,7 +977,7 @@ Chains follow Q177 merge-chaining. S marks a slice row.
|
||||
| C2-10b | S | Console chat: cited-item renderer through `renderItems`, the status line | C2-06, C2-09a, C2-03a | Haiku high | webui tests for items, scope badges, notices, "changed since" and the status line |
|
||||
| C2-12 | S | The setup sheet for Melanie (7.1, including N2 and N4, and what changes for Bean and Chet in 4) and the survey run sheet for `<host>` | C2-01 | Luna | doc only, reviewed against the survey's real flags |
|
||||
| C2-20 | S | Persona import (9.1): a script that reads only the persona definitions of the two Hermes profiles, confirms profile to name, and writes each persona file (4) with its `persona.name` and `persona.sha256` for the business file. Prints names, byte counts and sha256 only. A `--dry-run` mode, run before Jason's go, prints only counts of files, lines and lines starting `# ` or `## ` | C2-08 | Opus (Gosalyn), run under Jason's go | fixture Hermes profile trees: the right fields are taken, memory and session files are never opened (a read trace on the fixture), a profile with no persona field refuses, a persona that would fail C2-08's fence check refuses, output holds no persona text, each written file is 0600 and its digest matches, `--dry-run` writes nothing and prints the right counts for a fixture with two heading lines and no marker string from it |
|
||||
| C2-13 | S | Install script and precheck for `<host>` as `<user>`: bootstrap, release activate, business file with the mapping, `bean` and `chet` with their persona vars and files, any specialists she picks, her human id, token slot path, and `scripts/case2-unit.sh` with the template `packages/cli/systemd/mosaic-stack.service.in`, which root runs from a root-owned checkout in 10 step 2c. The install writes no unit. Jason or his delegate runs it (10) | C2-04, C2-03a, C2-20 | Opus (Gosalyn), Jason's go | precheck: config validates, `<user>` has no sudo and `id -G` prints exactly one entry, `bus.tester` is not on, the business file, `.history`, `changes.jsonl` and persona files have the modes in 4 and each persona digest matches, the run root is 0700, one marker prompt run through the host's claude with `--system-prompt-file` shows it replaces the default prompt (its version printed), free memory printed, `library.sync` fetches her repo read-only, `library.status` lists R-problems, no Discord binding exists. `case2-unit.sh` refuses an installed unit that differs from its render (one edited to `User=root` is the test), a symlink at the unit path, and a render whose `User=`, `Group=`, `ExecStart=` or hardening lines are off their fixed values. Tested against a scratch data root and a local bare repo |
|
||||
| C2-13 | S | Install script and precheck for `<host>` as `<user>`: bootstrap, release activate, business file with the mapping, `bean` and `chet` with their persona vars and files, any specialists she picks, her human id, token slot path, and `scripts/case2-unit.sh` with the template `packages/cli/systemd/mosaic-stack.service.in`, which root runs from a root-owned checkout in 10 step 2c. The install writes no unit. Jason or his delegate runs it (10) | C2-04, C2-03a, C2-20 | Opus (Gosalyn), Jason's go | precheck: config validates, `<user>` has no sudo and `id -G` prints exactly one entry, `bus.tester` is not on, the business file, `.history`, `changes.jsonl` and persona files have the modes in 4 and each persona digest matches, the run root is 0700, when some creative instance's harness is claude-code, one marker prompt run through the host's claude with `--system-prompt-file` shows it replaces the default prompt (its version printed), the key file in 10 step 2d exists, is owned by `<user>` at 0600 and sets a nonempty `ZAI_API_KEY` when an instance's provider is `zai` (name only, never the value), free memory printed, `library.sync` fetches her repo read-only, `library.status` lists R-problems, no Discord binding exists. `case2-unit.sh` refuses an installed unit that differs from its render (one edited to `User=root` is the test), a symlink at the unit path, and a render whose `User=`, `Group=`, `ExecStart=`, `EnvironmentFile=` or hardening lines are off their fixed values. Tested against a scratch data root and a local bare repo |
|
||||
| C2-14 | S | End-to-end acceptance on a scratch data root and a bare repo in her layout: sync, ask a creative agent in its thread, a reply whose cites verify, a playground cite as canon refused, a force-push held as diverged, the Console shows the reply as items | slice rows | Opus | one script, which the reviewer also runs |
|
||||
| C2-02 | | Bus writes: `writeLibraryFile`, `commitFile` refactor, r1's S0 rule on the working tree | C2-04 | Sol (Rocko) | writer tests, `packages/project/tests` unchanged and green |
|
||||
| C2-03b | | Push path, race retry, `unpushed`, `library-remote-invalid` on writes | C2-02, C2-03a | Opus | push tests against a bare repo |
|
||||
@@ -997,6 +1017,18 @@ mirror and runners live under `<user>`. It needs outbound HTTPS to git.mosaicsta
|
||||
providers. It needs nothing from her user, because her writing reaches it through the Gitea remote she
|
||||
already uses.
|
||||
|
||||
Model path (Q186, mos-1090). For 10-27, `bean` and `chet` both run harness pi with provider `zai` on
|
||||
`glm-5.3`, through one key for the hub (10 step 2d). Pi's provider comes from the instance's session
|
||||
(`packages/plugins/harness/pi/index.mjs:57`), and pi-ai reads a zai key from `ZAI_API_KEY`
|
||||
(`env-api-keys.js:89`, with `glm-5.3` in `data/zai.json`). `ENV_ALLOW` doesn't pass that name today
|
||||
(`packages/seat/src/session.mjs:83-88`), so row A adds it. A pi launch has no credential check
|
||||
(`pi/index.mjs:42`, `packages/cli/src/launcher.mjs:299`), so a missing key shows up only at the first
|
||||
turn. The C2-13 precheck catches that before the start. The creative roles' web search goes through the
|
||||
broker's search source, not the harness, so pi having no web tool of its own (`pi/index.mjs:44-45`)
|
||||
changes nothing here (5.2). After 10-27 Chet moves to his own ChatGPT/Codex login. That needs a
|
||||
per-instance pi agent dir, which is row B (Vikunja #428), and it starts after a live check that two
|
||||
clients on one login don't revoke each other's refresh tokens. Running any pi role waits on #383.
|
||||
|
||||
Memory. From mos-1000, her two Hermes services use about 1.8 GB together, and each Mosaic agent session
|
||||
measured 300 to 390 MB on dragon-lin. I estimated at least 2 GB more than the 3.8 GiB her guest saw, and
|
||||
4 GB more with specialists running at the same time. ops-01 is setting VM 1012 to 16 GiB fixed with 6
|
||||
@@ -1032,7 +1064,11 @@ The in-VM tightening is Vikunja #423. Only its step 1, the `localadmin` account,
|
||||
until prune, and in the harness argv if the host's claude lacks `--system-prompt-file` (4).
|
||||
- Dry run first (N2, mos-1051 item 3). Before Jason's go to import, the row runs a dry pass that reads the
|
||||
same two persona definitions and prints counts only: files, lines, and lines starting `# ` or `## `.
|
||||
No text and no line numbers. If any count of heading lines is nonzero, the fence rule in 4 would refuse
|
||||
No text and no line numbers. It also counts lines that name a Hermes tool or channel, from a fixed
|
||||
list in the script: the tool names in the hermes-agent checkout at df5700ebe, read from its code and
|
||||
not her profiles, plus `Hermes` and `Discord`. That prints one count per persona file, never the line,
|
||||
its number or the word. A nonzero count changes nothing in the import. It tells Jason a persona refers
|
||||
to things Bean and Chet won't have in Mosaic. If any count of heading lines is nonzero, the fence rule in 4 would refuse
|
||||
a real persona, so the rule changes, in a reviewed C2-08 follow-up, before the import runs. The text is
|
||||
never rewritten to fit the rule unless Melanie says so through Jason.
|
||||
- Hermes keeps running. The row changes nothing in the Hermes checkout, its profiles, its services or its
|
||||
@@ -1079,8 +1115,8 @@ What it adds is one bot account with read access to that one repo.
|
||||
groups and no keys. Create `/srv/mosaic` at 0700, owned by `mosaic`.
|
||||
- 2b: the install as `<user>`, by him or his delegate, run as `sudo -u mosaic -H` from `localadmin`.
|
||||
`mosaic` has no keys and no login shell, and nobody adds a key to make 2b work. `scripts/bootstrap.sh`, release package and
|
||||
activate, the pinned harness, and which model accounts its agents use. Model use is spend, so the
|
||||
accounts are his call.
|
||||
activate, and the pinned harness. The model path is set (9, Q186). Chet's ChatGPT/Codex login is
|
||||
not part of 10-27. It is row B (#428).
|
||||
- 2c, ops-01 via `localadmin`: root makes a checkout of the reviewed commit outside `/srv/mosaic`,
|
||||
owned by root, and checks that its HEAD is the commit Jason's go names. From that checkout it runs
|
||||
`scripts/case2-unit.sh`, which renders `mosaic-stack.service` from the template with the user and
|
||||
@@ -1089,6 +1125,14 @@ What it adds is one bot account with read access to that one repo.
|
||||
`systemctl link`, and it refuses a symlink at the unit path. On a re-install it refuses an
|
||||
installed unit that differs from the render. Root runs nothing from `/srv/mosaic` and reads no
|
||||
unit that `mosaic` wrote. Then it enables the unit. The unit starts only at step 9.
|
||||
- 2d, Jason: the hub's own key on the existing Z.ai account, with a spend cap if the account offers
|
||||
one. Model use is spend, so the key and the cap are his. Whose Z.ai account it is hasn't been said,
|
||||
and that is his input. The key goes in `/srv/mosaic/.config/mosaic-dev/secrets/claude-session.env`
|
||||
as `ZAI_API_KEY=`, owned by `mosaic`, mode 0600, the file the unit's `EnvironmentFile=` line loads
|
||||
(the same line as `packages/cli/systemd/mosaic-bus.service.in:24`). The name says claude, but it is
|
||||
the one file decision 119 and `packages/cli/README.md` document, so I kept it. He places it, or
|
||||
says who may, per the Q173 secrets rule. Agents never print it. Until #423 step 5, `melanie`'s
|
||||
sudo can read it, and so can her Hermes processes (9).
|
||||
3. A new Gitea bot account for the hub, with read access to the books repo only. Not bean-brain, and not
|
||||
her other three repos. Her repo's access list is hers, so adding the bot means asking her or acting as
|
||||
admin, which is his call.
|
||||
|
||||
@@ -748,7 +748,8 @@ precheck take `--profile factory|library`, default `library`:
|
||||
`case2-unit.sh` is the 2c step. Root runs it from a root-owned checkout of the reviewed commit outside
|
||||
`/srv/mosaic`, never from the release, because `mosaic` can write the release. It does the following:
|
||||
- It renders the unit from the checkout's template, with the user, the home and the copy id as inputs.
|
||||
- It refuses unless `User=`, `Group=`, `ExecStart=` and the hardening lines match fixed values. The
|
||||
- It refuses unless `User=`, `Group=`, `ExecStart=`, `EnvironmentFile=` and the hardening lines match
|
||||
fixed values. `EnvironmentFile=` is the line in `packages/cli/systemd/mosaic-bus.service.in:24`. The
|
||||
copy id is the one part of `ExecStart=` that varies, so a re-pin to a new copy can re-render the
|
||||
unit (row 195). It must be exactly 40 lowercase hex characters naming a copy that holds `scripts/mosaic`,
|
||||
directly under `<home>/.local/share/mosaic-stack/copies`. That is the rule `copy_root` uses
|
||||
@@ -774,19 +775,29 @@ The precheck refuses unless all of these hold:
|
||||
- `bwrap --unshare-all --ro-bind / / true` exits 0 as `<user>`. Without it no session starts. Row 195
|
||||
found no bwrap on .53, and `kernel.apparmor_restrict_unprivileged_userns=1`, and .54 may be the same.
|
||||
On a refusal, the precheck prints the sysctl's value and whether `bwrap` is on PATH.
|
||||
- One marker prompt run through the host's claude with `--system-prompt-file` shows that it replaces
|
||||
the default prompt. The claude version is printed.
|
||||
- When some creative instance's harness is claude-code, one marker prompt run through the host's claude
|
||||
with `--system-prompt-file` shows that it replaces the default prompt. The claude version is printed.
|
||||
With design r9's model path, Bean and Chet run pi, so this check is skipped unless she adds a
|
||||
claude-code specialist.
|
||||
- When an instance's provider is `zai`, `<configDir>/secrets/claude-session.env` exists, is a regular
|
||||
file owned by `<user>` at 0600, and sets a nonempty `ZAI_API_KEY` (design 10 step 2d). A pi launch
|
||||
has no credential check, so without this the first turn is where a missing key shows. The precheck
|
||||
prints the name and never the value.
|
||||
- `library.sync` fetches her repo read-only, and `library.status` lists R-problems.
|
||||
- No Discord binding exists.
|
||||
|
||||
It also prints free memory and verifies HOME is `/srv/mosaic`.
|
||||
|
||||
Tests run against a scratch data root and a local bare repo. Each precheck refusal has a case. The
|
||||
claude check runs against a fake claude that appends rather than replaces, and that case refuses.
|
||||
claude check runs against a fake claude that appends rather than replaces, and that case refuses. With
|
||||
no claude-code instance the claude check doesn't run, and a test shows a missing claude passes. The key
|
||||
file refuses when missing, at 0644, a symlink, or with `ZAI_API_KEY=` empty. A search of the test
|
||||
output for the fixture key value finds nothing.
|
||||
`case2-unit.sh` runs against a scratch unit directory. These cases refuse:
|
||||
- an installed unit edited to `User=root`
|
||||
- an edited `ExecStart=`
|
||||
- a template with a hardening line removed
|
||||
- a template with the `EnvironmentFile=` line removed or pointing elsewhere
|
||||
- a symlink at the unit path
|
||||
- a template with `ExecStartPre=+/srv/mosaic/x`
|
||||
- a template with `ExecStartPre=-+/srv/mosaic/x`
|
||||
@@ -882,7 +893,7 @@ its first turn, as `packages/cli/README.md:439-444` says.
|
||||
|
||||
### Out of scope
|
||||
|
||||
Placing a key anywhere. The hub's own key on the Z.ai account is design 10 step 2, and it is Jason's.
|
||||
Placing a key anywhere. The hub's own key on the Z.ai account is design 10 step 2d, and it is Jason's.
|
||||
Any pi launch or live check: running a pi role waits on #383. Chet's Codex login (row B, #428). A
|
||||
credential check for pi launches.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user