# Contributing to the Mosaic Framework The Mosaic framework is the open-source agent-operating layer that deploys to `~/.config/mosaic/`. It is designed to be **forked and customized** — but the shared core must stay operator-neutral, deduplicated, and upgrade-safe. This guide is the contract for changing framework-owned files. > Governance model and layer rationale: `constitution/LAYER-MODEL.md` (source-only). > Requirements & phase history: `docs/design/framework-constitution/`. --- ## 1. The layer model (where does my change go?) | Layer | What | Owner | On upgrade | File(s) | | ------ | ------------------------------------------------------------- | ---------------- | --------------------------------------- | -------------------------------------------- | | **L0** | Constitution — the non-negotiable law (hard gates) | Framework | **Overwritten** | `CONSTITUTION.md` | | **L1** | Standards & guides — how to do the work well | Framework | Overwritten; user delta → `*.local.md` | `STANDARDS.md`, `guides/*` | | **L2** | Persona (SOUL) — agent name, tone, role | User (init) | **Never overwritten** | `SOUL.md` (+ optional `SOUL.local.md`) | | **L3** | Operator (USER) — human identity, prefs, policy | User (init) | **Never overwritten** | `USER.md` (+ optional `USER.local.md`) | | **L4** | Project / runtime mechanism — per-repo deltas; harness wiring | Repo / framework | Project user-owned; runtime overwritten | `/AGENTS.md`, `runtime//RUNTIME.md` | **The one sentence a user can rely on:** edit `SOUL.md` / `USER.md` and the `.local.md` overlays — they survive every upgrade. To change framework behavior, add a `.local.md` overlay; never edit a framework-owned file in place. --- ## 2. Operator hygiene (PII / secrets prohibition) — **blocking** Framework-owned files ship publicly. They **must not** contain: - Operator or personal identity (names, handles, pronouns, accessibility notes). - Private `$HOME` paths, private hostnames, or domains. - Secrets, tokens, or credentials (use `~/.config/mosaic/credentials.json`; the hook URL soft-degrades via `${OPENBRAIN_URL}`). This is enforced by `tools/quality/scripts/verify-sanitized.sh`, wired **blocking** in CI (`.woodpecker/ci.yml`). It runs two rule classes: structural (private-`$HOME` defaults, dead paths, unrendered tokens) and a labeled current-contaminant denylist. Run it locally before pushing: ```bash bash packages/mosaic/framework/tools/quality/scripts/verify-sanitized.sh ``` Operator-specific behavior belongs in **your** `SOUL.md`/`USER.md`/`*.local.md`, never in the shared core. (The "framework-PR firewall" in `CONSTITUTION.md` §4 states this as law for agents opening framework PRs.) --- ## 3. Dedup rule — one source, everyone references it Hard gates live in **`CONSTITUTION.md` (L0) only**. `AGENTS.md`, `STANDARDS.md`, and every `runtime//RUNTIME.md` **reference** the law — they never restate it. Restating a gate is a defect: it creates two sources that drift. If you find a gate duplicated outside L0, delete the copy and point to L0. `AGENTS.md` is a thin dispatcher (load order + guide router + the tier-aware self-load). Keep it that way; new procedure goes in `guides/*` (on-demand), not in the resident core. --- ## 4. Resident line-count ceiling — **blocking** The framework-owned files injected by value (`CONSTITUTION.md`, `AGENTS.md`, each `runtime//RUNTIME.md`) are budgeted by **line count** — never by word count (a word cap forces paraphrasing the law, the exact drift vector we removed). ```bash bash packages/mosaic/framework/tools/quality/scripts/check-resident-budget.sh ``` Wired blocking in CI. Gate **wording** stays intact; if a file legitimately needs more lines, raise its ceiling in the script deliberately (in the same PR, with rationale). The per-harness _total_ resident prompt (which also sums the user's `SOUL.md`/`USER.md`) is a `mosaic doctor` runtime advisory — CI cannot see user files, so it is out of CI scope by design (DESIGN §7). --- ## 5. Dual-installer parity rule Two installers seed and migrate `~/.config/mosaic/`: - **`framework/install.sh`** (bash) — the canonical installer. - **`packages/mosaic/src/config/file-adapter.ts`** (TS) — the wizard path. **Any change to seed lists, overwrite/preserve semantics, or migration MUST land in BOTH**, validated by the **shared fixture suite**: - `framework/tools/quality/scripts/test-install-migration.sh` (bash matrix) - `packages/mosaic/src/config/file-adapter.test.ts` (vitest) Both assert the same behavior: framework-owned files overwrite (backup-once to `*.pre-constitution.bak`); user-seeded files seed-if-absent; `SOUL.md`/`USER.md`/ `*.local.md`/`credentials` are preserved. A change in one installer without the other (and its fixtures) is incomplete. --- ## 6. Adding a harness adapter A harness (runtime) is wired by: 1. `runtime//RUNTIME.md` — **mechanism only** (subagent syntax, hook/MCP wiring, injection method). No restated gates (see §3). 2. Launcher emission in `src/commands/launch.ts` — how the composed contract reaches the harness (system-prompt append vs. instructions file). Add the harness to the `RuntimeName` union and the runtime-path map. 3. `mosaic compose-contract ` works automatically once the runtime path exists (it composes base + `*.local.md` overlays for that harness). Then add a row to the compliance matrix (§8) and mark which gates are mechanical vs. resident-only for the new harness. --- ## 7. Re-contamination rule A green sanitization gate is not permanent. Before every PR: - Do not reintroduce operator identity, private paths, or secrets (§2). - Do not copy a gate out of L0 (§3). - Do not add an unrendered template token or a dead path to a shipped file. If `verify-sanitized.sh` goes red, that diff **is** your worklist — fix it, don't suppress it. --- ## 8. Harness × gate compliance matrix How each gate is enforced per harness. **Mechanical** = a hook/CI check the agent cannot bypass. **Resident** = injected contract prose (strong, but not a hard stop). **CI** = repo-side, harness-independent. | Gate / mechanism | Claude | Codex | OpenCode | Pi | | --------------------------------------------- | ----------- | ---------------- | ---------------- | ---------------- | | Contract injection (resident-by-value) | append SP | instructions | `AGENTS.md` | append SP | | Operator overlays (`*.local`, composed) | ✅ | ✅ | ✅ | ✅ | | Bare-launch self-load (Tier-3, read L0) | ✅ | ✅ | ✅ | ✅ | | Sanitization (no PII) — `verify-sanitized` | CI ✅ | CI ✅ | CI ✅ | CI ✅ | | Resident budget ceiling | CI ✅ | CI ✅ | CI ✅ | CI ✅ | | Migration parity (5-fixture, both installers) | CI ✅ | CI ✅ | CI ✅ | CI ✅ | | `no-memory-write` (PreToolUse hook) | **mech ✅** | resident-only ⚠️ | resident-only ⚠️ | resident-only ⚠️ | | QA / typecheck (PostToolUse hooks) | **mech ✅** | resident-only ⚠️ | resident-only ⚠️ | resident-only ⚠️ | | Native heartbeat (fleet `ps` model/status) | sidecar | sidecar | sidecar | **native ✅** | ⚠️ **Hook-parity gap (tracked, v2):** the mechanical PreToolUse/PostToolUse hooks exist for Claude Code only. On Codex/OpenCode/Pi those gates are currently enforced by the resident contract + CI, not by a per-tool hook. Closing hook parity is a **v2** item, not part of this alpha. --- ## 9. Known limitations (accepted residual risks) These are accepted with rationale (DESIGN §9); they are documented, not bugs: - **Bare-launch overlays are base-only.** A harness started without `mosaic` never ran the composer, so `*.local.md` overlays are not applied. Mitigated by the unconditional Tier-3 self-load + the `mosaic doctor` nudge in `AGENTS.md`; not eliminated. Relaunch via `mosaic ` to pick up overlays. - **Bare-launch drift is undetected by `mosaic doctor`** (the launcher never ran). - **Codex/OpenCode/Pi hook parity** is a tracked v2 gap (§8). - **Live-launch cross-harness verification** is v2; the alpha verifies the composer by unit test (per-tier anchor + Tier-3 byte-equality), not a live launch. **Deferred to v2 (explicit):** `constitution/` deploy directory; capability JSON adapters; 3-way merge; `policy/*.md` composition; per-layer version stamps as a migration driver. --- ## 10. PR checklist - [ ] No operator identity / private paths / secrets (`verify-sanitized.sh` green). - [ ] No gate restated outside `CONSTITUTION.md` (§3). - [ ] Resident budget green (`check-resident-budget.sh`). - [ ] Seed/migration changes landed in **both** installers + shared fixtures (§5). - [ ] New harness → compliance-matrix row updated (§8). - [ ] `prettier --check` + `pnpm lint` + `pnpm typecheck` + `pnpm test` green.