Files
stack/docs/design/framework-constitution/synthesis-v1.md
Jason Woltje c70b217a5c
Some checks failed
ci/woodpecker/push/ci Pipeline failed
docs(design): mosaic framework constitution — expert conference output
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>
2026-06-15 23:47:49 -05:00

33 KiB
Raw Blame History

Mosaic Framework Constitution — Synthesis v1 (Chief Architect Ruling)

Status: Canonical design. Resolves the seven-position debate (debate/position-*.md, debate/rebuttal-*.md) against the BRIEF (BRIEF.md) and the real framework tree at packages/mosaic/framework/. This document is the single design of record for the alpha. A PRD derives from it; implementation derives from the PRD.

Author: Neutral Chief Architect. Scope: DQ1DQ5 of the BRIEF, plus the two release-blockers the debate surfaced outside the DQ frame (LICENSE, hardcoded credential path).


0. Where the conference actually converged

Seven lenses, near-unanimous on the easy 80%. I am banking the consensus as settled and spending the ruling on the contested 20%.

Settled (all or nearly all papers agree — adopted without further debate):

  1. Introduce an explicit Constitution layer (framework-owned, immutable law) distinct from persona (SOUL) and operator profile (USER). (every paper)
  2. Split content by ownership × upgrade-fate × residency, not by topic. (architect §1.2, devex DQ1, aiml DQ1, coder DQ1, contrarian DQ1)
  3. Delete defaults/SOUL.md (the "Jarvis"/"PDA" file). Persona ships only as templates/SOUL.md.template, generated at init. install.sh:232-241 already refuses to seed it. (every paper)
  4. Subtraction before structure: create the Constitution by extraction and deletion, never by addition. A fifth restatement on top of four existing ones yields five disagreeing law files. (contrarian, endorsed in every rebuttal)
  5. A blocking CI grep for personal data + dead paths is the only durable anti-regression control. (every paper)
  6. "Hooks are the real enforcement; prose is the spec" — promote the repo's own prevent-memory-write.sh lesson (runtime/claude/RUNTIME.md:30-32) to Constitution doctrine. (devex DQ4, contrarian DQ5, aiml §1.2, coder, steward, moonshot)
  7. Remove framework-owned files from PRESERVE_PATHS so gate updates reach existing installs. (every paper — this is the literal drift bug)
  8. An enforced resident-token budget, or the new Constitution re-bloats into the old 155-line AGENTS.md within two releases. (aiml DQ5, endorsed by devex, coder, moonshot, contrarian)
  9. Fix the false defaults/AGENTS.md:11 claim ("already in your context… do not re-read") — it is provably false on a bare claude launch and teaches agents to skip the gates. (coder, contrarian, devex, aiml, moonshot)

