# C3

> Triggers on /c3 or architecture questions in projects with .c3/ directory. Phrases: "adopt C3", "onboard", "where is X", "audit architecture", "check docs", "add component", "implement feature", "what breaks if I change X", "add ref", "coding standard", "edit the canvas", "add prd/user-story". Ops: onboard, query, audit, change, ref, rule, canvas, sweep. The CANVAS is your architecture's own vocabulary; onboarded facts FREEZE; work advances by change-units. Classifies intent, loads the reference, runs the CLI.

- Skill: `lagz0ne/c3` (Agent Skill, multi-file: 13 files)
- Install (CLI): `npx skillmds@latest add lagz0ne/c3`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lagz0ne/c3/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Product & Planning
- Author: lagz0ne (https://skillmd.com/u/lagz0ne)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/lagz0ne/c3

---


# C3 — one model, three acts

C3 is your architecture's own vocabulary, frozen into shared truth, that work edits only through reviewed change-units.

1. **Shape the model, freeze the facts.** Descend the domain top-down — draft the **facts** the work needs and wire them as you go; the lean **canvas** (sections + typed columns each entity carries *here*) is already in place, taking a custom fact-type only where the domain needs one. Then flip the gate and the facts **freeze**: shared truth, never hand-edited again.
2. **Change-units drive progress.** Work advances by **change-units** — an ADR plus its patch folder, one atomic saga: declare intent, the tool keeps the result integral (membership, citations, gates), flip it all-or-nothing. Frozen facts change *only* through this merge.
3. **The canvas grows — and evolves — with the need.** When work outgrows the model, **raise the canvas** (climb a rung, additive) or **morph it** (reshape a mis-modeled type non-additively) and migrate every fact to fit — in one gated, atomic unit; completeness is never relaxed.

Build the model → freeze the facts → change-units drive the work → the canvas grows with the need.

## CLI invocation

The packaged runtime is `c3x`, exposed through the skill-local wrapper at `<skill-dir>/bin/c3x.sh`. There is no `c3` executable. Invoke the wrapper explicitly for every command:

```bash
# Template: resolve <skill-dir> to this skill's directory, then replace the command and args.
C3X_MODE=agent bash "<skill-dir>/bin/c3x.sh" check
```

For several commands in one shell, this helper is allowed, but it is only a shell function and does not install a `c3` command:

```bash
c3local() { C3X_MODE=agent bash "<skill-dir>/bin/c3x.sh" "$@"; }
```

`C3X_MODE=agent` → TOON output (~40% fewer tokens) and `help[]` hints appended to each result — follow them. The packaged CLI is the single source; this skill is the **router**: classify the intent, load the reference, invoke the wrapper, follow the output. It names every gate and teaches no procedure — procedure lives in the references.

## Intent Classification

| Keywords | Op | Reference |
|----------|----|-----------|
| adopt, init, bootstrap, onboard, "create .c3" | **onboard** | `references/onboard.md` |
| where, explain, how, diagram, trace, "show me", "what is", "what handles" | **query** | `references/query.md` |
| audit, validate, "check docs", "is the doc intact" | **audit** | `references/audit.md` |
| add, change, fix, implement, refactor, remove, design | **change** | `references/change.md` |
| pattern, convention, "create ref", "update ref", standardize | **ref** | `references/ref.md` |
| "coding rule", "coding standard", "split ref into rule" | **rule** | `references/rule.md` |
| "edit the canvas", "change the shape", "what sections does X have", "add a doc type", "raise the bar", "add prd/user-story" | **canvas** | `references/canvas.md` |
| impact, "what breaks", assess, sweep, "is this safe" | **sweep** | `references/sweep.md` |
| "does the code match", conformance, "is the doc still true", "check against code", drift-vs-external | **eval** | `references/eval.md` |

## Dispatch

1. Classify the op (ambiguous → `AskUserQuestion` with options).
2. Load `references/<op>.md`.
3. Run the CLI (Task tool for parallelism), follow `help[]`.

**Precondition — read-only fast path.** Concept → wrapper `search`; file/glob → `lookup`; id/section → `read --section`. After a hit, use one `graph <id> --depth 1` for route context, then stop when owner, governing refs, one causal link, and the next action have evidence. Read `route.facts`, `route.graph`, `route.anchors`, `route.lanes`, `route.drift`, and `route.hash` as inspection clues, not proof or apply gates. For ownership/query sessions, cap proof at four C3 calls: search/lookup, one graph, the owner section, and one governing-rule section; do not read every cited rule. Prefer compact reads; do not repeat successful reads. Use `list`, full reads, source scans, or tests only for a miss, drift, explicit audit, or change. For open-ended impact work, keep 2–3 independent routes, redirect duplicates, block theorem-strength gaps, and reopen only with a new mechanism; require concrete ids, commands, and evidence. **Never Read/Glob/Edit `.c3/` instances** (canvas definitions are the user-owned exception); missing `.c3/` → **onboard**.

## The shared contract

These rules are stated once here; every reference cites them.

**Frozen facts.** A *fact* is any entity whose canvas declares no `status:` set — `system`, `container`, `component`, `ref`, `rule`, `pm-requirement`, `user-story`. The moment a fact carries a body it is frozen: the wrapper's `write`, `set`, and `delete` operations on it are **refused** (the guard keys on the first arg; an unknown type is treated as frozen). The refusal names the only legal path: *"<id> is a fact — facts are frozen and change only through a change-unit."* A fact changes **only** by authoring patches in a change-unit and running the wrapper's `change apply` operation.

*Exempt from the freeze:* the wrapper's `add` operation (creating a new fact is unguarded), the first `write` that authors a never-bodied fact, editing a **change-doc** (`adr`/`prd`/`atomic-design-change` — they declare `status:`), and editing a **canvas definition** (user-owned). The fact→code binding lives outside the freeze entirely: it sits in `.c3/eval/<fact>.yaml` (a `code:` field) — an ordinary editable file, re-aimed freely as code moves, never a frozen fact, so it needs no exemption (`references/eval.md`).

**Membership is by construction.** A parent's membership table is synthesized by the tool from its children's `parent:` links, on every path that changes parentage (`add`, `change apply`, or `check --fix` through the wrapper). Leave the row to the tool — never hand-author or hand-edit it. (Set `parent:`; the row appears.) Parentage is **not** a graph edge: `parent:` sets the child's `parent_id` and the synthesized membership row — a separate axis from *wiring* edges (`uses`, citations, `edge<>` columns), which the wrapper's `graph` operation shows. A reparent updates `parent_id` + both parents' membership; it does not touch wiring.

**A fact is always complete to its rung.** A canvas is a **rung** — a complete contract for one complexity *level*, not a target to fill in over time. A fresh init's canvas is deliberately lean (rung-1); the deeper sections a complex project needs are a *higher* rung, not a hole. Completeness is never relaxed. To grow, **climb a rung**: raise the canvas, then migrate every affected fact up to the new contract, completely — integrity forbids a fact straddling two rungs. When the shape itself is wrong — mis-modeled, not merely lean — **morph** it: a non-additive reshape of the canvas (the *evolve-unit*: a `canvas`-scope patch) that migrates every instance to the new shape in one gated, atomic unit, on the same no-straddle rule (`references/change.md` §Morphing the model).

**ADR status set:** `[open, accepted, done, superseded]`. (The wrapper's `add adr` operation stamps `proposed` — the legacy synonym for `open`; `accepted` auto-latches to `done` when its After-cites resolve fresh.) Terminal change-docs (`done`/`superseded`) are content-frozen historical records, **exempt from the wrapper's `check` operation**. `list`/`check` exclude ADRs by default; `--include-adr` to include.

## Command table

The packaged CLI is the catalog — invoke the local wrapper with `<cmd> --help`; its output is authoritative. The change-unit gate stack (the load-bearing flow) lives in `references/change.md`.

| Command | Purpose |
|---------|---------|
| `list` | Topology with counts + coverage (`--flat`, `--compact`) |
| `check` | Validate facts against their canvas + consistency (`--fix`, `--only`, `--include-adr`). Fact-vs-code conformance is **not** here — run the wrapper's separate, off-switch `eval` operation |
| `eval` | Check a frozen fact's claim against the uncontrolled external it governs (the `code:` binding in `.c3/eval/<fact>.yaml`). A one-off CI-cadence verdict, **never a gate** (`references/eval.md`) |
| `repair` | Rebuild the disposable cache from canonical `.c3/` and reseal (after a branch switch / selective merge) |
| `search <query>` | Concept → entities by semantic + keyword + graph signal, with route clues when available |
| `lookup <file-or-glob>` | File/glob → component(s) + refs |
| `read <id>` | Entity content (`--full`; `--section <name> --cite` emits the patch base anchor) |
| `graph <id>` | Relationship graph plus route facets (`facts`, `graph`, `anchors`, `lanes`, `drift`, `hash`); `--depth`, `--direction forward\|reverse`, `--format mermaid`, `--unit <adr-id>` previews staged patches |
| `add <type> <slug>` | **Create** a fact (body via stdin or `--file`; `--container`, `--feature`). The unguarded create path |
| `canvas <list\|read\|add\|write>` | Manage canvas definitions (user-owned shape, at `.c3/canvases/`) |
| `schema <type>` | Render a canvas's sections/columns/REJECT-IF (leads with the rejection contract) |
| `write <id>` / `set <id> <field> <val>` / `delete <id>` | Direct edits — **refused on a frozen fact** (see the contract). For change-docs and canvas bodies only |
| `change <new\|view\|status\|accept\|apply\|rebase\|scaffold>` | The change-unit saga — the **only** way to mutate a fact. `apply` runs the gate stack atomically; `rebase` emits the drift bundle for drifted patches; `scaffold` stages a rung-climb. See `references/change.md` |

Missing a packaged operation → STOP, tell the user. No file-tool workarounds.

