- Docs
- Reference — intent fields, modes, and projection profiles
Reference — intent fields, modes, and projection profiles
Look up intent fields, level-specific additions, risk modes, output locations, contract maturity, and tracker projections.
The intent file
Section titled “The intent file”intent frame writes each intent from this template. The agent replaces every <…>, and the file continues in the same shape.
- **Slug:** `<slug>` <!-- kebab-case; matches the filename -->- **Level:** `<product-vision | product-strategy | capability | feature>` <!-- the altitude this intent sits at; an open recognized set, not a closed enum — name an intervening altitude if your org has one -->- **Owner:** `<who is accountable for this outcome>` <!-- required: a person or a role, declared rather than inferred from git history -->- **Status:** `<Draft | Accepted | Fulfilled | Withdrawn | Cancelled | Superseded>` <!-- required; one bare word. Withdrawn and Cancelled are peers of Fulfilled, not flavours of it — a rollup that counts them as delivered is the failure this vocabulary prevents -->- **Superseded by:** <!-- required when Status is Superseded, and refused otherwise; the Slug of the live intent that replaced this bet -->- **Kind:** `<outcome | opportunity>` <!-- optional, additive: the discovery-traceability chain rung this intent occupies on the opportunity-solution tree (outcome = the North Star / chain root; opportunity = a need in the OST). The structural-orphan lint reads this bold-body field to place the intent on the chain. Distinct from Level: (the altitude) — a `Level: capability` intent is placed by Level instead, and a feature intent maps downstream to a brief/spec. Omit it when not running the discovery-traceability chain; an intent still carries both an Outcome and an Opportunity section regardless. -->- **Scale:** `<app | business-unit>` <!-- resolved at intake by intent frame -->- **Maturity:** `<greenfield | brownfield>` <!-- brownfield unlocks current-state inputs -->- **Parent intent:** `<kind>:<slug>` <!-- optional: the higher-level intent this was decomposed from, e.g. `capability:<slug>` or `intent:<slug>`; omit at the top of the tree -->- **Outcome co-owner:** <!-- optional: another intent that shares this outcome, as a typed pointer such as `intent:<slug>`; omit when this intent owns the outcome alone -->- **Related intents:** <!-- optional: other intents this one sits beside, as comma-separated typed pointers such as `intent:<slug>` or `capability:<slug>`; write it on one side only, because the navigator shows it from both ends. It is never a parent or a dependency; omit when there is none -->- **De-risked:** <!-- optional: the ISO 8601 date the riskiest assumption was tested, or the literal `no`. Absent means nobody recorded it; `no` means someone decided against de-risking -->- **Shaping-reviewed:** <!-- optional: the ISO 8601 date a cold reviewer read this, or the literal `no` -->- **Decomposed:** <!-- optional: the literal `no`, or an ISO 8601 date followed by exactly one of children | brief | spec | direct-light | closed-empty. `closed-empty` means decomposition is deliberately complete with no child work; `direct-light` requires each item under ## Decomposition to state its requested outcome -->
## Outcome
<!-- LOAD-BEARING. What changes, and how you'll know. Name a *steerable inputmetric* you can directly move, the *lagging outcome* it should drive, and a*guardrail* that must not get worse. A qualitative-but-falsifiable outcome isfine in 0-to-1 — name the signal you'd accept as proof. -->
- **Input (steerable):** <the metric you can move directly>- **Outcome (lagging):** <the result it should drive>- **Guardrail:** <what must not get worse>The agent replaces every <…>. This is the template the skill writes from; the artifact continues in the same shape.
Run frame-domain — what the domain actually is
Section titled “Run frame-domain — what the domain actually is”You type:
## Intent fields
The `intent` template (shipped with the `intent` skill at`intent/assets/intent-template.md`). An intent's **preamble** is the runof `- **Field:** value` lines before the first `## ` heading. A corpus checkreads that region and decides each field by the tier below; a field-shaped linein the body is neither read nor judged.
Four tiers:
- **Required** — absent is refused.- **Constrained when present** — a value outside its set is refused. Omitting it is usually fine, but a corpus rule may still require the field, and the row says so when one does.- **Unconstrained** — no rule judges the value on the artifact alone. A rule that needs the rest of the corpus may still apply, and the row says so when one does.- **Retired** — the name itself is refused; use the replacement.
A field whose name appears in none of these tiers is accepted, so your ownadditions keep working.
| Field | Tier | Value || --- | --- | --- || `Owner` | required | who is accountable — a person or a role. Declared, never inferred from commit history || `Slug` | required | the canonical identity, independent of the filename's ordinal. Presence is checked; the value is not, so kebab-case is a convention the check does not enforce || `Level` | required | the altitude — an **open recognized set**, `product-vision › product-strategy › capability › feature`. Present or absent is checked; the value never is, so name an intervening altitude if your org has one || `Status` | required | exactly one of these bare tokens: `Draft`, `Accepted`, `Fulfilled`, `Withdrawn`, `Cancelled`, `Superseded`. No value carries a payload — the supersession pointer is a field of its own, below. `Withdrawn` and `Cancelled` are peers of `Fulfilled`, not flavours of it || `Superseded by` | unconstrained | the `Slug` of the live intent that replaced this bet. The value itself is never judged, exactly as `Slug` is not — whatever a target may be called, a pointer may name. Two rules still apply, and both are checked **over the corpus** rather than on one file, so they are the corpus lint's and not the shaping review's: `Status` and this field are required together and refused apart, and resolution is one hop, so this may not name an intent that is itself `Superseded` || `Accepted` | constrained when present | **When required:** `Status: Fulfilled` and `Status: Cancelled` must carry it; `Status: Draft` must not. See the status table below. **Value:** an ISO 8601 calendar date written `YYYY-MM-DD`, a space, then non-empty text. The check asks only that the text is there; make it say who ratified the bet and on what evidence, which is why the field exists. A bare date is refused, and so is the literal `no` that the progress fields accept — an unratified intent omits the field || `Fulfilled` | constrained when present | **When required:** only `Status: Fulfilled` carries it; every other status that decides the question refuses it. See the status table below. **Value:** the same shape as `Accepted` — a `YYYY-MM-DD` date, a space, then non-empty evidence text. The date is the text up to the first space, so punctuation written straight after it lands inside the date token and is refused || `Kind` | constrained when present | `outcome` or `opportunity` — the rung this intent occupies on the opportunity-solution tree || `Scale` | constrained when present | `app` or `business-unit` — resolved at intake (see Modes) || `Maturity` | constrained when present | `greenfield` or `brownfield` — gates current-state inputs || `Outcome co-owner` | constrained when present | a peer declaration in typed pointer form: one of `outcome`, `opportunity`, `capability`, or `intent`, followed by `:` and a non-empty target identity. The corpus lint resolves the target; this row only checks the one-artifact shape || `Related intents` | constrained when present | `none`, or comma-separated typed pointers with one of the prefixes `intent`, `capability`, `outcome`, or `opportunity`, then `:` and a slug. A bare slug or a path is refused, and so is a repeated item. `none` means no relation. Write the relation on one side only: the navigator shows it from both ends. The corpus lint then checks each target: it must be a live intent of the stated kind, and not this intent itself || `De-risked` | constrained when present | an ISO 8601 calendar date written `YYYY-MM-DD`, or the literal `no`. The basic form `20260922`, a week date, and an ordinal date are refused || `Shaping-reviewed` | constrained when present | an ISO 8601 calendar date written `YYYY-MM-DD`, or the literal `no` || `Decomposed` | constrained when present | the literal `no`, or an ISO 8601 calendar date written `YYYY-MM-DD` followed by exactly one of `children`, `brief`, `spec`, `direct-light`, `closed-empty` || `Governed by` | unconstrained | the governing decision this intent answers to || `Parent intent` | unconstrained | back-link to the intent this was decomposed from; omit at the top of the tree || `Milestone` | unconstrained | where this sits in an implementation sequence || `Type` | retired | use `Kind` || `Raised` | retired | use `De-risked` or `Shaping-reviewed` for a dated fact || `Stage` | retired | use `Status` || `Parent` | retired | use `Parent intent` || `Source` | retired | keep provenance in a `## Source` body section || `Authority` | retired | use `Governed by` in the preamble. The name stays valid *below* the first heading, where it is an attribution or a provenance token rather than this field |
**Which status needs which record.** `Accepted:` and `Fulfilled:` are the onlyfields whose presence `Status` decides. Every cell below is what the corpuslint does today:
<!-- First cells are deliberately unbackticked. The parity test reads every row in this section whose first cell is a backticked token as a preamble-field row, so a backtick here registers a status as a field. -->
| Status value | `Accepted:` | `Fulfilled:` || --- | --- | --- || Draft | refused | refused || Accepted | optional | refused || Fulfilled | **required** | **required** || Cancelled | **required** | refused || Withdrawn | optional | refused || Superseded | neither required nor refused | neither required nor refused |
`Withdrawn` never needs `Accepted:`, because abandoning a bet nobody ratifiedneeds no ratification. `Cancelled` does need it: cancelling says the work wasratified and then stopped. `Superseded` is not decided either way — no rulereads these two fields for it.
**Write these records in the preamble, not the body.** A `- **Accepted:** …`line below the first `## ` heading is read as absent, so the lint reports therecord as missing while you are looking straight at a line that appears tosupply it. If a refusal insists a record is absent and you can see it, checkwhich side of the first heading it sits on.
**Absent is not `no`.** For the three progress fields, an absent field meansnobody recorded the answer; the literal `no` means someone decided against it.A corpus report states which of the two it found, and absence alone never failsa check.
**Backticks and trailing comments are not part of a value.** `` - **Level:**`feature` `` and `` - **Level:** `feature` <!-- the altitude --> `` and`- **Level:** feature` all carry the same value. A line left holding only acomment is absent, not malformed — so a seeded field you have not filled incosts nothing and asserts nothing.
## Body sections
These are sections, not preamble fields, and no tier above applies to them.
| Section | Meaning || --- | --- || **Outcome** | a steerable *input* metric + the *lagging* outcome + a *guardrail* || **Opportunity** | the solution-independent need (a job to be done) || `Assumptions` | what must be true for the bet to pay off || `Decomposition` | the children: lower-level intents, or a spec/slice at the leaf. When `Decomposed` ends in `direct-light`, each checkbox item here states its own requested outcome |
## Tombstone files
When an intent is renamed, the old filename is retired rather than deleted. A**tombstone file** is left at the vacated name so that the old ordinal is neverreissued to a new intent.
**Partition rule:** a file in `docs/product/intents/` is a tombstone if and onlyif its preamble carries a `Tombstone:` field. Every file in the directory iseither a live intent or a tombstone; this single field is what decides which.
A tombstone's preamble carries exactly three fields and no others:
| Field | Value || --- | --- || `Slug` | The slug the retired file carried — unchanged from the original intent || `Tombstone` | The retirement date, written as one ISO 8601 calendar date `YYYY-MM-DD` || `Reissued as` or `Retired` | Exactly one of these two: `Reissued as` holds the repository-relative path to the renamed successor (under `docs/product/intents/`); `Retired` holds a single non-empty line describing why the intent was retired without a successor |
Both pointer fields together, or neither, are refused.
The tombstone file's **name** is the retired intent filename, unchanged — thesame `<TYPE>-NNNN-<slug>.md` structure and `.md` extension. Changing the name inany way would break the ordinal reservation: a name outside the expected shapeeither fails every later admission in the directory, or frees the ordinalsilently with no error. The correct name is the retired name, exactly as it was.
## Product-altitude fields (level-conditional)
When `Level` is a product altitude, the `intent` template seeds an extra, **level-conditional** field block — filled only at that rung; an empty heading is a prompt, not an error. Both live in the single `intent-template.md`; there is no new per-rung template or schema.
| Rung | Seeded fields || --- | --- || `product-vision` | customer-shaped pitch · the change · the job + struggling moment · who, by circumstance · existing alternatives · narrowest wedge · demand evidence · open assumptions tiered (`must-test-before-shipping` / `accept-as-bet` / `will-monitor-post-ship`) · counter-metrics || `product-strategy` | central challenge (diagnosis) · guiding policy · coherent actions (3–5) · problem/segment sequence · horizon |
## De-risk kind by level
`intent de-risk` tests *this* intent's riskiest assumption in the kind its level calls for:
| Level | De-risk kind || --- | --- || `product-vision` / `product-strategy` | **`market-existence`** — will anyone want this at all (market desirability) *and* can it be a business (viability); tested **once at the top**, categorically distinct from feature `desirability` || `capability` | architectural / adoption || `feature` | `desirability` |
## Modes
One **global** axis, resolved once; the rest are **per-intent** flags.
| Mode | Scope | Values | Effect || --- | --- | --- | --- || **Scale** | global (per repo) | `app` ↔ `business-unit` | *suggests* a starting altitude (decoupled from `Level`, overridable in a word), and sets where work lives + leaf shape; resolved at intake (infer → confirm → ask) || **Maturity** | per-intent | `greenfield` ↔ `brownfield` | brownfield unlocks current-state inputs (journey / process map) || **Reversibility** | per-intent (in `intent de-risk`) | one-way ↔ two-way door | recommends the prototype-approach || **Prototype-approach** | per-intent (in `intent de-risk`) | `validate-first` ↔ `prototype-led` | how the bet is tested; defaulted by reversibility, overridable |
## Business-unit scale — cross-component fields
At `business-unit` Scale the feature intent is sliced per component into one `core` brief per repo, coordinated from a value-stream meta-repo (the `align-value-stream` skill). The fields and artifacts that appear at this scale:
| Field / artifact | Where it lives | Meaning || --- | --- | --- || `parent-intent` | each per-component **brief** | optional upward pointer to the product `intent` the slice was projected from; provenance only, never interpreted by `author-delivery-brief continue`. The brief-level analogue of the intent-level `Parent intent` back-link in *Intent fields* above — same upstream-pointer idea, one artifact down. Distinct from `Epic` (an external coordinator). || federated catalog | meta-repo | Backstage Domain→System→Component→API; **references** each component repo's own `catalog-info.yaml`, never re-authored. || `contract@version` + courier snapshot | each slice | the shared contract referenced by version (never forked) + a read-only snapshot for provenance; provider/consumer roles mirror `providesApi` / `consumesApi` with a compatibility direction. || cross-component rollup | meta-repo | a markdown table, one row per slice → brief → status snapshot + coverage pointer; the **AND across rows** answers "delivered across all components?"; absent-source rows show `unknown / not-yet-catalogued` (never silently delivered). |
The hard limits are stated honestly: **no atomic cross-repo commit**, **no shared release train**, and the rollup is a **snapshot, not a live feed**. See the how-to *Run a capability across a value stream*.
## Output locations — config-driven, `docs/product` by default
`intent frame` writes intents to `<parent>/intents/<slug>.md` and`align-value-stream` writes rollups to `<parent>/rollups/<slug>.md`. Both resolve`parent` from the `[product]` table of an adopter-created`agentbundle-layout.toml` (repo-root file overrides user-profile file per table;default `docs/product` when no section resolves). Each intent and rollup is asingle file — a per-topic folder is deliberately not used. Full schema andanchor/security-rail details are in each skill's`references/agentbundle-layout.md`. `intent decompose`'s`docs/product/briefs/<slug>.md` output is pinned and not governed by this config.
## Contract maturity by stage
The detailed wire contract is pinned at the **spec** stage, not at intent.
| Stage | Contract maturity || --- | --- || intent | behavioral only (no fields/types) || brief | interaction / consumer-expectation (not a full schema) || **spec** | **detailed wire contract** (the existing `Contract:` seam) || build | implement + verify |
## Tracker projection profiles
:::noteThe canonical profile table lives in the pack at `intent/references/tracker-projection.md` (with the tier annotations); this is a summary — when they disagree, the skill reference wins.:::
The intent tree is deeper than any tracker. A repository may use a tracker asan outbound projection, or declare tracker-origin authority for mapped fieldsand use the configured refresh processor. The profile and artifact authorityrecord decide the direction; tracker object names do not.
| Canonical | `none` | Linear (lean) | Jira Align (deep) || --- | --- | --- | --- || capability intent | markdown | Initiative | Epic || feature intent | markdown | Project | Feature || spec / slice (leaf) | a direct `core` spec; coordinating brief only for multi-spec or cross-repository work | Issue | Story || story-as-trace | AC checklist | sub-issue | Story / sub-task |
v1 ships the **mapping**, not a live API; a story is a *trace* of a spec, never the decomposition unit. Live tracker sync is a later pack.