|
| 1 | +--- |
| 2 | +description: Author, review, and check an `intent/` corpus — the durable-intent doc contract — from any project, no fleet tooling assumed. Covers the artifact set, the `intent` CLI, and the failure modes that make a passing check prove nothing. Use when writing or reviewing intent artifacts, adopting the contract elsewhere, or wiring the checker into CI. |
| 3 | +agents: [coding] |
| 4 | +--- |
| 5 | + |
| 6 | +# intent — authoring and checking the contract |
| 7 | + |
| 8 | +The contract is specified in `intent/`, and `intent/` is written in the |
| 9 | +conventions it specifies. That makes the corpus the authority and this skill a |
| 10 | +guide to using it — read the corpus for the rules, read this for how to work |
| 11 | +against them and where the tooling will mislead you. |
| 12 | + |
| 13 | +Start at `intent/vision.md`, `intent/requirements.md`, `intent/spec.md`, |
| 14 | +`intent/ontology.md`. Each numbered directory specifies exactly one artifact |
| 15 | +type and is itself a small intent tree; go to the one matching the artifact you |
| 16 | +are writing. Do not reconstruct the rules from this file — it deliberately does |
| 17 | +not restate them, so it cannot drift from them. |
| 18 | + |
| 19 | +## The rule the whole contract turns on |
| 20 | + |
| 21 | +**Which artifact owns this fact?** A constraint that must hold is a |
| 22 | +requirement. The shape that satisfies it is spec. Why that shape and not |
| 23 | +another is a decision record. The gap between spec and reality is a `.delta/` |
| 24 | +entry. Work in progress — plans, milestones, tickets, status — is not intent at |
| 25 | +all and belongs outside the corpus. |
| 26 | + |
| 27 | +Two failure modes follow, and reviewers should hunt both: |
| 28 | + |
| 29 | +- **A fact with two homes.** Restating a requirement inside a spec means they |
| 30 | + can disagree later, and nothing says which one is wrong. |
| 31 | +- **A claim with no support.** Prose asserting something the corpus cannot |
| 32 | + substantiate reads as settled and is not. If a claim cannot be pointed at |
| 33 | + something, it is an open question or a decision record, not a specification. |
| 34 | + |
| 35 | +## Hidden directories hold a large share of the corpus |
| 36 | + |
| 37 | +`.decisions/`, `.delta/`, `.experiments/`, and `.reference/` are dot-prefixed |
| 38 | +by convention, and **`fd`, `rg`, most editor trees, and most CI globs skip them |
| 39 | +by default.** Between them they carry the reasoning behind most of what the |
| 40 | +numbered sections assert, so a survey that misses them concludes the corpus is |
| 41 | +about half the size it is and that its assertions are unexplained. |
| 42 | + |
| 43 | +Use `rg --hidden`, `fd --hidden`, `ls -a`. When you report a file count or a |
| 44 | +"nothing mentions X" result, say whether hidden paths were included — that |
| 45 | +claim is wrong far more often than it is checked. |
| 46 | + |
| 47 | +## The checker |
| 48 | + |
| 49 | +The checker is deterministic and consumer-agnostic: `intent/16-enforcement/` |
| 50 | +specifies the rules so that any tool can implement them, and the shipped binary |
| 51 | +is one such tool rather than the definition. Diagnostics carry a stable |
| 52 | +`VRS.ENF.<rule>` code, so a finding maps back to the rule that produced it — |
| 53 | +match on the code, never on the message text. |
| 54 | + |
| 55 | +**Expect `axe`- and `vrs`-flavoured identifiers out of an `intent` binary.** |
| 56 | +Rule IDs (`AXE.VRS-R*`) and JSON `schema_version` values (`axe.vrs.check.v1`) |
| 57 | +carry earlier names. That is deliberate, not a packaging bug: identifiers are |
| 58 | +what external references and differential comparisons are keyed on, so they are |
| 59 | +held stable and renamed in one coordinated pass rather than drifting per |
| 60 | +release. Key your tooling on them as they are. |
| 61 | + |
| 62 | +Run `--help` for the authoritative surface; the commands and what each answers: |
| 63 | + |
| 64 | +| Command | Answers | |
| 65 | +| --- | --- | |
| 66 | +| `check` | Does the corpus violate a mechanical rule? Link targets, decision-record shape, delta shape, proposed-decision lifecycle, reference shape, experiment shape. | |
| 67 | +| `graph` | What did the checker actually see? Emits the derived nodes and edges as JSON. | |
| 68 | +| `review` | Semantic review — the judgements no deterministic rule catches. Drives a coding agent. | |
| 69 | +| `review-fixtures` | Grades that semantic review against fixtures with known expected findings, i.e. checks the reviewer. | |
| 70 | + |
| 71 | +`check` and `graph` are pure and portable — filesystem in, diagnostics out, no |
| 72 | +network and no model. |
| 73 | + |
| 74 | +`review` and `review-fixtures` ship in the same binary but are **not** |
| 75 | +standalone. They drive a coding agent through an invocation contract, taking |
| 76 | +`--backend` and `--coding-agent` (which defaults to a `coding-agent` executable |
| 77 | +on `$PATH`). With no such executable they fail at the capabilities preflight |
| 78 | +before examining anything — a configuration failure, not a corpus finding, and |
| 79 | +worth recognising as such. `review` also resolves its prompt assets from the |
| 80 | +corpus under test, so pointing it at a tree with no `16-enforcement/` fails |
| 81 | +naming the missing asset rather than silently reviewing against something else. |
| 82 | + |
| 83 | +Outside a fleet that supplies an agent, `check` and `graph` are the two you |
| 84 | +will actually run. The other two are worth knowing exist for when one appears. |
| 85 | + |
| 86 | +### Profiles |
| 87 | + |
| 88 | +`check` takes `--profile local|strict`, defaulting to `local`. |
| 89 | + |
| 90 | +- `local` — authoring. Transitional rule classes surface as advisory findings. |
| 91 | +- `strict` — CI and merge gates. Blocking rules fail, and warning classes that |
| 92 | + have finished migrating are promoted to blocking. |
| 93 | + |
| 94 | +A corpus that passes `local` can fail `strict`. Gate on `strict`; a clean |
| 95 | +`local` run is not the same evidence. |
| 96 | + |
| 97 | +## Exit 0 is not evidence the corpus was read |
| 98 | + |
| 99 | +This is the trap worth knowing before any other. **`check` exits 0 on an empty |
| 100 | +directory, and on a directory containing no intent artifacts at all.** No |
| 101 | +artifacts means no rules apply, which means no violations. Worse, `--json` on a |
| 102 | +clean real corpus and on an empty directory differ only in the `root` path: |
| 103 | + |
| 104 | +```json |
| 105 | +{ "schema_version": "…", "root": "…", "profile": "strict", "diagnostics": [] } |
| 106 | +``` |
| 107 | + |
| 108 | +There is no scanned-file count in that envelope. So a green `check` is |
| 109 | +consistent with all of: the corpus is clean; the path was wrong; the checkout |
| 110 | +was shallow or empty; a glob excluded everything. **`graph` does not rescue |
| 111 | +this by exit code either** — it also exits 0 on an empty directory, returning |
| 112 | +`"nodes": [], "edges": []`. |
| 113 | + |
| 114 | +What discriminates is the **node count**, not any exit code: |
| 115 | + |
| 116 | +```sh |
| 117 | +intent check ./intent --profile strict |
| 118 | +test "$(intent graph ./intent --json | jq '.nodes | length')" -gt 0 |
| 119 | +``` |
| 120 | + |
| 121 | +Resist pinning that to a tight floor at the current count. It goes red the next |
| 122 | +time someone legitimately adds an artifact, and a gate that cries wolf on honest |
| 123 | +edits gets loosened until it means nothing. `> 0` is the assertion that the |
| 124 | +checker reached the corpus at all — which is exactly what a wrong path, an empty |
| 125 | +checkout, or an over-eager glob destroys. |
| 126 | + |
| 127 | +`> 0` will not catch **partial** loss. Cover that with a second gate of a |
| 128 | +different shape rather than by tightening the first: assert that specific named |
| 129 | +artifacts you expect are present in the graph. Two gates that fail for different |
| 130 | +reasons are worth more than one exact-match gate that fails for both — and that |
| 131 | +you will end up disabling. |
| 132 | + |
| 133 | +The same reasoning applies to any check whose subject might be absent: **a |
| 134 | +passing assertion over an empty set is not a passing assertion.** Prove the set |
| 135 | +was non-empty separately. |
| 136 | + |
| 137 | +## Adopting the contract elsewhere |
| 138 | + |
| 139 | +Nothing in the contract depends on the repository that defines it. The |
| 140 | +artifacts are plain Markdown with a naming discipline; a text editor authors |
| 141 | +them and the checker is optional at authoring time. |
| 142 | + |
| 143 | +Adopt in this order: |
| 144 | + |
| 145 | +1. **Copy the discipline, not the corpus.** Take the artifact set and the |
| 146 | + ownership rule. `intent/`'s own content is about the contract itself and is |
| 147 | + not a template for your domain. |
| 148 | +2. **Start with `requirements.md` + `spec.md`.** Add `vision.md` only when the |
| 149 | + "why" is not obvious from context, `ontology.md` once terms are being used |
| 150 | + precisely enough that a reader could get one wrong. |
| 151 | +3. **Add `.decisions/` the first time a choice is hard to reverse, surprising |
| 152 | + without context, and a genuine trade-off.** Fewer, real records beat a |
| 153 | + record per commit. |
| 154 | +4. **Wire `check --profile strict` into CI with the non-empty graph assertion** |
| 155 | + above, from the start. Retrofitting enforcement onto a corpus that has |
| 156 | + already drifted is the expensive order. |
| 157 | + |
| 158 | +Keep IDs stable once referenced. Renumbering is a whole-corpus edit — update |
| 159 | +every reference in the same commit, because a stale ID reference is not a |
| 160 | +dangling link and the checker will not catch it. |
0 commit comments