R9 + R10 of the Constitution alpha (in-repo deliverables): - framework/CONTRIBUTING.md: layer model, operator-hygiene/PII prohibition, dedup rule, resident budget, dual-installer parity rule, adding-a-harness, re-contamination rule, harness x gate compliance matrix (hook-parity gap marked as tracked-v2), known-limitations (DESIGN §9 residuals), PR checklist. - check-resident-budget.sh: line-count ceiling over framework-owned resident files (CONSTITUTION + AGENTS + each runtime/*/RUNTIME.md), with --self-test; replaces the crude inline ci.yml loop. Wired blocking in .woodpecker/ci.yml. Composer unit test (R9) already runs via pnpm test; verify-sanitized.sh (P1) already wired. Sanitization + budget + prettier all green. Remaining for the mission close: aiguide reconcile (separate repo) + the alpha tag (Lead cuts after full DoD §8 green + all phases merged; P5 #605 pending). Refs #606, #542 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EsgTQzV5YUGk1JtCLP4B83
9.3 KiB
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 | <repo>/AGENTS.md, runtime/<h>/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
$HOMEpaths, 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 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/<h>/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/<h>/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 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:
runtime/<h>/RUNTIME.md— mechanism only (subagent syntax, hook/MCP wiring, injection method). No restated gates (see §3).- Launcher emission in
src/commands/launch.ts— how the composed contract reaches the harness (system-prompt append vs. instructions file). Add the harness to theRuntimeNameunion and the runtime-path map. mosaic compose-contract <harness>works automatically once the runtime path exists (it composes base +*.local.mdoverlays 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
mosaicnever ran the composer, so*.local.mdoverlays are not applied. Mitigated by the unconditional Tier-3 self-load + themosaic doctornudge inAGENTS.md; not eliminated. Relaunch viamosaic <harness>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.shgreen). - 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 testgreen.