Adds the harness plug-in kind (interface 1). packages/plugins/harness/pi
and claude-code hold what core branched on: the adapter, thinking levels,
preflight, version probe, sandbox mounts, builtins line, typed tool names,
gate timeout, bundle files, adapter env, turn end and session-files path.
Core reaches a module only through the loader.
A session's route is the instance's harness, model and thinking vars, or
the three fallback. vars; a missing one refuses no-route, and the system
file's execution keys are never read for a session. The launcher checks
the primary route, then the fallback: harness-off, harness-refused,
thinking-unsupported, then preflight. A failed preflight falls back when
a fallback is set, and any refusal of the fallback names the primary's
failure too. Account checks run
only when the route's module counts an account. The manifest records
route, routeReason and harnessVersion, replacing piVersion and
claudeVersion. pi gets --thinking, Claude Code --effort, both from
MOSAIC_THINKING.
The business file refuses a partial fallback. routes and routes.set are
human-only bus verbs outside ORGANIZATION_KEYS; checkRoutes is shared by
routes.set, instances.set and limits.set and checks only changed routes.
The chief of staff changes an instance's model, and the assistant's whole
vars (Q169), through limits.set, so its route write runs the same checks.
A model outside launch.models refuses unknown-model, primary or fallback,
and routes.set passes that code through.
A new run binds only on a switched-on harness module name and records
its transcript path, which the usage reader uses. Settings gains a
Routing table with six selects per instance and loses the Role models
fieldset; it posts changed rows to /api/routes. webui/src/bus.mjs is
unchanged.
Until Jason's `mosaic plugins set` adds "harness": ["claude-code"], a new
launch refuses harness-off.
The business file can name the account claude-code launches use,
`launch.account` = {name, credential}. `name` is an identifier and
`credential` names one login set's environment variables, never a value.
`launch.limits.tokens.daily.<account>` = {limit, since, reset, timeZone}
sets a daily quota for that account. A daily key that isn't the account's
name refuses the business read.
The new plug-in limit-check/daily-quota (interface 2, pure) starts a day at
the first instant at or after `reset` on that local date in `timeZone`. Across
DST that makes a 23- or 25-hour day, and a reset in a skipped hour starts at
the gap's end. It counts the account's known records of all four kinds since
the later of the day start and `since`, and counts unknown turns apart.
The launcher refuses account-credential-missing, account-credential-ambiguous
and account-is-credential (an account name equal to a session credential's
value). Messages name variables, never values. The account rides mayLaunch,
bindLaunch, the usage records, mustStop and the launch record. A pi launch
has no account, records NULL, and no daily quota covers it. `mosaic limits`
and the Console's Settings show one fixed line when a daily row shows:
"Daily quotas count only this stack's own use of the account, not its use
anywhere else."
Bus schema 3h to 3i: 3h reserved usage_records.account as
CHECK (account IS NULL). The new step 3h-3i.sql rebuilds the table in one
transaction, keeping every row's seq and the sqlite_sequence value, and
recreates the three append-only triggers. All of sqlite_master equals 3h's
apart from the account line. A 3h engine refuses a 3i store.
packages/bus/tests/account-migration.test.mjs covers all three, with a
step that fails partway and leaves 3h intact. 3i goes live only through
`stack-release.sh activate ... --migrate` with Jason present (P19 371); the
activate path takes the pre-migrate backup, and the way back is restoring
it (agents/dewey/work/queue-126/MIGRATION.md).
Mos's go mos-0835, six conditions: (1) one transaction, account-migration
test 2 and mutant D29; (2) sqlite_master against 3h, test 1 and mutant D28;
(3) account is never a credential, the launcher's account-is-credential
refusal (launch-account.test.mjs) and the business name pattern
(token-limit-settings.test.mjs); (4) MIGRATION.md, accepted by Mos in
mos-0837; (5) the packet's DESIGN.md "no schema change" line corrected;
(6) the public/ digest below.
The public/ change in bus.js (the daily line under the token-limit table)
carries Mos's decision 123 go mos-0833 on the +/- digest 03e6d9da...ba78,
unchanged at landing.
Owner Dewey, brief docs/plans/2026-10-14_prd-1.2-build.md, "Daily quota for
the credential the stack uses today". Review round 2 rebases the round 4
build onto 1df04f52f (row 167). Reviewer: Filbert approve 29068 on round 1
(manifest d18314f7...8e65); Filbert approve 29080 on
round 2 (manifest f332db76...6fa6).
Seat run on round 2: touched 158/0, singles 1388/0 with 1 esbuild skip,
test-land-work.sh 86/0, 30/30 mutants killed.
Sage gate on 54319f552: GATE_PASSED, 2474+422/0, all 15 packages, the queue
suite and 10 script selftests.
Nothing live.
`mosaic business instances BUSINESS` reads the role instances, and
`mosaic business instance add|set` writes one add or change through the
broker's new human-only `instances` and `instances.set` verbs. The writer is
packages/business/src/instance-settings.mjs. It takes the caller's revision,
validates the next document, refuses a definition that declares credentials
(organization-credentials-out-of-scope), keeps protected instances as they
are, logs the human as the actor, and says when the running bus needs a
restart. Neither command restarts the bus.
The writer refuses the instance ids human and tester with invalid-request,
because the broker refuses a business whose roles use either name when the
bus starts.
The Console's Settings view shows the instances and, under --send only,
posts to POST /api/instances with the exact Origin and same-origin Fetch
Metadata. A refusal keeps the draft. An answer without the view's shape is
outcome-unknown (503). The page's public/ diff carries the decision 123 go
in mos-0832.
Neither verb is in ORGANIZATION_KEYS, so no agent tool reaches them.
Owner Darkwing, brief in row 165 (#1662). Round 3 rebases round 2 onto
4f45cadc0 (row 156). The public/ +/- digest is 939ecd28...9444, unchanged
at landing. Reviewers on candidate manifest e30b54da...f580: Dewey
approve 29052, Filbert approve 29053. Seat run on 4f45cadc0: 1436/0
singles, 37/37 mutants killed. Sage gate on e8b09735a: GATE_PASSED 25/25,
packages 2282/0, queue node 156/0, script selftests 422/0, 23:59:13Z to
00:05:35Z. Rebased onto 50a57e454 over two SESSIONS-only commits.
Nothing live.
Until now a landing ran only when the chief of staff or merge-gate
followed row 149's manual steps. The host now does it.
Broker. landHolders(business) lists the approved merge decisions each
instance holds, sharing the #held generator with landHeld.
landRelease(record) releases a run's claim with by='land-relaunch'.
Delivered and unread messages keep the run, and a run that hasn't had
its first message.receive answers {released:false, landing:true}
(#received, round 2), so a landing turn in progress is never cut. A
run that never reaches its first receive, a hung landing turn or a
broker restart, keeps the release closed, and the decision falls back
to row 149's path.
usage.begin accepts a decision id that landHolders lists for the run.
The bus process answers both ops from their own launchOp lines and
refuses any op it doesn't name.
Launcher. start() reads landHolders once for a non-thread instance and
takes land_work and the session's landing list from that one answer.
landPass() runs after threadPass() on each tick.
Runner. One turn per landing entry before the message loop, with a
usage bracket on the decision id.
Docs. A "Landing runs" section in the cli README and docs/TOOLS.md.
roles/merge-gate.md, cto.md and chief-of-staff.md say the host starts
the run, and row 149's steps are the fallback.
Owner Dewey, brief docs/plans/2026-10-18_landing-run-launch.md, design
DESIGN.md in the packet (sage-0808). Round 2 answers Filbert's F1-F3
(29033, rulings sage-0942). Reviewer on candidate manifest
72a5c1b6...b700: Filbert approve 29039. Seat run 4: 290/290 singles,
36/36 mutants killed. Sage gate on a618528b2 (candidate 524bfcc80): GATE_PASSED 25/25. Package tests 2258 plus queue 156, script selftests 422, 23:30:07Z to 23:38:04Z. Run 1 stopped at pkg-webui on board-held.test.mjs:163, the P19 366 timeout, 220/1. Run 2 resumed at pkg-webui on the same tree: webui 221/0 and every scripts/test-*.sh green.
Nothing live.
Jason's Q169: only the chief of staff removes the assistant; the chief
and the human configure it and its seat name.
Configure. A new organization key, assistants, replaces the vars,
tracker or definition of an instance whose definition is already the
assistant. holder and credentials are refused, and the whole document
still goes through validateBusinessDocument. set() refuses
organization-definition-refused if any other instance's definition
changed. THREAD_DEFINITION and END_PROTECTED move to
packages/business/src/vocabulary.mjs, so the broker and
launch-settings.mjs read one list. The human writes it with
mosaic limits set --file or the Console Settings view's Assistant
section; the chief writes it with change_organization. Both carry the
file's revision.
Seat name. The chief gets a typed set_name tool (name.set,
instance.name). The Console gets POST /api/name on the settings
boundary, through human-cli.
Remove. role.end and role.revoke of a threaded instance revoke every
thread of that instance whose latest claim is a claim, and report
threads: N. The raise and the check both record a missing holder run as
null. A new human-only verb, assistant.stop, revokes the human's own
threads of an assistant instance; the Console calls it from POST
/api/assistant-stop. The bundle, the end_run description and
roles/chief-of-staff.md now say the chief ends and configures the
assistant. No schema step.
Owner Darkwing, brief docs/plans/2026-10-16_q169-assistant-config.md.
Reviewers: Dewey (security) r1 approve 29012, r2 29014, r3 29018; Filbert r1 29010,
r2 29015, r3 29017, on candidate manifest 96cae28e...9016. Round 2 is
confirm-only after rows 162 and 125 moved the base under docs/TOOLS.md
and the cli README. Round 3 bumps row 164's webui/src/bus.mjs byte
baseline in packages/bus/tests/channel-proof.test.mjs for the eight
STATUS entries; Sage's gate on r2 failed only there. Mos's decision 123 go for the public/bus.js diff
(mos-0816) covers 9f9ce31b, unchanged here. Sage gate on 197722caa:
GATE_PASSED 25/25 (node 2370, selftests 422) 21:11:38Z, a rerun on the same tree after a first run stopped at pkg-webui on a board-held.test.mjs timeout that passes singly.
Nothing live. Follow-up brief in the packet: the names read rethrow, one
shared settings snapshot, null tests for the two new routes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
New scripts/stack-release.sh with four verbs. adopt records the running
copy, the unit flags and the store schema in state/stack-active.json; it
stops nothing. activate ID BUSINESS [--pm] [--migrate] stops the units,
checks the stopped store, backs it up, migrates when the target's schema
differs, installs and starts the target, then gates on both units active,
a live bus host whose pid is the bus unit's MainPID with boot ok, Console
/healthz, stack-copy.sh check and one launched journal line. A failed
gate rolls back inside the same run and keeps the attempted store as
bus.post-attempt-<stamp>. rollback [--restore ACT [--events N]] goes back
to the log's previous copy and counts the events written after the
backup. status prints the pointer, the log tail and the copy check.
--plan prints what a run would do and writes nothing; it reads the store
schema from the store the running bus holds, or from a stopped store.
Exit codes: refusal 3, gate failure with rollback 1, rollback failed 2,
usage 4. Nothing is pruned.
stack-copy.sh gets a reachable function split from copy_commit and a
guard so its helpers can be sourced. TOOLS.md "Pinned stack update" and
the cli README pinned-stack paragraph describe the verbs.
Owner Darkwing, brief docs/plans/2026-10-18_stack-release.md (D1).
Reviewer Filbert: r1 approve (comment 28997) on 091693c5, r2 confirm-only
approve (29004) on candidate manifest c213a801...bd15c after row 125
moved the base under TOOLS.md and the cli README. Sage gate on 23622980f:
25 of 25 steps rc=0 on c96a95320 (15 packages + 10 scripts), node pass 2353 fail 0, selftests 422 passed 0 failed, 2026-10-18T20:32:13Z to 20:38:55Z, network sage-r162_default removed, 0 containers.
Nothing live. The 8e7ea89a1 window (repin-8e7ea89a1.md) runs these verbs
on Mos's go with Jason present.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Adds token limits under launch.limits.tokens (instances, providers, keys,
models.P.M). Core (packages/bus/src/limits.mjs) reads the organization
file and the per-turn usage records row 124 writes, then asks every
switched-on limit-check plug-in; the first refusal wins. A limit no
switched-on check reports reads "not enforced". The limit-check kind is
interface 2 (mayLaunch, mustStop, report); a v1 check is refused at load.
The shipped token-limit check is pure and counts known end records only;
unknown turns add nothing and are shown as their own count.
The launcher refuses limit-reached through the host's mayLaunch op, or
limit-check-failed naming the check. The broker asks mustStop after a
usage end and stops the run at its next receive or state. Settings stamps
since on a new or changed limit and runs reset; launch.mjs and
business.mjs validate the shape. Readers: mosaic limits and mosaic limits
reset, the bus limits view, the Console /api/bus/limits route and the
Settings token table with Reset. Key limits stay "not enforced" until
row 126 names accounts on records.
Owner Dewey, design under lead decision 150.
Reviewer Filbert: r1 changes (comment 28965), r2 approve (28981), r3
approve (28996) on candidate manifest 8b71c405...fe56 after the rebase
onto row 164 (37 of 38 paths with identical +/- lines, TOOLS.md:621
bracket). Decision 123 go on the bus.js hunk from Mos (mos-0814). Sage
gate on b6827d19e: 25 steps, all rc 0 (15 packages, 10 script suites), 2295 node tests and 422 script selftests, 0 failed, 20:03:25Z to 20:08:08Z, network sage-r125_default removed.
Live stays as pinned. Not part of the 8e7ea89a1 window.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Adds plugin kind `channel` (interfaceVersion 1, dispatch(request, {call}))
with cli and webui modules. Project and thread surfaces and thread
talk/follow in the CLI and the Console chat go through the selected
channel. An empty or absent channel selection is off: the CLI exits 3 and
the Console answers 503, each naming `mosaic plugins` and `mosaic plugins
set` with the business selector. Management plugins and plugins.set stay
on the core transport. The loader gains a synchronous snapshot(kind)
getter; loaded(), modules() and last-good handling are unchanged. No lock
is held across dispatch. serve.mjs, public/ and the bus are untouched.
Owner Rocko. Reviewer Dewey: r1 changes (comment 28980, B1: the recovery
sentence was never asserted), r2 approve (comment 28984) on candidate
manifest ae2fcfda...1fc8, the B1 assert killing mutant D1. Design accepted
by Mos (mos-0768, mos-0773). Fixture rewrite at project.test.mjs:47 acked
by Mos (mos-0789) on Dewey's line-by-line check: lines 48-51 identical,
one added assert. Sage gate on e5b10d275: 25 steps green, 2081 package tests, 156 queue node tests, 422 script selftests, 0 failed.
Live stays as pinned. The re-pin that takes this live puts `mosaic
plugins set` in Jason's window right after activate (mos-0768).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Rocko's round 2 candidate e09313aba4d155a1c5af7bfb227ec397e96c0d57444782cd0b48593102bcc684
(38 paths, base 23533625d), approved by Dewey in #1618 comment 28923 (queue rev 1757).
Packet: agents/rocko/work/queue-124/r2/.
- Schema 3g to 3h: packages/bus/src/migrations/3g-3h.sql adds an append-only
usage_records table; nothing earlier changes. usage_records is in timedTables.
- The transcript usage-source module reads token counts from Pi and Claude
Code session transcripts and follows no symlink.
- `mosaic usage` in the CLI and a read-only usage section in the Console's
Settings (one GET route; 400 on a query string).
Decision 123 go: Mos, mos-0737. Activation (3g to 3h) is a migrating run
with Jason present, in Mos's combined re-pin; landing changes nothing live.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 128 round 1, Researcher's candidate (agents/researcher/work/queue-128/,
row128.patch, manifest 9eed6a78, 8 paths, base 0f3eb25ea). Filbert
approved round 1 (comment 28895).
`mosaic project create` and `project list` call project.create and
project.list; `init` and `check` keep their arguments and refusals.
`mosaic threads`, `thread create`, `thread open` and `thread read` cover
the thread verbs, and `mosaic talk --thread` sends thread.send as a
REQUEST and prints only the reply to the sent message. `mosaic follow
--thread` is the same loop without the send. A thread reference is its
id, an id prefix of 8 or more characters, or <project>/<name>; unknown,
short and ambiguous references refuse with exit 2 before any send. Every
verb refuses inside an agent run. There is no default thread, so a plain
`talk assistant` still meets thread-required-use-thread-send.
Acceptance 314 step 1 now creates the project and the assistant thread.
New: packages/cli/src/thread.mjs, packages/cli/tests/thread-cli.test.mjs.
Sage's landing gate ran on 77b1a6e8a plus the candidate: 25 steps, all
rc 0 (15 packages, 10 script suites), 14:44:02Z to 14:48:42Z, network
sage-r128_default removed. The commit sits on 7de8b7270, which adds one
docs/SESSIONS.md line that no test reads.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 141 round 1, Darkwing's candidate (agents/darkwing/work/queue-141/,
build.patch bb036c6d, manifest d474b330, 26 paths, base 18aee8fa1),
rebased without change by Sage onto 7e40fb83b as round 2
(agents/sage/work/queue-141-r2/, build.patch 72b890d9, manifest
cae29087). Row 148 moved two of the paths, packages/bus/README.md and
packages/bus/src/broker.mjs; the interdiff touches only index and @@
lines. Filbert approved round 1 (comment 28841).
Schema 3f->3g adds instance_names, an append-only log whose latest row
per instance is its current name. message.send resolves a to that is
not an instance key or a role through the names table, and records
to_name. The new bus writer name.set and read names back the CLI verbs
mosaic name INSTANCE NAME (human-only) and mosaic names [--json].
`instance.name` is routed under REQ-MSG-2 (1.5). It joins ACTIONS and
ROUTED in the vocabulary and the broker, and roles/chief-of-staff.json
grants it within-role, as row 139's brief asks of whichever of 139 and
141 lands second. The chief has no tool for it until row 155, so the
chief's untypedActions and bundle untyped list are ["instance.name"]
(harness tools.test.mjs:43, bundle.test.mjs:94).
Follow-ups: Vikunja P19 tasks for TOOLS.md and acceptance 314 step 10
(Filbert, doc-only) and for refusing a new key or definition equal to a
current name. Row 155's brief carries the return of untyped to [].
Sage's landing gate ran on 7e40fb83b plus the candidate: 25 steps,
all rc 0 (15 packages, 10 script suites), 22:30:48Z to 22:35:15Z,
network sage-r141_default removed. The commit sits on 2a85b41da,
which adds one docs/SESSIONS.md line that no test reads.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 137 round 4, Darkwing's candidate (agents/darkwing/work/queue-137/r4/,
build.patch 0cabe175, manifest 548ee477, 31 paths, base 63c82f1c4).
Filbert approved round 4 (comment 28809) and Dewey approved it (28816)
after round 3 changes (28801, 28805). Darkwing's round 4 ran 9/9 mutant
kills, bus 317, seat 150, land-work 86.
Round 5 is a rebase only (agents/sage/work/queue-137-r5/, build.patch
d6cbaaa8, manifest f73598fe). Row 150 changed docs/TOOLS.md, broker.mjs
and cli/README.md under it. The round 4 patch applied unchanged onto
435d1c616, and with index and @@ lines removed the two patches are
byte-identical. Filbert checked the interdiff (comment 28818).
A landing moves refs/heads/main in <dataRoot>/working/<business>/
<project>.git, never the project root or canonical refactor. The seed now
fetches the root as refs/heads/root and fast-forwards main only when it
is an ancestor, so a landed main survives the next push. Only a
cross-role merge decision lands. Its squash names the real channel:
"via the CLI" for the human, and "as its arbiter, via the broker" for an
arbiter's decision.resolve. Every other class refuses not-authorized
before the human check.
This carries row 139's two items. REQ-LAND-1: a gated merge decision
never lands. REQ-DEC-2: the host land op accepts an arbiter-resolved
merge. land-work's read.mjs stays human-only, and land-work.sh still
accepts only a human CLI resolution.
Sage's landing gate ran on 435d1c616 plus the candidate: 25 steps,
all rc 0 (15 packages, 10 script suites), 20:51:00Z to 20:55:34Z,
network sage-r137_default removed. Cherry-picked onto 5d98fb194, which
added only a docs/SESSIONS.md line.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 150 round 2, Darkwing's candidate (agents/darkwing/work/queue-150/r2/,
manifest 7556dda0, 7 paths), a rebase-only round onto 63c82f1c4 after
row 139 changed broker.mjs. Filbert approved round 1 (comment 28800) and
the rebase (comment 28806): only broker.mjs's index line and hunk offset
moved. Darkwing's r2 round ran 6 files, ROUND_PASSED.
`mosaic inbox --read <id>...` and `--read-all` mark the human's unread
messages read. Each argument is tried; refusals print their code and the
command exits 2. The Console's send section now names `mosaic inbox` and
`mosaic inbox --read`. broker.mjs changes a comment only.
The public/ diff is sha256 096d922c, unchanged from round 1 and covered
by Mos's decision 123 go.
Sage's landing gate ran on 4ebef2284 plus the candidate: 25 steps,
all rc 0 (15 packages, 10 script suites), 20:41:55Z to 20:46:24Z,
network sage-r150g_default removed. Cherry-picked onto 1ad48035c, which
added only a docs/SESSIONS.md line.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 152 round 1, Dewey's candidate on 56639c99b. Filbert approved
(comment 28741). The bus marks a waiting message launchable or not;
when the target isn't in the launch block, launch.by is still told,
with a notice saying the launch would be refused, and talk prints that
launch.by can't launch the role. Sage's landing gate ran on 5f57d85e5
plus the candidate: 25 steps, all rc 0.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 151 round 1, Dewey's candidate on 686fc1cb6. Filbert approved
(comment 28726). Test-only. Sage's landing gate ran on this commit
plus row 153.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Round 2 candidate 7a585aa9606863a0d44a26094b585160914e3d8fd5f13436b56470cd69e6d867
(Rocko, packet fafee2f22), approved by Filbert in comment 28707.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Dewey's row 146 work (agents/dewey/work/queue-146/build.patch, packet
08e327bf5), applied unchanged on 625c21f41. Candidate manifest
616f953f...9607 on dda7e31b0; no commit since touches its 10 paths.
Dewey's gate passed and 17 of 17 mutants were killed. Filbert approved
round 1 in comment 28641.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Jason-approved merge, rebased: git diff f4d7b91a9..0e7d1d8b8 from
work/vikunja-19-309, stacked on 305. Business reviewer verdict dfd44af2
approve on 0e7d1d8b8; Jason resolved merge decision 12a20e47 via the CLI.
No conflict. packages/plugins/README.md, which refactor also changed,
merged with the source commit's +/- lines; the other four paths are the
source blobs. Filbert reviews the rebased diff.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Jason-approved merge, rebased: git diff 813671596..f4d7b91a9 from
work/vikunja-19-305, stacked on 295. Business reviewer verdict 57d7f0b7
approve on f4d7b91a9; Jason resolved merge decision 0eebf83f via the CLI.
Conflict resolution only. packages/bus/src/broker.mjs conflicted with
row 123 (89fd2d6fe): both sides extend the limits branch of request().
Kept row 123's organization.set role path and ORGANIZATION_KEYS, and
added 305's plugins and plugins.set to the verb list and its keys lines.
plugins and plugins.set take the human-only path as in 305: role is true
only for organization.set, the actor is the human, and the verb reaches
the organization writer unchanged. organization.set is unchanged.
packages/plugins/tests/searxng.test.mjs conflicted with 307: both add a
test at the end of the file. Kept 307's AbortSignal test, then 305's
hasModule test. Three other paths that refactor also changed merged
without conflict, with the source commit's +/- lines; the other six
paths are the source blobs. Filbert reviews the rebased diff.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Jason-approved merge, landed unchanged: git diff 07c12b51b..abda248a8
from work/vikunja-19-302. Business reviewer verdict 4998de97 approve on that
commit; Jason resolved merge decision 29ff6589 via the CLI. No commit on
refactor since 07c12b51b touches these paths.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Darkwing's row 121 round 2 (agents/darkwing/work/queue-121/r2, base
20d2b5788, manifest 710d5086...e67e9b, 30 files), applied unchanged on
d7ebaa9a5; no commit since the base touches any of the 30 paths. Dewey
asked for changes on round 1 in comment 28591 (F1 to F6) and approved
round 2 in 28615. Landing gate on d7ebaa9a5 plus the candidate: all 24
suites passed, 0 failed.
F6 and Dewey's three round 2 notes are follow-ups (sage-0369, P19 task
311). One of them corrects the packet: BUILD.md says the decision-route
setup's projects key is needed, and Dewey's probe showed project.create
reads it only with repo, so the key is dead setup.
The live bus stays at 3b until Mos's schema window migrates it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
packages/plugins holds the kind registry and the loader for in-repo
plug-in modules (REQ-PLUG-1). The first two kinds are usage-source and
limit-check (REQ-LIMIT-4). The business file's plugins key turns modules
on per kind, through plugin-settings.mjs and step 5's write path
(REQ-ROLE-3). A refused load is logged and keeps the kind's old modules.
Any filesystem error other than ENOENT or ENOTDIR refuses as unreadable.
The organization writer validates the bytes it writes as well as the
document. stack-copy ships packages/plugins. Nothing is wired into a
host process yet.
Candidate 466c835f7dce79d20c7ab74c197a52b70e7fdeb0efae0456222dc6d0a633f219,
Dewey packet 80797a539 (round 2), base 0bdd573ff. Filbert approved
round 2 in 28568 and Darkwing in 28570. Landing gate at f7d249634: 24 suites green, 0 failed.
14 package suites passed 1586 tests (plugins 21, business 92,
bus 171, cli 195, webui 112). The 10 script suites passed. Follow-up:
P19 task 293, coded writer refusals.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
launch.max becomes launch.models plus launch.limits (total, providers,
exact provider/model). The launcher re-reads limits on every attempt.
Settings and `mosaic limits` write through one locked, journaled
organization writer. `mosaic limits migrate` is print-only.
Candidate 00b84e311475f97ced0d9a9599fba23a28442971ed15d8d489d9422d84a8812e,
Rocko packet 4b6e50636, Filbert round 2 approve (comment 28542).
Landing gate at 0c56cc2d4: 23 suites green. Decision 123 go from Mos.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
roles/assistant.json and assistant.md are new. The assistant holds only
message.send and relays each ruling verbatim to the chief of staff. The
chief of staff gains role.launch; the PM drops it. Test fixtures move
launch.by from "pm" to a `chief` instance.
This does not change the live host. Jason's organization file names
launch.by "pm", which the new role files refuse, so his edit and the
re-pin happen together in one Mos window (decision 144; the order is in
agents/researcher/work/queue-119/build.md).
Lands Researcher's round 2 candidate, approved by Filbert in comment
28528 (rev 1240). Candidate manifest f77c4917, all 22 files match.
Landing gate on 46117feb8: 23 suites, GATE_PASSED 01:09:35Z.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
When the broker answers human-required or tester-required, the CLI
now prints a second line saying the bus accepts these commands only
from its own tree and to run `mosaic` on PATH on a pinned host. The
entry block becomes an exported run(); exit codes are unchanged.
Lands Darkwing's row 130 round 1 candidate, approved by Filbert in
comment 28520 (rev 1228). Candidate manifest 9a5de54d, all four files
match. Landing gate on 9e837ce5f: 23 suites, GATE_PASSED 00:44:07Z.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Candidate manifest 19ef7133db592787c24fa473357687a5741ccd7823627b970624c930a7611dbc
from Rocko's round 1 packet (a6e4fe747), on BASE 234121b30. No
manifest path changed between BASE and the landing target. The
bus-service.sh drop-in guard now refuses inherited mosaic-.service.d
and service.d drop-ins, the header lists every flag, the unreachable
install-show fakes are gone, and the stack-copy.sh wrapper carries its
copy and lease comments after the line-2 marker. Filbert approved in
28489 with no findings. Sage reran the full gate at the landing target
with the candidate applied.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 117. At a launch, update() kept a clone that was on another branch
or dirty and ran no git in it, so its refs/remotes/origin/* stayed as
old as the last clean launch. Now those two reasons get the clean
path's fetch, with the same arguments and environment, and no merge.
The result is a new outcome, fetched, with the reason, the clone's
branch and HEAD, and origin { branch, commit } after the fetch. Every
earlier check still keeps the clone with no fetch. The launcher writes
a checkout-fetched launch-log line, and the bundle prompt names a
fetched clone's branch, commit and origin. Nothing in unsafe(),
allowed(), gitEnv() or SAFE changed.
Candidate manifest 9fa839edfb2bd04771bbac1913b142cb16aef227a1265120e0d318fb64d6a502
from Darkwing's round 1 packet (17d801f48), on BASE 559ef2287. Dewey
approved in 28443. Sage reran the full gate at the landing target with
the candidate applied.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A tester binds with a process proof from the bus's own tester-cli.mjs
when the business var bus.tester is true. It may send [mos test] messages
to a role, receive replies on the tester address and use the read verbs;
every other verb refuses. Messages store from_role tester and write no
human.input event. turnRequest() marks them as never Jason's instruction.
human.mjs is unchanged.
Candidate manifest bdaf7f476abd0b2b5095ab2f7f43e38540e6ba48ee14a02a4f4995a1469b79df
(Darkwing round 2, packet 9f1563ec1), BASE badfa52b9. Approved by Filbert
(comment 28360) and Sage (comment 28361). Sage gate rerun passed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The broker gains a read-only state verb (launch state with the event that set it, open tasks capped). The runner fetches it before each turn and puts a "Current state" block at the top of the request; a failed read fails the turn. turnRequest() adds the message time. roles/pm.md gets one rule: the block is the truth for launch state and task status. Seat session, seat sandbox and cli launcher tests re-anchored to the new request shape.
Built by Researcher, packet 875c515e9. Filbert approved round 3, comment 28333, candidate manifest 0a62225e (11 paths). Sage gate on 9774d70db plus row109.patch: every package node suite and every scripts/test-*.sh green on the first run, skipped 0 in bus, harness and seat. Vikunja #259.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Dewey approve, comment 28331, manifest 5e888f93. Sage gate on be6f2ed8c
plus the patch: every package suite green (cli 178); test-queue failed
review.test.mjs:123 once under load (16s vs 3.7s), passed 28/28 rerun alone;
release 14, task 98. Dewey note a (ended() rejects on a child error and skips
release()) is recorded for the next row that touches host.mjs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Darkwing round 1, approved by Dewey in #1600 comment 28319 on manifest
ae38cbe280aa5885aec7648d38143920753db86ea1ca3934d0a8885fb61e5105.
Sage gate rerun on f63c965f9 plus build.patch: every package suite and
every scripts/test-*.sh green (cli 168, harness 73, test-release 14).
readHostState now treats a host.json that vanishes mid-read as no host
for stopHost and hostStatus too (Dewey note b); Sage accepts it as
correct. Nothing goes live until a re-pin under Mos's go.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
sandboxArgv sets GIT_AUTHOR_NAME/EMAIL and GIT_COMMITTER_NAME/EMAIL from
the instance and business ids (name = instance id, email
<instance>@<business>.mosaic.invalid); spawnSession and the launcher pass
the ids through. checkout results carry the clone's commit (a kept clone
gets none), and the bundle prompt names it. allowed() is unchanged.
Packet agents/darkwing/work/queue-104/r1/ (manifest f99f2ae7). Dewey
approved round 1 in 28293 (posted under jarvis by mistake; 28294 is
Dewey's confirmation). Sage's gate on f00613106 plus the candidate:
every package suite and scripts/test-*.sh green (test-release failed 3
activation checks once, not reproduced; rerun 14/0).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 103, the row 100 follow-up. Built by Darkwing, packet
agents/darkwing/work/queue-103/r1/, candidate manifest
6e5ac8c0782bc595d7c0d711d457738ffb42f1ba5f38253912943dd55e55888a.
Sage approved on #1597, comment 28252; Dewey approved, comment 28260.
Host git runs through runGit: a detached group, SIGTERM at the limit,
SIGKILL after the grace, and one more SIGKILL to the group after a
signalled git closes. git-socket close() waits at most 2 s. startHost
claims bus-host/host.lock by hard link before the broker fork.
packages/cli/README.md and tests/host.test.mjs carry row 85's hunks
too; row 85 lands first.
Sage's gate rerun on 3a1e11b83 with rows 85, 102 and 103 applied,
Docker up: node suites bus 128, business 67, cli 165, control-board
124, conversation 182, discord 178, harness 73, ledger 78, mosaic 69,
queue 155, runs 43, seat 113, tasks 92, webui 108; scripts auth 15,
conductor 17, config 24, discord 66, extension-package 18,
foundation 44, queue 28, release 14, task 98. All pass, 0 fail.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 85 round 2. Built by Rocko, packet agents/rocko/work/queue-85/r2/,
candidate manifest
bd7ea899c7cacef43b415b8e9ecb164e1f36718ffbe64347881a2c5653170c98.
Filbert approved on #1579, comment 28256; Darkwing approved, comment
28258.
stack-copy.sh builds shared read-only copies under
XDG_DATA_HOME/mosaic-stack/copies; the bus and Console services render
and install against a copy with --copy and --pm. No live step is run
by this commit; those need Mos's go.
Sage's gate rerun on 3a1e11b83 with rows 85, 102 and 103 applied,
Docker up: node suites bus 128, business 67, cli 165, control-board
124, conversation 182, discord 178, harness 73, ledger 78, mosaic 69,
queue 155, runs 43, seat 113, tasks 92, webui 108; scripts auth 15,
conductor 17, config 24, discord 66, extension-package 18,
foundation 44, queue 28, release 14, task 98. All pass, 0 fail.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 93 follow-up: SIGTERM then SIGKILL for host git, rollback-failed,
a total body deadline, fetch-aborted for a reviewer gone mid-fetch,
working refs first in have, and tests for five untested refusals.
Dewey approved in 28226 and Sage in 28225; Sage's full gate passed
16:57:32-17:01:32Z. The host side is live at the next bus restart.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Commits move as v2 bundles over bus-host/git.sock (decision 135). The bus
host keeps one bare working repository per business and project, seeds main
from the project root under a per-repository lock, fetches a pushed bundle
with fsck into a temp ref, requires history shared with main, and moves the
task's work ref only as a fast-forward. Host and runner git run with no
system or global config, hooks at /dev/null and local transports only. The
socket binds only for roles holding git.push.working or review.verdict.
The broker records a push as the action.allowed for git.push.working with
its commit, takes review.request for the latest push and one review.verdict
per request, and refuses task.close on a pushed task without an approve
verdict for the latest push. recordEvent reserves both shapes, so agents
can't forge either.
Reviewed by Dewey (28196) and Sage (28197), both approve. Gate on 7a729aef:
14 node suites and 9 scripts green.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 91, round 3. Darkwing built it, Dewey approved it (comment 28150) on
manifest ca570607 (8 paths, base 2b2a9e14). At each launch the host
makes or updates a git clone of the project in the role's workspace,
and the session prompt names each clone. Round 3 closes Filbert's round
2 escape: a clone with a submodule is kept as it is, and no host git
recurses into one (decision 130 thread). Live at the next bus restart;
the prompt lines appear only when the launcher passes checkouts.
Sage gate on fc6d5822 plus the patch, 14:18:25Z to 14:22:27Z: bus 115,
business 60, cli 131, control-board 124, conversation 182, discord 178,
harness 67, ledger 78, mosaic 69, queue 150, runs 43, seat 89, tasks 89,
webui 104, all fail 0. Every scripts/test-*.sh exited 0; test-release
ran 14 cases.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 94, round 2. Rocko built it, Dewey approved it (comment 28104) on
manifest 53b01ea9 (16 paths, base e918a915). The bus keeps a messages
view with read state, where delivered but not read stays read:false. The
CLI gains messages and follow, and inbox leaves out messages already
read while inbox --json stays byte-compatible. The Console gets a
Messages page and an unread count in the nav. Mos gave the go under
decision 123 (public/ files). Sage gate on 645489e4 plus the patch,
12:52:14Z to 12:55:44Z: bus 115, cli 129, webui 104, all fail 0. Every
scripts/test-*.sh exited 0 (auth 15, conductor 17, config 24, discord
66, extension-package 18, foundation 44, queue 27, release 14, task 98).
Manifest 16/16 before and after.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 69, built by Darkwing, approved by Dewey (comment 28048) and Filbert
(comment 28055) on manifest c68e6582. Sage gate on c6711453: cli 123/0,
queue 150/0, every scripts suite green.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 92, round 2. Darkwing built it. A role session runs in a bwrap
sandbox that sees only its own workspace, a private /proc, /dev and IPC
namespace, and the variables ENV_ALLOW passes. The launcher checks the
session credential before a Claude launch, records a runner killed from
the host as killed rather than failed, and the bus unit template carries
the credential file (decision 119). The harness gate and the cli, seat
and harness READMEs say what the sandbox does and does not hide.
Candidate manifest 8bf4141cbe69fc7bed188555bcc88dcab0b1ea2149912cb6f970ba8c2629dd97
(13 paths), base ac37cd17, packet agents/darkwing/work/queue-92/r2/.
Approvals: Dewey 27978, Filbert 27984 (round 1: Dewey 27942, Filbert
asked for changes in 27951). Sage's gate rerun 22:27:37Z-22:30:35Z on
1b7f3781 plus the patch, manifest 13/13: seat 33, cli 120, harness 65,
bus 108, webui 86, control-board 124, and every scripts/test-*.sh exited 0
(test-release 4, Docker cases skipped at a dead socket).
Live at the next bus restart and the next role session launch (decision
109). Installing the new unit and restarting is Mos's call.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Row 81. The broker gains a `replies` read verb for human and reader
sessions: `{id}`, a message UUID, returns that business's messages whose
in_reply_to is the id, oldest first, at most 50, and writes no
deliveries row, so the reply still reaches the next `mosaic talk`. An
unknown id refuses message-not-found. The Console serves it through
BUS_VERBS with an id check, and the Sent receipt shows the replies to a
web send. The cli's talk timeout message and README now say the reply
may still come and the next `mosaic talk` prints it.
Dewey's round 2, candidate manifest 3ce7527f, base 1e5f5958, a rebase
after row 61. Approved by Darkwing (27783 round 1, 27821 round 2).
Sage's gate green 19:25:18Z to 19:30:39Z. Live at the next bus restart
(the broker verb) and Console restart (the view), bus first.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Two default-pin cases (no --claude): the only claude on PATH is mode 0644,
and claude in a PATH dir with a space. render exits 1 with stdout empty
for each. PATH holds only the test's dirs. Author Rocko, reviewer Filbert
(27560), candidate manifest 3016dbf1.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
One test in packages/cli/tests/host.test.mjs: a directory given with
--claude is refused, and a symlink default stays the symlink path. One
in packages/harness/tests/claude-session.test.mjs: a directory pin exits
2 before claude runs, and a pin under a directory with a space runs.
agents/rocko/work/queue-72/mutants.sh (committed with the packet in
036afdb6) reruns the six row 68 mutants: all killed on the candidate,
all surviving on the base. Accepted deviation: bash's command -v never
returns a directory, so a directory named claude on PATH takes the
no-claude branch, which the test asserts.
Author: Rocko. Candidate manifest e6531a5311f17ea147700e417dfdbd766a9c38acf3c3b44755267c285b78e006
(base a0080da8, no drift on the candidate paths, bus-service.sh or
adapter.sh). Approved by Filbert, comment 27460 on #1566; their N1 is
row 78, #1572.
Sage gate rerun on a worktree of df676fa1 with the patch: manifest OK;
cli 113/113, harness 58/58, 0 skipped; test-auth 15, conductor 17,
config 24, discord 66, extension-package 18, foundation 44, queue 27,
release 14, task 98, all 0 failed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
MOSAIC_CLAUDE_BIN names the claude binary by absolute path instead of
finding it on PATH. scripts/bus-service.sh render|install --claude PATH
writes it into the unit (default: command -v claude in the installing
shell); the claude adapter, the launcher's version read and the seat
session environment all use it. Mos's Q18 ask: the unit's PATH found
/usr/bin/claude 2.1.259, which refuses claude-opus-5-5.
Candidate: round 2 manifest 21c1ab05, round 1 (a2008d8b) rebased onto
f2f2861b after row 55 changed docs/TOOLS.md and packages/cli/README.md;
the changed lines are byte-identical. Approved by Filbert (27349, 27374)
and Dewey (27350, 27375). Sage's gate on f2f2861b plus the patch: cli
112, seat 27, harness 57, nine scripts/test-*.sh 0 failed, Docker on.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
With tracker.descendants on, the tracker project is the root of a tree.
Each reconcile reads the sync bot's project list (archived projects and
negative pseudo-project ids left out) and walks it by parent_project_id.
A child that passes the install checks is read through its board, and
one that doesn't is watch-only (bucket 0) and never refuses the
business. A tick reads each project in the tree. A child answering 403
or 404 leaves the tree only if GET /projects/<id> then answers 403 or
404 too, and its open tasks get the one-by-one read. Task refs carry
the project, so a task moved inside the tree shows under its new ref
and the old ref gets its tombstone. tracker.descendants reaches the adapter
through the business var and packages/cli/src/config.mjs (lead decision
87). Off, the adapter reads as v0 did.
Darkwing built it (agents/darkwing/work/queue-62), in three rounds.
Round 3 was approved by Filbert (27317) and Dewey (27338) on manifest
8b81e836, 13 paths. Their non-blocking notes and Darkwing's follow-ups
(two surviving mutants in test 18, the fake's view-404 code) go to a
follow-up row.
Sage's gate on 918a4a19, sequential and teed: node suites tasks 71,
business 60, bus 80, cli 110 and queue 150, 0 failed; webui 39 of 40,
then 40 of 40 on three reruns (row 62 touches no webui file; a timing
test under load 17 with Dewey's gate running beside it); test-auth 15,
test-conductor 17, test-config 24, test-discord 66,
test-extension-package 18, test-foundation 44, test-queue 27,
test-release 14, test-task 98, all 0 failed (Docker on). edc5de71..HEAD
touches none of the 13 paths.
Live read, 2026-10-11T21:28:03Z, tasks.woltje.com v2.7.0, root #19,
descendants on, sync key only, GETs only (the startup scope probes not
sent): reconcile 15 GETs, 42 snapshots; tick 8 GETs, 0 snapshots.
Children 18, 20 and 21 are watch-only. A missing view id on #18 answers
404 (code 3014) while #18 reads 200, as the README says. Record:
agents/sage/work/vikunja-setup/2026-10-11_tick-62.json.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bare `mosaic` on a terminal opens the app. It has Inbox, Tasks, Agents
and Trail screens, help, and a decide overlay, and it uses the alternate
screen, raw mode, resize and SIGTERM, and restores the terminal on exit.
draw(state) in screens.mjs is pure. cli.mjs exports resolveDecision,
which `mosaic decide` and the app share, so both write the same lines
and ask the same question. A decision resolves on `y` only while
decideShown() says the whole decide box is on screen. The app reads that
at the key. A box that doesn't fit is replaced by "Too small to show this
decision", and any key answers No. scripts/mosaic sends no arguments to
packages/cli (a decided scope addition), so the queue dispatch test
follows. The cli README and docs/TOOLS.md describe the app.
Darkwing built it (agents/darkwing/work/queue-55), in three rounds.
Round 3 was approved by Dewey (27308) and Filbert (27309) on manifest
59f1b9b4, 9 paths. Their non-blocking notes go to row 69 (#1562): a
narrow-terminal test for the decideShown MIN_COLS guard, a way out from
the hidden box, a U+18D08 width test, a cut box keeping Esc back, and
the README row count stated as an example.
Sage's gate on 3634d06e, sequential and teed: node suites cli 110 and
queue 150, 0 failed; test-auth 15, test-conductor 17, test-config 24,
test-discord 66, test-extension-package 18, test-foundation 44,
test-queue 27, test-release 14, test-task 98, all 0 failed (Docker on).
122b1223..3634d06e touches none of the 9 paths.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Slice 1 S6. packages/harness runs a role session under the pi or claude
adapter behind a tool gate, and packages/seat holds the session and its
process. The bus host gains a launch socket: `mosaic bus start
<business> --pm <harness>:<model>` runs the PM without a window, the PM
launches role sessions through the broker within the business file's
`launch.max`, and every launch, refusal and end is a launch-log line and
a broker event. `mosaic talk`, `mosaic launches off|on|list` and
`mosaic stop <run>` are new CLI verbs. packages/bus gains the IPC ops
identity, authorize, refuse, endLaunch and credentialStatus, plus
Broker.endLaunch (decision 77); no socket verb, event kind or schema
changed. The session environment is an allowlist, and the runner exits
before claiming if a founder credential reaches it.
Filbert built it (agents/filbert/work/s6). Darkwing reviewed on #1523:
round 1 changes (26991/26995), round 2 changes (27004/27010), round 3
changes (27012/27032), round 4 approve (27033/27034) on manifest
08a78972, 42 paths.
Sage's gate on 64b0f9f1 (12:32Z), sequential and teed: node suites
business 60, bus 74, cli 83, control-board 124, conversation 182,
discord 178, harness 56, ledger 78, mosaic 69, queue 149, runs 41,
seat 27, tasks 51, webui 39, every one 0 failed; test-auth 15,
test-conductor 17, test-config 24, test-discord 66,
test-extension-package 18, test-foundation 44, test-queue 27,
test-release 14, test-task 98 and 26 without Docker, all 0 failed.
64b0f9f1..ee7f909b touches none of the 42 paths. It landed after the
Q14 hold ended at 2026-10-11T17:19:23.857Z. The recorded PM-to-coder
run on a scratch data root is still owed before row 41 moves to done.
Co-Authored-By: Claude Opus 5.5 <[email protected]>