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

427 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.