docs(design): mosaic framework constitution — expert conference output
Some checks failed
ci/woodpecker/push/ci Pipeline failed

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>
This commit is contained in:
2026-06-15 23:47:49 -05:00
parent d481a74a86
commit c70b217a5c
22 changed files with 5822 additions and 0 deletions

View File

@@ -0,0 +1,426 @@
# 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.