Verified live facts (I re-ran the greps, did not trust the papers):

  • tools/_lib/credentials.sh:19 AND tools/git/detect-platform.sh:89 both default to $HOME/src/jarvis-brain/credentials.json — a private path shipped as an executable default.
  • mosaic/rails/git/ appears in 12 shipped template files (all of templates/agent/ + projects/*), while defaults/AGENTS.md:30 uses tools/git/ and install.sh:192-194 actively deletes a stale rails symlink. A dozen templates emit a command pointing at a path the installer removes.
  • No LICENSE at monorepo root, packages/mosaic/framework/, or as a package.json field.

Contested 20% (resolved in the Decision Records, §3): number of layers; physical-directory split vs flat files; one Constitution file vs a constitution/ directory; 3-way merge vs .local overlays; YAML front-matter + hash-refusal vs structural enforcement; capability-manifest JSON vs prose table; injection-by-value vs self-load.


1. The Canonical Layer Model

Five concerns, collapsed into four owned layers plus a non-resident governance spec. The collapse resolves the architect-vs-contrarian layer-count fight: the architect's "Standards" and "Operator Policy" are real concerns but do not earn separate sovereign documents — Standards is framework law that a deployment tightens via an additive overlay; Operator Policy is a section of USER plus optional policy/ example files. (Decision D1, D2.)

A layer boundary is legitimate iff the two sides differ in owner, upgrade-fate, OR residency. This single test (architect §1.2, banked by every rebuttal) does all the work.

# Layer Owns Owner Upgrade fate Residency Canonical deployed path
L0 Constitution Irreducible non-negotiable law: hard gates, escalation triggers, block-vs-done, mode declaration, precedence rule, the "hooks are the gate" doctrine, the "no operator context in framework PRs" rule Framework Overwritten wholesale every upgrade. Never in PRESERVE_PATHS. 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, the E2E procedure, QA matrix, orchestrator protocol, all guides/* Framework (deployment may tighten via overlay) Overwritten; user delta lives in STANDARDS.local.md / never edits guides STANDARDS.md resident; guides/* on-demand ~/.config/mosaic/STANDARDS.md, ~/.config/mosaic/guides/*
L2 Persona (SOUL) Agent name, tone, role, communication style, persona-scoped 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/accommodations, comms prefs, projects, operator policy (e.g. merge-authority delegation), operator tool paths 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 config, MCP wiring, injection tier) Repo / framework Project file user-owned; runtime mechanism overwritten Project loaded in-repo; runtime resident, ~15 lines <repo>/AGENTS.md, ~/.config/mosaic/runtime/<h>/RUNTIME.md
Layer-Model spec (governance) The definition of these layers + precedence + "what may live in L0" Framework maintainers Source-only, never deployed Not resident packages/mosaic/framework/constitution/LAYER-MODEL.md

AGENTS.md (deployed) is not a layer — it is the thin load-order dispatcher + Conditional Guide Loading table that routes to L0L4. It is framework-owned and overwritten on upgrade.

Precedence — typed two-axis, not a flat stack

A flat "L0 > L1 > L2 > L3" ordering is a trap (contrarian DQ1, devex DQ1): persona and law are not on the same axis. The governing rule, stated verbatim in L0, in one sentence each:

Safety axis (gates, integrity, destructive actions): L0 Constitution is supreme. Nothing in STANDARDS, SOUL, USER, policy/, project AGENTS.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.

This generalizes the two good instincts already half-present in the tree (SOUL.md:48, injected reminders never expand permissions; SOUL.md:32, user formatting wins) and makes precedence total and one-sentence-holdable rather than scattered across runtime files. (D3.)

Enforcement strength is ranked, not chosen

Resolving the conference's central fault line (injection-by-value vs self-load vs metadata-gate): the three are not alternatives — they are a priority ladder (aiml §3, devex §3, architect §3, coder, contrarian):

mechanical (hook/CI)  >  resident-by-value (system-prompt injection)  >  file-read (self-load fallback)
  1. 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-template-tokens). A hook does not compete for attention or care about injection tier. This drains prose out of the resident core, which is the precondition that makes the next tier work.
  2. Resident-by-value second. The irreducible non-checkable gates (the ones governing when the agent stops — block-vs-done, escalation, completion-definition) are injected by value at primacy on the strongest channel each harness offers, restated as a ≤5-bullet anchor at the recency position (bottom).
  3. File-read third (fallback). AGENTS.md says: "If CONSTITUTION.md is not already in your context, READ IT NOW." — conditional, never the false unconditional "already loaded." This is the safety net for harnesses/launches where injection silently failed; it is explicitly the weakest tier, never the primary mechanism.

2. File-by-File Plan (what content moves where)

2a. New files

New file Content Source of content
~/.config/mosaic/CONSTITUTION.md (ships as defaults/CONSTITUTION.md) L0, one flat file, ~7090 lines. The 13 hard gates minus the operator-policy clause (see below); the 5 escalation triggers; block-vs-done; mode declaration protocol; the one-sentence precedence rule (both axes); the "hooks are the gate" doctrine; the "no operator context in framework PRs" rule; a single pointer line to the guide index. Gates keep full unambiguous wording; procedure (wrapper paths, flags) moves to L1. Extracted from defaults/AGENTS.md:23-87
packages/mosaic/framework/constitution/LAYER-MODEL.md The §1 layer model + precedence + "what may live in L0" governance spec. Source-only, never deployed, never resident. This document
packages/mosaic/framework/examples/personas/execution-partner.md The sanitized, placeholdered essence of the Jarvis persona (a worked example, copied on request, never auto-loaded) defaults/SOUL.md (sanitized)
packages/mosaic/framework/examples/overlays/e2e-loop.json The sanitized, placeholdered essence of jarvis-loop.json (~/src/<your-project> placeholders) runtime/claude/settings-overlays/jarvis-loop.json
packages/mosaic/framework/examples/policy/merge-authority.example.md The operator-policy merge-authority decision, as an example operator policy a deployment may adopt defaults/AGENTS.md:37 ("Policy: Jason, 2026-06-11")
LICENSE (monorepo root) + packages/mosaic/framework/LICENSE MIT license text new (D8)
CONTRIBUTING.md (framework package) Layer model, PII/secrets prohibition, the dedup rule, how to add a harness adapter, the re-contamination rule new (D8)
tools/quality/scripts/verify-sanitized.sh The blocking CI grep (PII + home paths + dead rails/ + unrendered tokens) new (D6)

2b. Files that shrink / change role

File Change Why (DQ)
defaults/AGENTS.md Gut from 155 lines to a ~50-line dispatcher: load order + Conditional Guide Loading table + the self-bootstrapping "read CONSTITUTION.md if not resident" line. Zero restated gates. Remove from PRESERVE_PATHS. DQ1, DQ5
defaults/STANDARDS.md Stays L1, but: drop the "Master/slave model" framing (line 5); stop re-asserting gates that now live in L0; end with an additive include convention for STANDARDS.local.md. Remove from PRESERVE_PATHS. DQ1, DQ3, DQ5
defaults/TOOLS.md Delete the jarvis-brain MANDATORY rule (line 40). Generic tool index only; operator-specific rules move to the operator's USER.md/project AGENTS.md. DQ2
templates/SOUL.md.template Already clean and correct. Keep. Ensure every {{TOKEN}} has a non-empty default in mosaic-init (no placeholder can survive into a resident file). DQ2
templates/agent/AGENTS.md.template (+ 11 sibling/project templates) Delete the restated Hard-Gates block. Replace with one line: "This project is governed by ~/.config/mosaic/CONSTITUTION.md. Add only project-specific extensions below." Fix all rails/git/tools/git/. DQ4, DQ5
runtime/{claude,codex,pi,opencode}/RUNTIME.md Strip restated policy (wrappers-first, mode declaration, caution-doesn't-override-gates). Reduce to harness mechanism only + a one-line reference to CONSTITUTION.md. DQ4, DQ5
tools/_lib/credentials.sh:19, tools/git/detect-platform.sh:89 $HOME/src/jarvis-brain/credentials.json${MOSAIC_CREDENTIALS_FILE:?MOSAIC_CREDENTIALS_FILE must be set} (fast-fail, consistent with the framework's own STANDARDS.md:35 ban on ${VAR:-default} for required values). Document the env var in USER.md.template under ## Tool Paths. DQ2 (blocker)
guides/ORCHESTRATOR.md (lines 99,111,152), guides/TOOLS-REFERENCE.md, guides/BOOTSTRAP.md Replace jarvis-brain/docs/templates/ with ~/.config/mosaic/templates/ (the canonical install path). DQ2

2c. Files deleted / moved out of the shipped package

File Action Why
defaults/SOUL.md Delete. Persona is generated at init from the template only. Primary contamination vector
runtime/claude/settings-overlays/jarvis-loop.json Delete; sanitized essence → examples/overlays/e2e-loop.json Personal project map
defaults/AUDIT-2026-02-17-framework-consistency.md Move to docs/ at monorepo root (maintainer artifact, not agent context) Not framework content

3. Decision Records

Each contested question, resolved with Decision / Rationale / Rejected.

D1 — Layer count: four owned layers (+ a non-resident spec), not five, not three

  • Decision: L0 Constitution / L1 Standards+Guides / L2 Persona / L3 Operator / L4 Project+Runtime. "Operator Policy" is a section of L3 (USER) plus optional policy/*.md, not a fifth sovereign layer.
  • Rationale: The owner×fate×residency test legitimizes splitting law from persona from operator (so the "Policy: Jason, 2026-06-11" clause at defaults/AGENTS.md:37 must leave L0 — different owner, different upgrade-fate). But it does not legitimize a standalone policy/ layer: no paper named a failure mode that "USER.md has a ## Operator Policy section" cannot handle (steward §2b). Three layers (contrarian/coder) under-serves the merge-authority extraction; five (architect) re-creates the very AGENTS.md/STANDARDS.md overlap that already drifts (contrarian §2c). Four is the count where every boundary passes the test and none is gratuitous.
  • Rejected: Architect's five layers (Standards + Operator-Policy + Deployment as separate sovereigns) — taxonomy inflation; more documents to keep non-duplicative is the disease, not the cure. Contrarian/coder's strict three — loses the operator-policy seam the merge-authority leak proves is needed.

D2 — One flat CONSTITUTION.md, not a constitution/ deploy directory

  • Decision: L0 deploys as a single flat file ~/.config/mosaic/CONSTITUTION.md. The constitution/ directory exists only in the package source, holding the non-deployed LAYER-MODEL.md governance spec.
  • Rationale: A directory of GATES.md+DELIVERY.md+… multiplies load-order failure points — on a weak-injection harness an agent can load file 1, get pulled into the task, and operate with incomplete gates (coder §3, devex "load-order indirection"). You can anchor a file at primacy+recency; you cannot anchor a directory (aiml). One file is injected/read whole and is impossible to partially load. The separation-of-concerns the directory camp wants is real but is a post-alpha evolution target, triggered only if L0 exceeds its budget.
  • Rejected: Architect/steward/moonshot constitution/ deploy directory — correct intuition, wrong alpha granularity; reserve for v2.

D3 — Precedence is structural (placement + overwrite + hooks), not metadata/hash-enforced

  • Decision: Enforce L0 supremacy and immutability through (a) directory/overwrite mechanics — L0 is overwritten wholesale every upgrade, so a user edit simply does not survive; (b) placement — L0 at primacy, ≤5-bullet anchor at recency, SOUL/USER in the low-attention middle; (c) hooks/CI for every checkable gate. No YAML front-matter, no content-hash launch gate.
  • Rationale: Front-matter (mosaic-layer: 0, mosaic-override: forbidden) spends the single most valuable primacy-position attention slot on key-value pairs whose audience is a bash script, and teaches the model that override-rules are parseable properties — an injection surface (aiml §2.1, steward §2a, coder §2b, devex §2a). Hash-refusal-on-launch is invisible on the exact direct-launch paths where drift happens (it only runs inside mosaic <harness>), bricks the one user who customized, and false-positives on every mid-upgrade state and CRLF/trailing-newline diff (every rebuttal rejected it). Immutability-by-overwrite needs zero hashes: overwrite is the guarantee.
  • Rejected: Moonshot's front-matter + "launcher refuses to start on hash mismatch"; steward's --check-constitution-as-error. A post-hoc advisory mosaic doctor drift warning (never a launch block, never on model-visible bytes) is acceptable and kept.

D4 — Upgrade-safe customization = additive .local overlays, not 3-way merge

  • Decision: Framework-owned files (L0, L1 STANDARDS.md+guides/*, AGENTS.md, runtime) are overwritten wholesale on upgrade. User customization that must survive lives in never-touched additive overlays: SOUL.local.md, USER.local.md, STANDARDS.local.md, optional policy/*.md. One overlay mechanism, owned by the launcher/composer, resolved before injection — not a per-guide variant, not an inert <!-- mosaic:include --> comment. TOOLS.md (generated then hand-tuned) is the one file that may keep the existing .bak.<ts> backup-on-regenerate behavior.
  • Rationale: The directory/overwrite split makes 3-way merge unnecessary — there is nothing to merge when framework files are clobbered and user deltas are separate (architect §2.2, contrarian §2a). Markdown has no merge semantics: git merge-file resolves by line, so a reflowed paragraph produces phantom conflicts, and a half-resolved merge can leave <<<<<<< markers inside the agent's resident identity file — the same erratic-behavior class as a half-rendered {{TOKEN}} (aiml §2.3, moonshot §1). A 3-way merge also needs a base that no current install has (contrarian §2a) — most fragile exactly at the alpha boundary the BRIEF says must not break. Interactive merge prompts hang headless launches. The three papers that invented different overlay schemes (coder per-guide, aiml/devex per-layer, contrarian include-comment) must converge: devex (§2b) correctly rules that per-layer overlays composed by the launcher is the only one that does not silently no-op on a pointer harness.
  • Rejected: Architect/devex 3-way mosaic-reconcile; moonshot interactive [Y/n] auto-merge; contrarian's inert include-comment; coder's per-guide .local.md (guides are L1, referenced not forked). Per-layer template-version markers survive only as a doctor advisory signal ("your SOUL was generated from template v2; v4 ships — review examples/"), never as a merge trigger.

D5 — Cross-harness: single L0 source + capability-resolved adapters + tiered injection + a smoke test

  • Decision: L0 is one canonical text. Adapters carry mechanism only. The Constitution speaks in capability verbs ("use structured reasoning before planning"); each harness adapter binds the verb to a concrete tool and declares whether absence is a hard stop. For the alpha, that binding is a single markdown table in the adapter docs (not a JSON manifest). Injection is tiered and honest about asymmetry: Tier-1 (system-prompt append: Pi, mosaic claude/codex) injects L0 by value; Tier-3 (bare claude/codex/opencode pointer) carries the ≤5-bullet irreducible-gate summary inline plus the read instruction. A CI smoke test launches each harness path and asserts the irreducible gates are present in the effective context — the control that makes "enforced across harnesses" true rather than aspirational.
  • Rationale: The four harnesses genuinely do not inject symmetrically (devex §3, verified: adapters/pi.md:14-16 system-prompt; Claude append-or-pointer with competing harness <system-reminder>s; Codex/OpenCode instructions-file). "Byte-for-byte everywhere" is an aspiration, not a switch. The capability-verb split kills the already-live contradiction — defaults/AGENTS.md:143 says sequential-thinking MCP is REQUIRED-or-stop, while adapters/pi.md says native thinking replaces it (aiml §1.3). But a bespoke capabilities.json schema + validator for a four-row, three-axis table is over-engineering at alpha (coder §2c, contrarian §2c): a markdown table conveys the same and catches errors at review time. The JSON manifest is a good v2 evolution once there are 6+ harnesses.
  • Rejected: Devex's adapters/<h>.capabilities.json machine-read manifests for the alpha (kept as a v2 roadmap item); moonshot's "Pi is the reference harness" (inverts single-source-of- truth — defines abstract law in terms of one runtime's affordances; architect §2.3). Moonshot's COMPLIANCE.md harness×gate matrix as documentation is kept (good for visibility); machine-read- and-enforced is not.

D6 — Sanitization: per-layer strategy + a blocking CI gate that closes the class, not the tokens

  • Decision: Per-layer, not one global choice (contrarian DQ2): L0/L1 ship generic-and-complete (law has no PII once leaks are removed; empty law = no gates = dangerous); L2/L3 ship as templates only, generated at init (delete defaults/SOUL.md); examples/ ship the worked Jarvis config sanitized + placeholdered (~/src/<your-project>), copied on request, never auto-loaded. The blocking CI gate (verify-sanitized.sh) fails the build on the structural class, not just current tokens: jarvis|jason|woltje|\bPDA\b, plus ~/src/<word> / /home/<word>/ absolute home paths, plus dead /rails/ tokens, plus unrendered {{...}}/${...} in resident files — over defaults/ guides/ templates/ runtime/ adapters/, excluding examples/.
  • Rationale: The contamination reached ~2955 files because defaults/README.md:7's prose promise has no enforcement; a CI grep is ~15 lines and is the only durable control (every paper). It must close the class because the primary author of future framework PRs is an agent running with some operator's SOUL/USER in context — a denylist of today's tokens won't catch tomorrow's operator (steward §3, moonshot "biggest risk"). The unrendered-token check closes the half-rendered-template failure class (aiml §2.2): a SOUL.md containing You are **{{AGENT_NAME}}** makes the model adopt the literal braces.
  • Rejected: Generic-defaults for persona (recreates the bug — "Assistant" becomes the new "Jarvis"; devex DQ2); empty-defaults for persona (terrible first-run); prose-only sanitization (already proven to decay).

D7 — Resident-token budget: budget the container by line count, keep gate wording intact

  • Decision: Enforce a resident line-count ceiling in CI + mosaic-doctor over the always-resident set (CONSTITUTION.md + AGENTS.md index + SOUL.md + USER.md + the resident RUNTIME slice). Budget the container, not the constitution's clarity. Gates keep full unambiguous wording; procedure (wrapper paths, --purpose flags) moves to on-demand E2E-DELIVERY.md.
  • Rationale: A new top-level CONSTITUTION.md is psychologically tempting to fill and will re-bloat to 155 lines within two releases without a mechanical forcing function (aiml "biggest risk," moonshot §1). But moonshot's "exactly 500 words" is asserted, not derived, and is self-defeating: gate #13 alone is ~110 words, so a 500-word cap forces paraphrasing the gates — paraphrased law is the exact drift vector we are killing (aiml §2.2). Budget the resident set by line count (the mechanism several papers converge on); let each gate keep its wording; push procedure to guides.
  • Rejected: Moonshot's "exactly 500 words for CONSTITUTION.md" — right instinct, wrong unit; forces lossy compression of normative text.

D8 — Two non-DQ release blockers ship in the alpha DoD: LICENSE and the credential path

  • Decision: Add MIT LICENSE (monorepo root + framework package) + "license": "MIT" in package.json, on day zero. Fix both hardcoded $HOME/src/jarvis-brain/credentials.json defaults to fast-fail env vars. Ship CONTRIBUTING.md (with the operator-data-hygiene section) with the alpha, not deferred.
  • Rationale: "Public does not mean licensed" — under Berne, an unlicensed public repo is all-rights-reserved, so every fork/contribution has unclear IP status, and retroactively licensing after the alpha creates ambiguity about the pre-license period (steward, the only paper to surface this; endorsed by architect §1.3, devex §1c). A hardcoded private credential path shipped as an executable default is worse than the persona contamination — it is in the tooling layer and it is runnable. MIT maximizes adoption and signals genuine open infrastructure.
  • Rejected: Deferring LICENSE/CONTRIBUTING to "pre-stable" — the alpha will have downstream users; the window to fix legal status cleanly closes at the alpha tag. AGPL/Apache considered; MIT chosen for adoption (revisitable, but pick one now).

4. Sanitization plan for the public package

Ships generic (PII-free, complete, in the package): defaults/CONSTITUTION.md, defaults/AGENTS.md (dispatcher), defaults/STANDARDS.md, defaults/TOOLS.md (generic index), all guides/* (purged), templates/* (token-only), examples/* (placeholdered worked configs), runtime/*/RUNTIME.md (mechanism-only), adapters/*.md, LICENSE, CONTRIBUTING.md.

Generated at mosaic init (never in the package, gitignored downstream): ~/.config/mosaic/SOUL.md, USER.md, TOOLS.md (rendered from templates), *.local.md overlays, optional policy/*.md, per-harness runtime copies.

Deleted / relocated from the shipped tree: defaults/SOUL.md (delete); runtime/claude/settings-overlays/jarvis-loop.json (delete → examples/overlays/); defaults/AUDIT-2026-02-17-*.md (move to monorepo docs/).

Mechanical gate (the durable control): tools/quality/scripts/verify-sanitized.sh, wired into .woodpecker.yml, blocking. Fails on: operator tokens; absolute home paths (~/src/<word>, /home/<word>/); dead /rails/ paths; unrendered {{...}}/${...} in resident files. Excludes examples/. Plus a structural-firewall L0 rule: "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 in policy/ or a project AGENTS.md, not the framework."


5. Customization + upgrade-safety mechanism

The single sentence a user can now truthfully 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. Want to change framework behavior? Add a .local.md overlay or a policy/ file (tighten-only)."

Mechanism:

  1. Physical seam = ownership. Framework-owned files are overwritten wholesale (rsync without an exclude); user-owned files (SOUL.md, USER.md, *.local.md, policy/, TOOLS.md, memory, sources, credentials) are the only PRESERVE_PATHS entries. Remove AGENTS.md and STANDARDS.md from PRESERVE_PATHS — this single change makes gate updates reach every existing install (the literal drift bug, contrarian §0/§3).
  2. Additive overlays, launcher-composed. mosaic compose-contract <harness> concatenates, in precedence order, base + .local deltas before injection, so the model receives one pre-merged blob and never runs a redundant read-merge ritual. (D4.)
  3. One global FRAMEWORK_VERSION integer + linear migrations (the existing install.sh:160-202 scaffold). No per-layer version matrix — it is a combinatorial test cliff no single maintainer will cover (contrarian, steward §2b). Per-layer template versions survive only as a doctor advisory.
  4. Migration v2→v3 (backward-compatible, the BRIEF's hard constraint):
    • Snapshot ~/.config/mosaic/~/.config/mosaic/.backup-v2/ before touching disk.
    • Install CONSTITUTION.md as a new file nothing previously owned (avoids the reclassification catastrophe moonshot §2 flags — we do not try to diff/split a user-edited flat AGENTS.md into "framework vs user" content).
    • Install the slimmed AGENTS.md dispatcher; remove AGENTS.md/STANDARDS.md from PRESERVE_PATHS going forward.
    • The agent self-loads L0 from AGENTS.md regardless of launcher injection (the self-bootstrap fallback), so even a stale-pointer install gets the gates.
  5. The migration is the biggest risk; gate it with a falsifiable test matrix (contrarian §3, the decider, not a mitigation). Alpha cannot tag until three fixtures pass with no interactive prompt, no hang: (1) fresh install; (2) legacy-flat user-edited install — law moves, user files survive; (3) user-tuned-standard install — change survives as STANDARDS.local.md, framework STANDARDS.md updates. Smallest design that passes all three wins (it does: rsync + linear migration + overlays + a 15-line grep — zero new subsystems).
  6. Detection without enforcement: mosaic doctor reports drift/unrendered-tokens/budget-overflow as advisories (warn, never block launch). --check-constitution is an opt-in diagnostic, not a gate (D3).

6. Cross-harness strategy (single source of truth + adapters)

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 (kills the four-way duplication and the live rails/-vs-tools/ + sequential-thinking-except-Pi contradictions).

Adapter contract (mechanism only): an adapters/<h>.md / runtime/<h>/RUNTIME.md may specify only (a) the injection channel + tier this harness uses, and (b) how L0's capability verbs map to concrete tools (subagent syntax, MCP wiring, hook config). The Constitution says "use structured reasoning before planning"; the Claude adapter binds it to mcp:sequential-thinking (gate=true), the Pi adapter to native thinking (gate=false). For the alpha this binding is a markdown table; JSON manifests are a v2 item once 6+ harnesses exist.

Tiered, honest injection (the four harnesses are not symmetric):

Harness Channel Tier L0 delivery
Pi --append-system-prompt (+ no hook backstop) 1 By value at primacy; keep L0 tiny — resident fidelity is Pi's only enforcement
mosaic claude / mosaic codex system-prompt append 1 By value at primacy + ≤5-bullet recency anchor
Codex / OpenCode (instructions-file) written file 2 Resident-ish; self-load line as backup
bare claude/codex/opencode thin pointer 3 Pointer carries the ≤5-bullet gate summary inline + "READ CONSTITUTION.md NOW" — never the false "already loaded"

Mechanical backstop: every hookable gate is a hook where the harness supports one (prevent-memory-write.sh precedent); Codex/OpenCode hook parity is a tracked gap in the compliance doc, not a silent inconsistency. A CI smoke test asserts the irreducible gates are resident on every harness path — the control that makes the cross-harness claim true.


7. Alpha Definition of Done (derived, for the PRD)

Blocking: MIT LICENSE + package.json field; credential-path fast-fail fix; defaults/SOUL.md + jarvis-loop.json deleted; rails/tools/ fixed in 12 templates; verify-sanitized.sh green and wired to CI; CONSTITUTION.md extracted (gates one place, dispatcher AGENTS.md self-bootstraps); AGENTS.md/STANDARDS.md out of PRESERVE_PATHS; resident line-count budget enforced; per-layer overlay + compose step; migration v2→v3 passing the 3-fixture matrix with no hang; cross-harness smoke test green; CONTRIBUTING.md with operator-hygiene section; tag the alpha. PRD precedes implementation.

Explicitly deferred to post-alpha (v2): constitution/ deploy directory; adapters/<h>.capabilities.json JSON manifests; 3-way merge reconciliation; per-layer version stamps as a migration driver; DCO CI.