Conference of 7 experts (architect/moonshot/contrarian/coder/aiml/devex/steward) debated layering, sanitization, upgrade-safety, cross-harness robustness. Artifacts: BRIEF, 7 positions, 7 rebuttals, synthesis-v1, 3 red-team passes, canonical DESIGN.md, OPEN-QUESTIONS.md, MISSION.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
36 KiB
Mosaic Framework Constitution — Canonical Design (Alpha)
Status: CANONICAL. This is the single design of record for the alpha. It supersedes
synthesis-v1.md where they differ. It integrates synthesis-v1.md and the three red-team passes
(debate/redteam-contrarian.md, debate/redteam-devex.md, debate/redteam-steward.md), each finding
either mitigated here or explicitly accepted with rationale (§9). A PRD derives from this document;
implementation derives from the PRD.
Scope: DQ1–DQ5 of BRIEF.md, plus the non-DQ release blockers (LICENSE, hardcoded credential
path) the debate surfaced. Every claim is grounded in the real tree at
packages/mosaic/framework/ and packages/mosaic/src/; paths and line numbers were re-verified
against the working copy, not trusted from the prior papers.
0. What changed vs synthesis-v1
The synthesis layer model and "subtraction not addition" doctrine survive the red team intact and are adopted wholesale. What the red team broke — and this document fixes — is the seam between the spec and the mechanisms it assumed already existed. Three facts re-verified here change the plan:
- The resident contract is the root file
~/.config/mosaic/AGENTS.md, seeded once and never re-seeded.launch.ts:326reads rootAGENTS.md;install.sh:236seeds it only when absent ([[ ! -f ... ]]);file-adapter.ts:187(if (existsSync(dest)) continue) does the same in the npm path. Removing files fromPRESERVE_PATHSdoes NOT update them — it only stops preserving a file the seed loop then declines to recreate. The synthesis's headline drift fix is mechanically wrong (contrarian R1, steward RISK-04). Fixed in §3/§5. mosaic <harness>already self-heals a missingSOUL.mdviacheckSoul()(launch.ts:55-68): it runs the setup wizard, so deletingdefaults/SOUL.mddoes not brick amosaic-launched session. The real hole is (a) bare launches that bypassmosaic, and (b) the wizard hanging on a non-TTY host (devex B1, contrarian R4). Fixed in §3/§4.- The contamination is broader than synthesis-v1 enumerated — re-grep finds the private
credential path in three scripts (incl.
tools/health/stack-health.sh:23), a private domainbrain.woltje.comin the shippedprevent-memory-write.shhook, and operator tokens acrosstools/,guides/, and the init generator's default role string — none of which the synthesis fix list or the proposed grep scope covered (devex B3, steward RISK-01/03). Fixed in §6.
There are two dual implementations of the upgrade logic (install.sh bash + file-adapter.ts
npm), kept in sync only by a comment (file-adapter.ts:148). Every mechanism change in this document
is specified as "in both installers, proven by one shared fixture suite" (contrarian R10). This is
promoted to a first-class design constraint, not an afterthought.
1. Layering & Precedence (final model)
1.1 The legitimacy test
A layer boundary is legitimate iff the two sides differ in owner, upgrade-fate, OR
residency. This single test (from synthesis-v1.md §1, banked by all three red teams) decides
every split below and rejects gratuitous ones.
1.2 The canonical layers
Five concerns, four owned layers plus a non-resident governance spec.
| # | Layer | Owns | Owner | Upgrade fate | Residency | Deployed path |
|---|---|---|---|---|---|---|
| L0 | Constitution | Irreducible non-negotiable law: the hard gates, escalation triggers, block-vs-done, mode declaration, the two-axis precedence rule, the "hooks are the gate" doctrine, the "no operator context in framework PRs" firewall, and the universal merge-disambiguation rule (see §1.4) | Framework | Overwritten wholesale every upgrade (unconditional copy, never seed-if-absent). User MUST NOT edit. | Always resident, byte-budgeted | ~/.config/mosaic/CONSTITUTION.md |
| L1 | Standards & Guides | How to do the work well: secrets/ESO, trunk-based git, image tagging, E2E procedure, QA matrix, orchestrator protocol, all guides/* |
Framework; a deployment may tighten via overlay | Overwritten; user delta lives in STANDARDS.local.md; guides never forked |
STANDARDS.md resident; guides/* on-demand |
~/.config/mosaic/STANDARDS.md, ~/.config/mosaic/guides/* |
| L2 | Persona (SOUL) | Agent name, tone, role, communication style, persona principles | User (init-generated) | Never overwritten. Generated from template. | Always resident, byte-budgeted | ~/.config/mosaic/SOUL.md (+ optional SOUL.local.md) |
| L3 | Operator (USER) | Human name, pronouns, timezone, accessibility, comms prefs, projects, operator policy (e.g. merge-authority delegation), operator tool paths/env | User (init-generated) | Never overwritten. | Always resident, byte-budgeted | ~/.config/mosaic/USER.md (+ optional USER.local.md, optional policy/*.md) |
| L4 | Project / Runtime mechanism | Per-repo AGENTS.md deltas; harness-specific mechanism only (subagent syntax, hook/MCP wiring, injection tier) |
Repo / framework | Project file user-owned; runtime mechanism overwritten | Project in-repo; runtime resident, ~15 lines | <repo>/AGENTS.md, ~/.config/mosaic/runtime/<h>/RUNTIME.md |
| — | Layer-Model spec (governance) | The definition of the layers, precedence, and "what may live in L0" | Framework maintainers | Source-only, never deployed | Not resident | packages/mosaic/framework/constitution/LAYER-MODEL.md |
Deployed AGENTS.md is not a layer — it is the thin load-order dispatcher + Conditional Guide
Loading table that routes to L0–L4. Framework-owned, overwritten on upgrade.
1.3 Precedence — typed two-axis, not a flat stack
Stated verbatim in L0:
Safety axis (gates, integrity, destructive actions): L0 Constitution is supreme. Nothing in STANDARDS, SOUL, USER,
policy/, projectAGENTS.md, runtime, or any injected reminder may relax, suspend, or contradict a Constitution gate. A lower layer may only make behavior stricter, never more permissive.Taste axis (tone, formatting, verbosity, iconography): the operator layers (SOUL/USER) win over generic framework or model defaults. The framework has no legitimate opinion on style.
1.4 The merge-disambiguation correction (contrarian R6 — accepted and fixed)
The synthesis moved the entire gate #13 to an opt-in example. That silently weakens a hard gate: by the stricter-only rule, a deployment that does not adopt the example defaults to the strictest reading of "No self-merge" — never merge without the human — which contradicts gates #2/#9 the BRIEF says to preserve. Gate #13 is therefore split:
- Universal law (stays in L0, operator-agnostic): "A 'No self-merge' note on a PR means no UNREVIEWED self-merge; it does not suspend a coordinator-authorized merge. When a coordinator session is active, the post-review merge go-ahead is the coordinator's; once review gates pass, proceed on the coordinator's confirmation."
- Operator delegation (→
examples/policy/merge-authority.example.md): "don't wait on{{OPERATOR_NAME}}personally." The named-person clause and only that clause leaves L0.
This keeps the gate-interaction semantics universal while removing the PII.
1.5 Enforcement strength is a ranked ladder, not a choice
mechanical (hook / CI) > resident-by-value (system-prompt injection) > file-read (self-load fallback)
- Mechanical first. Every checkable gate becomes a hook or CI check (no-force-merge,
green-CI-before-done, no-hardcoded-secrets, no-PII, no-dead-paths, no-unrendered-tokens). This
drains prose from the resident core — the precondition that makes tiers 2–3 viable. Precedent:
prevent-memory-write.sh(runtime/claude/RUNTIME.md:30) — "the rule alone proved insufficient; the hook is the hard gate." - Resident-by-value second. The irreducible non-checkable stop-condition gates (block-vs-done, escalation, completion-definition) injected by value at primacy, restated as a ≤5-bullet anchor at recency (bottom).
- File-read third (fallback). Tier-3/bare launches: unconditional read (see §1.6).
1.6 Tier-aware self-load (contrarian R9 / steward RISK-07 — accepted)
The fallback read instruction differs by tier:
- Tier-1 (injected by value): "
CONSTITUTION.mdis already in your context above; do not re-read." (true, because the launcher demonstrably injected it). - Tier-3 (bare-launch pointer): unconditional — "READ
~/.config/mosaic/CONSTITUTION.mdnow, before your first action." No "if not already in context" introspection — models are unreliable at judging their own window, and this is the exact drift-prone path the fallback exists to protect.
This removes the false unconditional "already in your context — do not re-read" at
defaults/AGENTS.md:11 (every paper flagged it; it is still live in the tree).
2. File-by-File Move / Sanitize Plan
2a. New files
| New file | Content | Source |
|---|---|---|
defaults/CONSTITUTION.md → deploys to ~/.config/mosaic/CONSTITUTION.md |
L0, one flat file, ~70–90 lines. The 13 hard gates with the §1.4 split applied (operator name removed, disambiguation kept); 5 escalation triggers; block-vs-done; mode-declaration; the §1.3 two-axis precedence rule verbatim; the "hooks are the gate" doctrine; the §4 "no operator context in framework PRs" firewall; the §1.6 tier-aware self-load lines; one pointer to the guide index. Gates keep full wording; procedure (wrapper paths, --purpose flags) moves to L1. L0 is authored in capability verbs — no tool-named "else stop" (see §7, devex M7). |
Extracted from defaults/AGENTS.md:23-87,143 |
constitution/LAYER-MODEL.md |
The §1 model + precedence + "what may live in L0" + the overlay-eligibility list (§4). Source-only, never deployed, never resident. | This document |
examples/personas/execution-partner.md |
Sanitized, placeholdered essence of the Jarvis persona — a worked example, copied on request, never auto-loaded | defaults/SOUL.md (sanitized) |
examples/overlays/e2e-loop.json |
Sanitized essence of jarvis-loop.json (~/src/<your-project> placeholders) |
runtime/claude/settings-overlays/jarvis-loop.json |
examples/policy/merge-authority.example.md |
The operator delegation clause from §1.4 | defaults/AGENTS.md:37 |
LICENSE (monorepo root) + packages/mosaic/framework/LICENSE |
MIT text + "license": "MIT" in package.json |
new (D8) |
CONTRIBUTING.md (framework package) |
Layer model, PII/secrets prohibition, dedup rule, how to add a harness adapter, the re-contamination rule, the dual-installer parity rule, the known-limitations list (§9) | new |
tools/quality/scripts/verify-sanitized.sh |
The blocking CI gate (§6) | new |
.woodpecker.yml (framework package or monorepo root) |
Wires verify-sanitized.sh, the resident line-count check, and the composer unit test as blocking steps |
new (steward RISK-02 — the gate is prose until wired) |
2b. Files that shrink / change role
| File | Change | DQ |
|---|---|---|
defaults/AGENTS.md |
Gut 155→~50-line dispatcher: load order + Conditional Guide table + tier-aware self-load. Zero restated gates. Remove the false line 11. Change seed semantics to unconditional overwrite (see §3). | DQ1, DQ5 |
defaults/STANDARDS.md |
Drop "Master/slave" framing (line 5 → "Primary / satellite"); stop re-asserting L0 gates; end with the STANDARDS.local.md additive-include convention. Becomes overwrite-on-upgrade. |
DQ1,3,5 |
defaults/TOOLS.md |
Delete the MANDATORY jarvis-brain rule block (lines 40-44). Generic index only. |
DQ2 |
defaults/README.md:72 |
--name Jarvis --user-name Jason --timezone America/Chicago → placeholder names. |
DQ2 |
templates/SOUL.md.template |
Already clean. Keep. Ensure every {{TOKEN}} resolves to a non-empty value in init (no token survives into a resident file). |
DQ2 |
templates/agent/AGENTS.md.template and templates/agent/projects/*/{AGENTS,CLAUDE}.md.template |
Delete the restated Hard-Gates block. Replace with: "This project is governed by ~/.config/mosaic/CONSTITUTION.md. Add only project-specific extensions below." Fix every rails/git/→tools/git/, rails/codex/→tools/codex/ across BOTH AGENTS.md.template and CLAUDE.md.template families (devex m10 — synthesis named only the AGENTS family). |
DQ4,5 |
runtime/{claude,codex,pi,opencode}/RUNTIME.md |
Strip restated policy. Reduce to harness mechanism + one-line CONSTITUTION.md reference. Rewrite the four "sequential-thinking MCP is required / else stop" lines to capability-verb form (§7). |
DQ4,5 |
tools/_lib/credentials.sh:19, tools/git/detect-platform.sh:89, tools/health/stack-health.sh:23 |
${MOSAIC_CREDENTIALS_FILE:-$HOME/src/jarvis-brain/credentials.json} → ${MOSAIC_CREDENTIALS_FILE:?MOSAIC_CREDENTIALS_FILE must be set} (fast-fail per STANDARDS.md:35). Document the env var in USER.md.template under ## Tool Paths. Three sites, not two (steward RISK-01, devex B3). |
DQ2 (blocker) |
tools/qa/prevent-memory-write.sh:29 |
https://brain.woltje.com/v1/thoughts → ${OPENBRAIN_URL:?OPENBRAIN_URL must be set}/v1/thoughts. This hook prints its URL to the agent on every blocked write — a private domain in every install. |
DQ2 (blocker-class) |
tools/_scripts/mosaic-init:277-278 |
Default AGENT_NAME "Assistant" + the verbatim Jarvis role string ("execution partner and visibility engine"). Fail-closed on persona in --non-interactive unless --agent-name given; replace the role default with a neutral placeholder. (devex B2 — the generator re-creates the bug verify-sanitized.sh can't see.) |
DQ2 |
tools/_scripts/mosaic-doctor:312 |
mosaic-jarvis skill → mosaic-agent (generic). |
DQ2 |
guides/ORCHESTRATOR.md (99,111,152), ORCHESTRATOR-LEARNINGS.md:127, ORCHESTRATOR-PROTOCOL.md:4, TOOLS-REFERENCE.md (149,182,226), BOOTSTRAP.md |
Replace jarvis-brain/... paths with ~/.config/mosaic/... canonical paths; remove the MANDATORY jarvis-brain rule block. (steward RISK-03 — broader than synthesis named.) |
DQ2 |
2c. Files deleted / relocated
| File | Action | Why |
|---|---|---|
defaults/SOUL.md |
Delete. Persona generated at init from template; mosaic self-heals via checkSoul(); bare-launch hole closed in §3. |
Primary contamination vector |
runtime/claude/settings-overlays/jarvis-loop.json |
Delete → sanitized examples/overlays/e2e-loop.json |
Personal project map |
defaults/AUDIT-2026-02-17-framework-consistency.md |
Move to monorepo docs/ |
Maintainer artifact, not agent context |
3. Customization + Upgrade-Safety Mechanism
The single sentence a user can rely on: "Edit SOUL.md/USER.md and the *.local.md overlays
freely — upgrades never touch them. Never edit CONSTITUTION.md/STANDARDS.md/guides/*/AGENTS.md
— they update automatically every upgrade. To change framework behavior, add a .local.md overlay or
a policy/ file (tighten-only)."
3.1 The seam = ownership, enforced by overwrite semantics (contrarian R1 / steward RISK-04 — the central fix)
The synthesis's "remove from PRESERVE_PATHS" is necessary but not sufficient. The seed-if-absent
logic must be replaced with unconditional overwrite for the framework-owned root files, in BOTH
installers:
- Split the seed lists by ownership.
DEFAULT_SEED_FILES(file-adapter.ts:16) and theinstall.sh:236seed loop are split into:FRAMEWORK_OWNED=CONSTITUTION.md,AGENTS.md,STANDARDS.md→ always copied (overwrite) on every upgrade. Never inPRESERVE_PATHS.USER_SEEDED=TOOLS.md(generated-then-tuned) → seed-if-absent, kept inPRESERVE_PATHS, retains.bak.<ts>-on-regenerate.
SOUL.md,USER.md,*.local.md,policy/,memory,sources,credentialsare the onlyPRESERVE_PATHSentries.AGENTS.mdandSTANDARDS.mdare removed.- Test the injected bytes, not file presence (contrarian R1). The migration fixtures assert what
buildPrompt/launch.ts:325-333composes, because testingdefaults/AGENTS.mdcontent would pass while the resident root contract stayed stale.
3.2 Additive overlays, launcher-composed (steward RISK-06 / devex M6 — build it, don't assume it)
mosaic compose-contract <harness> does not exist and is alpha-blocking, not assumed.
Minimum viable spec:
- Concatenates, in precedence order, base +
.localdeltas before injection, so the model gets one pre-merged blob (no redundant read-merge ritual). - Per-harness emission (the four harnesses are not symmetric):
- Pi /
mosaic claude/mosaic codex— append the merged blob via--append-system-prompt. - Codex / OpenCode — write the merged blob into the instructions file
(
~/.codex/instructions.md,~/.config/opencode/AGENTS.md).
- Pi /
- Bare launches that bypass
mosaicget base-only overlays (the launcher never ran to compose them). This is documented loudly as a known limitation (§9), and theAGENTS.mdself-load fallback emits a one-line "overlays requiremosaic <harness>; runmosaic doctor" nudge. - Alpha scope cut (accepted): ship
SOUL.local.md+USER.local.md(the two files users actually customize) andSTANDARDS.local.md. Deferpolicy/*.mdcomposition to v2 if build budget is tight — but the L0 merge-disambiguation rule (§1.4) meanspolicy/is additive delegation only, never load-bearing for a gate, so deferral is safe.
3.3 Versioning & migration
- One global
FRAMEWORK_VERSIONinteger + linear migrations (existinginstall.sh:157-198scaffold). No per-layer version matrix (combinatorial test cliff). Per-layer template versions survive only as amosaic doctoradvisory. - Bump
FRAMEWORK_VERSION2→3. The v2→v3 migration:- Snapshot
~/.config/mosaic/→~/.config/mosaic/.backup-v3/first (contrarian R2 — today there is no snapshot; thecp-fallbackrm -rfatinstall.sh:140can loseSOUL.md/credentialson interrupt). Implement as atomic snapshot → sync → on-failure-restore in BOTH installers; a fixture kills the process mid-sync and asserts no data loss. - Vendor the v2 baseline of
AGENTS.md/STANDARDS.mdinto the migration. If the installed file differs from the v2 baseline (it was user-edited — the sanctioned customization until now), copy it toAGENTS.md.pre-constitution.bak/STANDARDS.local.mdand print a one-line notice before overwriting (contrarian R2, devex M5). Never silently delete; never auto-merge (Markdown has no merge semantics — a half-resolved merge leaves<<<<<<<markers in the resident identity file). Fixture 3 asserts the delta landed in.local.md, not merely that a backup exists. - Install
CONSTITUTION.mdas a new file nothing previously owned (avoids reclassifying a user-edited flatAGENTS.md).
- Snapshot
- Headless bootstrap (devex B1 / contrarian R4 — the hole
checkSoulhalf-covers).mosaic <harness>self-heals a missingSOUL.mdviacheckSoul()(launch.ts:55), but the wizard hangs on a non-TTY host. Fix:install.shrunsmosaic-init --non-interactiveafter sync so a validSOUL.md/USER.mdalways exists post-install; the wizard's non-interactive path is fail-closed on persona (devex B2) — it errors asking for--agent-namerather than silently shipping an agent named "Assistant" with the Jarvis role string.
3.4 The migration is the biggest risk — gate the alpha on a falsifiable fixture matrix
Alpha cannot tag until these pass with no interactive prompt, no hang, run against both
install.sh and FileConfigAdapter.syncFramework from one shared suite (contrarian R10):
- Fresh install → valid resident
CONSTITUTION.md+AGENTS.md+SOUL.md+USER.mdexist; assert injected bytes. - Legacy-flat user-edited install (
MOSAIC_INSTALL_MODE=keep, the upgrade default; steward RISK-05) → law moves toCONSTITUTION.md, rootAGENTS.mdis overwritten with the new dispatcher, the user's old edits land inAGENTS.md.pre-constitution.bak,SOUL.md/credentialssurvive. - User-tuned-standard install → the
STANDARDS.mddelta survives asSTANDARDS.local.mdand the frameworkSTANDARDS.mdupdates. - Unattended install (no TTY) → valid resident
SOUL.md/USER.mdexist, zeroreadcalls, no agent named "Assistant". - Interrupt-during-sync → snapshot restore leaves no data loss.
3.5 Detection without enforcement
mosaic doctor reports drift / unrendered-tokens / budget-overflow / template-version-skew as
advisories (warn, never block launch). --check-constitution is opt-in diagnostic, not a gate.
Accepted limitation: drift on bare launches that never invoke mosaic is undetected by doctor
(devex m9) — documented in CONTRIBUTING.md; the self-load fallback nudges the user toward doctor.
4. Sanitization — per-layer strategy + a class-closing CI gate
Ships generic (PII-free, complete): CONSTITUTION.md, AGENTS.md (dispatcher), STANDARDS.md,
TOOLS.md (generic index), all guides/* (purged), templates/* (token-only), examples/*
(placeholdered), runtime/*/RUNTIME.md (mechanism-only), adapters/*.md, LICENSE, CONTRIBUTING.md.
Generated at mosaic init: SOUL.md, USER.md, TOOLS.md, *.local.md, optional policy/*.md,
per-harness runtime copies.
Deleted / relocated: per §2c.
4.1 The CI gate — honest scope (contrarian R7 / devex B3 / steward RISK-01,02,03)
verify-sanitized.sh is split into two rule-classes so it neither false-positives into being disabled
nor under-scopes past the runnable contamination:
- Structural rules (operator-independent, always valid): unrendered
{{...}}/${...}in resident files; dead/rails/tokens; L0 must contain no tool-named hard-stop (grep CONSTITUTION.md for 'sequential-thinking|MCP.*REQUIRED|else stop' → fail, §7); no${VAR:-$HOME/...}private-default in any*.sh. - Current-contaminant denylist (labeled one-time regression guard, NOT a general PII detector):
jarvis|jason|woltje|\bPDA\b|jarvis-brain|brain\.woltje\.com, and the specific absolute path/home/jwoltje/. Anchored to avoidcomparison/jsonwebtokenfalse hits. - Scope:
defaults/ guides/ templates/ runtime/ adapters/ tools/over both*.mdand*.sh(the credential leak and the hook URL live in*.shundertools/— the synthesis grep covered neither). Excludesexamples/. - Self-test: the gate plants a
jarvis-braintoken in a fixture and asserts the gate fails, so a grep-syntax error can't silently no-op the gate (steward RISK-02). - Wired blocking in
.woodpecker.yml. Until green-and-wired, the alpha cannot tag.
4.2 The durable class-closer is the L0 prose firewall + human review, with the grep as backup
The primary author of future framework PRs is an agent running with some operator's SOUL/USER in
context; a 6-token denylist cannot generalize to the next operator's name. So the primary control
is the L0 rule, stated verbatim in CONSTITUTION.md:
"When proposing a framework PR or capturing a
framework-improvement/tooling-gap, you MUST NOT include content derived from SOUL.md, USER.md, or operator-specific context. If you cannot express it operator-agnostically, it belongs inpolicy/or a projectAGENTS.md, not the framework."
The grep is the backup regression guard, explicitly labeled as such — not oversold as closing the PII class.
5. Cross-Harness Adapter Strategy
Single source: L0 CONSTITUTION.md is the one law text. No harness gets a forked copy; runtime
files and project templates reference it, never restate it.
Adapter contract (mechanism only): adapters/<h>.md / runtime/<h>/RUNTIME.md may specify only
(a) the injection channel + tier, and (b) how L0's capability verbs bind to concrete tools and
whether absence is a hard stop. The Constitution says "use structured reasoning before planning";
the Claude adapter binds it to sequential-thinking MCP (gate=true); the Pi adapter to native
thinking (gate=false). For the alpha, this binding is a markdown table; JSON manifests are v2.
Tiered, honest injection (the four harnesses are not symmetric — verified):
| Harness | Channel | Tier | L0 delivery |
|---|---|---|---|
| Pi | --append-system-prompt, no hook backstop (adapters/pi.md:14) |
1 | By value at primacy; keep L0 tiny — resident fidelity is Pi's only enforcement |
mosaic claude / mosaic codex |
system-prompt append (launch.ts:518,551) |
1 | By value at primacy + ≤5-bullet recency anchor |
| Codex / OpenCode | instructions file | 2 | Resident-ish; composer writes merged blob; self-load backup |
bare claude/codex/opencode |
thin pointer | 3 | ≤5-bullet anchor inline + unconditional "READ CONSTITUTION.md NOW" |
Tier-3 anchor must be a literal L0 substring, not a paraphrase (devex M4 — accepted). You cannot forbid paraphrasing gates (D7) and then ship a 5-bullet paraphrase as the Tier-3 payload. The anchor is the exact bytes of the 5 irreducible stop-condition gate lines, so Tier-3 is a strict subset of Tier-1, never a divergent text. The composer unit test asserts byte-equality of the anchor against its L0 source lines.
Verification control — re-scoped (contrarian R3 / steward RISK-11 — accepted). The synthesis's
"live-launch each harness in CI and assert effective context" is impractical (no Codex/OpenCode prompt
dump; Tier-3 unassertable without reading model behavior). Replace with a composer unit test:
assert buildPrompt(harness) output contains the irreducible-gate anchor for each tier, and that the
Tier-3 anchor is byte-equal to its L0 source. This is real and cheap. Live-launch smoke testing is a
v2 aspiration. Codex/OpenCode hook parity is a tracked gap in CONTRIBUTING.md's
compliance matrix, not something the alpha closes.
sequential-thinking contradiction (devex M7 — accepted). It lives in four RUNTIME files
(runtime/{claude,codex,opencode}/RUNTIME.md:3 say "required"; runtime/pi/RUNTIME.md:61 says "not
gated"). All four are rewritten in the same PR to capability-verb form; L0 carries no tool-named
"else stop"; the structural CI rule (§4.1) enforces it; a fixture asserts a bare pi launch does not
emit a sequential-thinking halt.
6. Phased Implementation Plan (alpha — ordered, each phase independently shippable)
Each phase is a self-contained, CI-green PR. Order is dependency-driven: legal/safety first, then the extraction the rest depends on, then mechanism, then cross-harness, then the gate that locks it.
Phase 0 — Legal & runnable-leak blockers (no behavior change)
- Add MIT
LICENSE(root + framework) +"license": "MIT"inpackage.json. - Fix the credential path in all three
*.shsites →${MOSAIC_CREDENTIALS_FILE:?...}. - Fix
brain.woltje.cominprevent-memory-write.sh→${OPENBRAIN_URL:?...}. - Ships independently; closes the legal window and the executable-leak class. No layer changes yet.
Phase 1 — The sanitization gate (the lock comes before the cleanup)
- Write
verify-sanitized.shwith the §4.1 two-class rules + self-test; wire blocking in.woodpecker.yml. Build goes red on the current contamination — intended; it scopes Phase 2. - Ships independently as "CI now fails on operator data," even before the data is removed (the red build is the worklist).
Phase 2 — Sanitize the existing tree to green (mechanical, no architecture)
- Purge all operator tokens across
guides/,defaults/TOOLS.md,README.md,mosaic-doctor,mosaic-initdefaults;rails/→tools/across both template families; drop "Master/slave". - Delete
defaults/SOUL.md,jarvis-loop.json; relocate the AUDIT file; createexamples/*. - Phase 1's gate goes green. Ships independently; package is now PII-free but still pre-Constitution.
Phase 3 — Extract L0 by subtraction
- Create
defaults/CONSTITUTION.md(gates one place, §1.4 split, capability-verb authored, precedence verbatim, firewall rule, tier-aware self-load). - Gut
defaults/AGENTS.mdto the ~50-line dispatcher; remove the false line 11. - Create
constitution/LAYER-MODEL.md. Strip restated policy fromSTANDARDS.md+ the four RUNTIME files; rewrite the sequential-thinking lines to capability verbs. - Add the L0 line-count CI ceiling over framework-owned resident files only (§7).
- Ships independently; no install/migration changes yet — fresh installs get the new structure.
Phase 4 — Overwrite semantics + migration + headless bootstrap
- Split seed lists into
FRAMEWORK_OWNED(overwrite) vsUSER_SEEDED(seed-if-absent) in BOTH installers; removeAGENTS.md/STANDARDS.mdfromPRESERVE_PATHS; addCONSTITUTION.md. - Implement snapshot→sync→restore; vendor the v2 baseline; v2→v3 migration moves user edits to
.local/.bak. BumpFRAMEWORK_VERSION=3. install.shrunsmosaic-init --non-interactive(fail-closed persona).- Land the shared fixture suite (§3.4) run against both installers. Gates the tag.
Phase 5 — Overlay composer + cross-harness composer test
- Build
mosaic compose-contract <harness>per §3.2 (SOUL.local.md+USER.local.md+STANDARDS.local.md; per-harness emission; documented bare-launch base-only behavior). - Composer unit test (§5): per-tier anchor present; Tier-3 byte-equal to L0.
- Ships independently as "customization now survives upgrades."
Phase 6 — Docs, compliance matrix, alpha tag
CONTRIBUTING.md(operator-hygiene, dual-installer parity rule, known-limitations §9, harness×gate compliance matrix with the hook-parity gap marked).- PRD ↔ design reconciliation; tag the alpha after the full DoD (§8) is green.
7. Resident-token budget (steward RISK / contrarian R5 / devex m8 — accepted, re-scoped)
Budget the container by line count, keep gate wording intact. But CI cannot see user-generated
SOUL.md/USER.md, and the resident set varies per harness tier (contrarian R5). So the control is
split:
- CI (package-side): a line-count ceiling over framework-owned resident files only
(
CONSTITUTION.md+ dispatcherAGENTS.md+ the residentRUNTIME.mdslice). Real and enforceable. mosaic doctor(runtime advisory): sums the actual composed prompt — includingSOUL.md/USER.mdand the per-harness tier — and warns the operator. This is the only place the total resident budget is visible, and it is per-harness, not a single global number (devex m8: hook-less harnesses like Pi need more resident, so the advisory threshold is per-harness).
Gates keep full wording; procedure (wrapper paths, flags) moves to on-demand E2E-DELIVERY.md.
Reject "exactly 500 words for L0" — gate #13 alone is ~110 words; a word cap forces paraphrasing law,
the exact drift vector being killed.
8. Alpha Definition of Done (for the PRD)
Blocking, all CI-green: MIT LICENSE + package.json field; three credential-path sites + the hook
URL fast-failed; verify-sanitized.sh (two-class, *.sh+*.md, self-tested) wired blocking;
operator data purged from the full set (guides/tools/init-generator included); rails/→tools/ in
both template families; defaults/SOUL.md+jarvis-loop.json deleted; CONSTITUTION.md extracted
(gates one place, capability-verb, §1.4 split, no false "already loaded"); AGENTS.md/STANDARDS.md
out of PRESERVE_PATHS and seed-semantics switched to overwrite in both installers; snapshot/
migration v2→v3 moving user edits to .local/.bak; mosaic-init --non-interactive fail-closed
persona; 5-fixture matrix (§3.4) green against both installers asserting injected bytes;
compose-contract built + composer unit test (per-tier anchor, Tier-3 byte-equality); resident
line-count ceiling enforced; CONTRIBUTING.md + compliance matrix; tag the alpha. PRD precedes
implementation.
Deferred to v2 (explicit): constitution/ deploy directory; adapters/<h>.capabilities.json;
3-way merge; live-launch cross-harness smoke test; policy/*.md composition; per-layer version stamps
as a migration driver; DCO CI.
9. Red-Team Disposition (every finding mitigated or accepted)
| Finding | Disposition |
|---|---|
| contrarian R1 / steward RISK-04 — "remove from PRESERVE_PATHS" doesn't update resident root file | Mitigated §3.1: split seed lists, unconditional overwrite for framework-owned, in BOTH installers; test injected bytes |
| contrarian R2 — snapshot/restore described but unimplemented; cp-fallback can lose data | Mitigated §3.3: atomic snapshot→sync→restore + interrupt fixture; user-edited AGENTS.md→.pre-constitution.bak |
| contrarian R3 / steward RISK-11 — live-launch smoke test impractical | Mitigated §5: re-scoped to composer unit test; live-launch → v2; hook-parity tracked in compliance matrix |
contrarian R4 / devex B1 — deleting defaults/SOUL.md + interactive init bricks headless first-run |
Mitigated §3.3: checkSoul() self-heals mosaic launches; install.sh runs --non-interactive init; fixture 4 |
| contrarian R5 / devex m8 — line budget can't see user files / varies per tier | Mitigated §7: CI ceiling on framework files only; doctor per-harness runtime advisory |
| contrarian R6 — extracting gate #13 weakens a hard gate for non-adopters | Mitigated §1.4: split #13 — disambiguation stays universal in L0; only the named delegation leaves |
| contrarian R7 / devex B3 / steward RISK-03 — denylist false-positives / misses the class | Mitigated §4.1-4.2: two rule-classes (structural + labeled denylist); L0 prose firewall is the primary class-closer |
| contrarian R8 / steward RISK-06 / devex M6 — compose-contract is a new subsystem called "zero" | Accepted + scoped §3.2: alpha-blocking work item with tests; policy/ composition deferred to v2 with rationale |
| contrarian R9 / steward RISK-07 — conditional self-load asks model to introspect | Mitigated §1.6: Tier-3 read is unconditional; conditional only on Tier-1 |
| contrarian R10 — two installers synced by a comment, TS path ignored | Mitigated throughout: every mechanism "in both installers, one shared fixture suite" |
| devex B2 — non-interactive init ships "Assistant" + Jarvis role | Mitigated §2b/§3.3: fail-closed persona; grep init defaults |
devex B3 / steward RISK-01 — credential leak in 6+/3 files, grep misses tools/+*.sh |
Mitigated §2b/§4.1: all three *.sh sites + hook URL; grep scoped to tools/ and *.sh |
| devex M4 — Tier-3 paraphrase = two "Mosaics" | Mitigated §5: Tier-3 anchor is a literal L0 substring; byte-equality asserted |
| devex M5 / steward RISK-05 — pulling from PRESERVE clobbers existing edits; non-TTY false-green | Mitigated §3.3/§3.4: vendor v2 baseline, extract delta→.local before overwrite; fixtures pin MOSAIC_INSTALL_MODE |
| devex M7 — sequential-thinking contradiction in 4 files; L0 "else stop" halts Pi | Mitigated §5/§4.1: rewrite all 4; L0 capability-verb only; structural CI rule + Pi fixture |
devex m9 — doctor drift advisory absent on bare launches |
Accepted §3.5: documented limitation; self-load nudge |
devex m10 / steward RISK-08 — CLAUDE.md.template siblings keep rails/ + gates |
Mitigated §2b: both template families; CI /rails/ rule over templates/ |
| devex m11 — dead-path/legacy-term sanitization is one-off | Mitigated §4.1: structural rules close the dead-path class |
steward RISK-02 — verify-sanitized.sh doesn't exist / unwired |
Mitigated §2a/§4.1/Phase 1: built, self-tested, wired blocking |
| steward RISK-09 — "Master/slave" framing | Mitigated §2b: → "Primary / satellite" |
| steward RISK-10 — no LICENSE | Mitigated Phase 0 |
Accepted residual risks (stated in CONTRIBUTING.md): bare-launch overlay no-op (base-only) and
bare-launch drift-undetected-by-doctor — both inherent to launches that bypass mosaic; mitigated
by the unconditional Tier-3 self-load + nudge, not eliminated. Codex/OpenCode hook parity is a tracked
v2 gap. Live-launch cross-harness verification is v2.