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,281 @@
# Rebuttal — Cross-Harness DevEx Lens
**Author lens:** Cross-Harness DevEx Expert — Claude Code / Codex / Pi / OpenCode injection + tool
differences; owns portability and the end-user customization experience.
**Method:** Read all seven position papers (`position-{aiml,architect,coder,contrarian,devex,moonshot,steward}.md`)
and re-verified every load-path / injection / install claim against the real tree under
`packages/mosaic/framework/`. This rebuttal does not restate my opening paper; it adjudicates the
*others* from the one seat that actually has to make the contract land identically on four harnesses
that inject context in three incompatible ways.
The conference has near-unanimous consensus on the easy 80% (split out an L0 Constitution by
ownership/mutability; delete `defaults/SOUL.md`; ship a CI PII gate; kill the `rails/``tools/` path
drift; budget the resident core). I will not relitigate that — it's settled, and I agree. The
remaining 20% is where the design actually lives or dies, and it is almost entirely **my lane**:
*how does L0 reach the model, and what happens when it doesn't.* Three of the six other papers get
that question subtly but dangerously wrong.
---
## 1. The 23 strongest ideas from other personas worth keeping
### 1a. Coder's self-bootstrapping Constitution — the single best idea in the room, because it is the only one that survives a harness we don't control
`position-coder.md` §"Biggest Risk" and §"Single Strongest Recommendation" name the failure mode the
governance-first papers all skate past:
> "If `mosaic claude` composes a `--append-system-prompt` that includes AGENTS.md but not
> `constitution/CORE.md`, the hard gates are silently absent... The Constitution must not rely on the
> launcher getting the injection order right; it must be a file the agent is instructed to read
> regardless."
This is correct and it is *load-bearing for my entire lens*. Ground truth: today
`defaults/AGENTS.md:11` literally asserts *"The core contract is ALREADY in your context (injected by
`mosaic` launch). Do not re-read it."* — and that claim is **false on a bare `claude` launch**, where
the only artifact is the thin `~/.claude/CLAUDE.md` pointer (`runtime/claude/CLAUDE.md:12-13` admits
it is "only a fallback for direct `claude` launches"). An agent that trusts a false "already loaded"
assertion skips the read and runs ungoverned. The contrarian (`position-contrarian.md` DQ4 point 1)
independently flags the same line as "a behavior-degrading rule." Two lenses converging on the same
concrete bug means it's real.
**Keep:** L0 must be *both* injected by value *and* self-loadable by file-read instruction, and the
pointer must never claim residency it can't guarantee. Belt and suspenders, because on the harnesses I
own, the suspenders (injection) are not always wearable.
### 1b. AI/ML's resident-token budget as a CI-enforced wall, and the "physics" framing that justifies it
`position-aiml.md` is the only paper that treats *what the model can actually weight* as a first-class
constraint rather than an afterthought. Its DQ5 diagnosis — ~300+ resident lines / ~34K tokens of
"dense, imperative, partially-redundant, partially-contradictory law... including for `list the files
in this dir`" — is exactly right, and its mechanism (a non-advisory line-count assertion in
`mosaic-doctor` + framework CI) is the only proposal that stops the new `CONSTITUTION.md` from
re-bloating into the old 155-line `AGENTS.md`. Its closing line — *"Ship the budget gate in the same
alpha as the Constitution, or don't ship the Constitution"* — should be adopted verbatim as alpha DoD.
From the DevEx seat this matters doubly: the **weakest-context harness sets the ceiling for
everyone**. A budget that fits Pi's `--append-system-prompt` and Claude's window must also survive
Codex/OpenCode writing the same bytes to an instructions file the model may only skim. Budget
discipline is portability discipline.
### 1c. Steward's license + `credentials.sh` findings — the only papers-killing-shipping-blockers nobody else surfaced
`position-steward.md` §"The Missing License" and finding S6 (`tools/_lib/credentials.sh:19` hardcodes
`$HOME/src/jarvis-brain/credentials.json` as a default) are the two findings that, if missed, make the
*first public push itself* a hygiene incident regardless of how clean the layering is. No LICENSE = not
legally open source (Berne default: all rights reserved). A hardcoded private credential path shipped
as a default is worse than the SOUL contamination everyone fixated on, because it's executable and it's
in the *tooling* layer, not the persona layer. These are unglamorous and correct. Keep both as alpha
blockers.
---
## 2. The 23 weakest / riskiest proposals, with concrete failure modes
### 2a. Moonshot's machine-readable front-matter + "launcher refuses to start on hash mismatch" — over-engineered enforcement that breaks exactly the harnesses I own
`position-moonshot.md` DQ1 proposes YAML front-matter (`mosaic-layer: 0`, `mosaic-override: forbidden`)
on each deployed file, and a launcher that "reads these headers and refuses to start if a layer-0 file
has been structurally overridden (content-hash check against installed version)." `position-steward.md`
S11 proposes the cousin: `mosaic doctor --check-constitution` treating any deployed-file diff as "an
error, not a warning, because it means the hard gates may be compromised."
Concrete failure modes from the cross-harness seat:
1. **YAML front-matter is not free in resident context — it's noise injected into the prompt.** These
files are concatenated into the system prompt (`--append-system-prompt` on Pi/Claude; an instructions
file on Codex/OpenCode). A `---\nmosaic-layer: 0\nmosaic-owner: framework\nmosaic-override:
forbidden\n---` block at the top of the *highest-primacy position in the whole stack* spends the most
valuable attention real estate (aiml behavior #1, primacy) on metadata the model must parse and then
ignore. The framework's own best instinct is the opposite: `defaults/USER.md` leads with human-readable
prose, not machine front-matter. Machine-readable layer tags belong in a *manifest the launcher reads*,
never in the *text the model reads*. This is precisely the adapter-capability-manifest split I argued
for — keep machine metadata out of the model's eyes.
2. **"Launcher refuses to start on hash mismatch" makes the framework hostile and is trivially bypassed
on 3 of 4 harnesses anyway.** A user who adds one clarifying line to their deployed contract now
cannot launch. Worse: the hash check only runs inside `mosaic <harness>`. A bare `claude`, `codex`,
or `opencode` launch — which the framework explicitly supports via thin pointers — *never invokes the
launcher*, so the "refuse to start" gate is absent on every direct launch. You get a control that
punishes compliant `mosaic`-launch users and is invisible to exactly the unmanaged launches where
drift is most likely. That is enforcement theater with a usability tax.
3. **Treating any constitution-file diff as a violation collides with the upgrade model.** During a
v2→v3 migration the deployed file legitimately differs from "installed version" for a window. A
checksum-as-violation check will false-positive every mid-upgrade state and every legitimate
`MOSAIC_NO_SYMLINK` copy that differs by a trailing newline.
**Resolution:** enforce L0 immutability *structurally* (it lives in a framework-owned dir that is
overwritten wholesale on upgrade — architect/coder/steward all converge here) and *socially* (CI PII +
dead-path grep on the source repo). Drop the runtime hash-refusal. Detection (`mosaic doctor` reporting
drift as an *advisory*) is fine; *refusing to launch* is not.
### 2b. The proliferation of three mutually-incompatible "user overlay" schemes — a portability landmine if any one ships as-is
Three papers invented three *different* customization-survival mechanisms, and nobody noticed they
conflict:
- `position-coder.md` DQ3: per-*guide* `E2E-DELIVERY.local.md` siblings, with `AGENTS.md` instructing
"after loading any guide, check for a `.local.md` variant and merge-read it."
- `position-aiml.md` DQ3 + `position-devex.md` (mine): per-*layer* `SOUL.local.md` / `USER.local.md`,
loaded last-within-layer.
- `position-contrarian.md` DQ3: an `<!-- mosaic:include STANDARDS.local.md -->` directive embedded in
the shipped file.
These are not interchangeable and the difference is *my* problem, because each implies a different
*injection-time composition step* and the four harnesses compose differently:
- The coder's "agent checks for a `.local.md` after each guide load" assumes the **agent** does the
merge at read time. That works on a file-reading harness but is redundant/confusing when the launcher
already injected a pre-composed blob (Pi, `mosaic claude`) — now the agent is told to go re-read and
merge files that are *already in its system prompt*, doubling tokens and risking contradiction between
the injected copy and the freshly-read copy.
- The contrarian's `<!-- mosaic:include -->` directive assumes a **composer** that understands the
directive. Markdown comments are inert; nothing in the current tree processes them. Ship that directive
without building the processor (`mosaic compose-contract`, which only the architect actually specs) and
the "override" is a no-op comment the model ignores — silent failure of the user's customization.
**Concrete failure mode:** a user reads the contrarian's docs, adds `STANDARDS.local.md`, and it is
*never loaded* because the Claude path injects `STANDARDS.md` verbatim with the comment treated as text.
The user believes their tightened secret-handling rule is active; it isn't. That's a security regression
dressed as a customization feature.
**Resolution (my lane to call):** pick **one** overlay mechanism, and make the **launcher/composer**
own it, not the agent. Exactly one composition step (`mosaic compose-contract <harness>`, per
`position-architect.md` DQ4) resolves base + `.local` overlays *before* injection, on every harness, so
the model receives one already-merged blob and never runs a read-merge ritual that's redundant on
injected harnesses and the only path on pointer harnesses. Overlay granularity = per-layer
(`SOUL.local.md`, `USER.local.md`, `STANDARDS.local.md`), not per-guide — guides are L1 framework-owned
and should be referenced, not forked.
### 2c. Architect's + my own 3-way-merge reconciliation engine — the contrarian's attack lands, and I concede part of it
`position-architect.md` DQ3 and my own opening paper both propose per-file template versioning plus a
`git merge-file`-style 3-way merge (`mosaic-reconcile`) for user-seeded files on upgrade.
`position-contrarian.md` DQ3 attacks this directly: *"Reject version-pinning per-file. Per-file pins
create a combinatorial matrix of (framework vN, user pinned vM) states that no one will test."*
He's right about the **test matrix**, and from a DevEx standpoint an *interactive merge-conflict
resolution flow* is a terrible first-run/upgrade experience — it drops a non-expert user into
`<<<<<<< theirs` markers in a config file they didn't know they were editing. For an alpha, that is too
much machinery for too little payoff.
**Resolution / concession:** for the alpha, adopt the **overlay model (2b) instead of 3-way merge**.
Overlays sidestep merge entirely: framework files are overwritten wholesale (no merge needed), user
deltas live in never-touched `.local.md` files (no merge needed). 3-way merge is only required for the
one genuinely-hand-tuned-generated file, `TOOLS.md` — and even there, the alpha can ship "we regenerate
`TOOLS.md` from template; your old one is backed up to `TOOLS.md.bak.<ts>`" (machinery `install.sh`
already has) rather than a conflict UI. Defer real reconciliation to post-alpha. The contrarian's
"subtraction before structure" applies to the *upgrade mechanism* too.
---
## 3. The key disagreement most relevant to my lens, sharpened — and how to resolve it
### The fault line: **inject-by-value (byte-for-byte, launcher-composed) vs. self-load-by-instruction (agent reads files).** Both camps are half-right, and the framework needs both *with a defined boundary* — which no paper draws.
- **Inject-by-value camp** (`position-aiml.md` DQ4: *"L0 must be injected as system-prompt text on
every harness, identically, byte-for-byte"*; `position-moonshot.md` DQ4; `position-steward.md` DQ4):
correct that injection at primacy position is strictly stronger than a deferred "go read this." A
system-prompt-resident gate is non-removable for the turn; a "please read `AGENTS.md`" pointer is a
request the model can skip under load.
- **Self-load camp** (`position-coder.md`): correct that the launcher cannot be trusted as the *sole*
delivery path, because bare `claude`/`codex`/`opencode` launches bypass `mosaic compose-contract`
entirely and get only the thin pointer.
Here is the fact both camps under-weight, and it is the central fact of my lens: **the four harnesses
do not offer the same injection channel, so "byte-for-byte identical injection everywhere" is not
currently achievable as stated.** Ground truth:
- **Pi:** full contract via `--append-system-prompt` + `--skill` + `--extension`
(`adapters/pi.md:14-16`). Tier-1 injection, strongest. *And* Pi has **no permission backstop**
(`runtime/pi/RUNTIME.md:20`), so resident-text fidelity is the *only* enforcement — aiml's point 4
is right: keep L0 tiny precisely because Pi has no hook wall behind it.
- **Claude:** `mosaic claude` *can* `--append-system-prompt` (Tier 1), but bare `claude` gets only
`~/.claude/CLAUDE.md` (Tier 3 pointer). **And Claude's own harness injects competing
`<system-reminder>` mandatory-read blocks** — this very session's reminder demonstrates the harness
will inject *its own* "read these files first" instructions that compete with ours for primacy.
- **Codex / OpenCode:** write to an instructions file (`~/.codex/instructions.md`,
`~/.config/opencode/AGENTS.md`) — between Tier 1 and Tier 3; resident-ish but the model may skim.
So "byte-for-byte everywhere" is an *aspiration*, not a switch you flip. The honest design is a
**tiered injection contract that names the strength per harness and degrades safely**, which is exactly
the per-harness capability manifest I proposed (`position-devex.md` DQ4) — and which the inject-by-value
papers asserted *as if all four harnesses were symmetric*. They are not. `position-aiml.md` even
half-concedes this in its own point 4 (Pi special case) without following the thread to its conclusion:
if Pi is special, the contract is *not* byte-for-byte uniform, it's capability-resolved.
### Proposed resolution — a single, testable injection contract that both camps can sign
1. **L0 is delivered by the strongest channel each harness offers (manifest-declared), AND is
self-loadable as a fallback. The two are not alternatives — they are tiered.**
- Tier 1 (system-prompt append: Pi, `mosaic claude`, `mosaic codex` where supported): launcher
injects the composed L0 by value at primacy. The pointer/AGENTS index then says: *"The Constitution
is resident above. If it is NOT in your context, read `~/.config/mosaic/CONSTITUTION.md` now."* —
conditional, not the false unconditional "already loaded; do not re-read" of `defaults/AGENTS.md:11`.
- Tier 3 (bare-launch pointer: direct `claude`/`codex`/`opencode`): the pointer carries the
**5-bullet irreducible-gate summary inline** (aiml DQ4 point 3) *and* the instruction to read the
full `CONSTITUTION.md`. Even a model that skips the read has the irreducible law resident.
2. **Per-harness capability manifest (`adapters/<h>.capabilities.json`) is the single source for: which
injection tier this harness gets, and how abstract capability-verbs in L0 map to concrete tools.**
This is what collapses the four near-duplicate "sequential-thinking required (except Pi)" stanzas
(`runtime/{claude,codex,opencode}/RUNTIME.md` require it; `runtime/pi/RUNTIME.md:59-61` exempts it).
The Constitution says *"use structured multi-step reasoning before planning"* (capability verb); the
manifest resolves it to `mcp:sequential-thinking` (gate=true) on Claude/Codex/OpenCode and
`native-thinking` (gate=false) on Pi. `position-moonshot.md` DQ4 reached the same "behavior
requirement, not tool requirement" conclusion for sequential-thinking — generalize it to *all*
capability references via the manifest rather than prose carve-outs scattered across runtime files.
3. **Back every hookable gate with a hook where the harness has hooks; track parity as an open gap, not
a silent inconsistency.** This is repo-proven doctrine, not theory: `runtime/claude/RUNTIME.md:30-32`
says the prose memory rule "proved insufficient — the hook is the hard gate." Promote that to
Constitution doctrine. The contrarian (DQ5 point 4) and I agree here. The manifest is also where
"Codex/OpenCode have no `prevent-memory-write` equivalent yet" gets recorded as a tracked gap — which
is the *honest* version of moonshot's COMPLIANCE matrix, minus the launch-refusal enforcement I
rejected in 2a.
4. **Resolve the inject-vs-self-load tension by making the launcher own composition and the agent own
verification.** Launcher composes + injects (`mosaic compose-contract`, architect DQ4). Agent runs a
one-line self-check: *"if CONSTITUTION not resident, read it."* This satisfies the inject-by-value
camp (strongest channel used) and the self-load camp (never trusts the launcher blindly) with a
single defined seam, and it is **testable**: a CI smoke test launches each harness path (Pi append,
`mosaic claude` append, bare-`claude` pointer, Codex instructions-file) and asserts the 7 irreducible
gates are present in the effective context. That smoke test — not a hash-refusal, not front-matter —
is the mechanical control that makes "the Constitution is enforced across harnesses" a *true*
statement instead of an aspirational one.
The disagreement dissolves once you stop pretending the four harnesses are symmetric. They aren't; the
manifest names the asymmetry; the tiered contract degrades safely across it; the smoke test proves it.
---
## Top contentions (return value)
1. **Keep coder's self-bootstrapping Constitution**`defaults/AGENTS.md:11`'s "already loaded; do not
re-read" is *false* on bare `claude`/`codex`/`opencode` launches and makes agents skip the gates. L0
must be injected by value AND self-loadable by instruction; the pointer must never claim residency it
can't guarantee.
2. **Keep aiml's CI-enforced resident-token budget and steward's two shipping blockers** (LICENSE file;
`tools/_lib/credentials.sh:19` hardcoded private credential path). The weakest-context harness sets
the budget ceiling for all four — budget discipline IS portability discipline.
3. **Reject moonshot/steward's "launcher refuses to start on hash mismatch" + YAML front-matter on
resident files.** The hash gate is invisible on the very direct-launch paths where drift happens, and
punishes compliant users; front-matter spends primacy-position attention on metadata the model must
parse and ignore. Enforce L0 immutability structurally (overwritten dir) + socially (CI grep); machine
metadata goes in a launcher manifest, never in the text the model reads.
4. **Three papers invented three incompatible user-overlay schemes** (coder per-guide `.local.md`; aiml/me
per-layer `.local.md`; contrarian `<!-- mosaic:include -->`). Pick ONE, owned by the
launcher/composer, not the agent — the contrarian's inert-comment directive would silently no-op a
user's tightened security rule on the Claude path. Per-layer overlays, composed before injection.
5. **Concede the 3-way-merge attack.** For alpha, overlays replace reconciliation: framework files
overwritten wholesale, user deltas in never-touched `.local.md`. Defer real merge to post-alpha.
6. **The core disagreement is inject-by-value vs. self-load — and it's a false binary** rooted in the
wrong assumption that the four harnesses inject symmetrically (Pi system-prompt + no hook backstop;
Claude append-or-pointer + competing harness `<system-reminder>`s; Codex/OpenCode instructions-file).
Resolve with a **per-harness capability manifest** (injection tier + capability-verb→tool mapping,
collapsing the four "sequential-thinking except Pi" stanzas), a **tiered injection contract** that
degrades safely (Tier-1 append + Tier-3 pointer carrying the 5-bullet gate summary inline), and a
**CI smoke test asserting the 7 irreducible gates are resident on every harness path** — the only
control that makes "enforced across harnesses" true rather than aspirational.