# CRAYON-C4 decisions (ADR) file — authoring guide for an AI

You are generating or updating a **CRAYON-C4 decisions file**: a small JSON
document carrying a project's Architecture Decision Records (ADRs), in the
shape the Decisions screen's **Decisions file (.json)** export produces and
its **Import…** button accepts. Produce ONE JSON object that validates
against `crayon-c4-decisions.schema.json` (next to this guide) AND follows
the authoring rules below. Output only the JSON (no prose, no markdown
fences) unless asked.

A decisions file is deliberately narrow: it carries nothing but decisions —
no diagrams, no nodes. That is what makes it safe to hand to an AI tool
running locally against your architecture repo, edit under version control,
and import back without touching anything else in the project.

## 1. Contract (hard rules)

- The file MUST include `"schemaVersion": 1` and `"kind": "crayon-c4-decisions"`.
- `adr.adrs` MUST be an array (may be empty, though an empty file has nothing
  to import).
- Every entry MUST be an object with a non-empty string `id`. Ids MUST be
  **unique within the file**.
- Import is keyed by `id`: an id the destination project does not have yet is
  **added**; an id it already has is **updated** to match this file's record
  (only when the content actually differs — a byte-identical record is left
  alone); an existing decision whose id this file does not mention is **never
  removed**. A decisions file is therefore always safe to import repeatedly
  and safe to hand-edit a subset of.
- `status` SHOULD be one of `proposed`, `accepted`, `deprecated`,
  `superseded` (soft-checked — an unrecognised value does not block import,
  but only these four drive the app's own lifecycle rules).
- `date` is `YYYY-MM-DD`.
- `context`, `decision`, `consequences` are markdown strings (MADR-style:
  the situation, what was decided, what follows from it).
- `supersedes` / `supersededBy`, when present, MUST name another `id` **in
  this same file or already in the destination project** — they form a
  linear chain (an ADR supersedes at most one earlier one, and is superseded
  by at most one later one).
- `links` is an array of `{ target, name, elementType }`. `target` names a
  stable element identity in the model this decision is about:
  - `{ "kind": "c4-node", "nodeId": "<id>" }`
  - `{ "kind": "c4-relationship", "from": "<id>", "to": "<id>" }`
  - `{ "kind": "deploy-definition", "definitionId": "<id>" }`
  - `{ "kind": "deploy-placement", "environmentId": "<id>", "placementId": "<id>" }`

  `name` and `elementType` are a **soft reference** — the element's display
  name and kind at the time of linking (e.g. `"Web App"` / `"Container"`) —
  and MUST always be populated, even if you are not certain the destination
  project's model still has an element with that exact id. A link whose
  target does not resolve in the destination project is pruned on import
  rather than rejected; the soft reference is what lets a reader still see
  what the decision was about.
- `categories` is an optional array of short free-text strings (e.g.
  `["data", "infrastructure"]`) — an emergent vocabulary, not a fixed enum.
  Comma characters are stripped on import (they are the separator used by the
  sibling Markdown export), so don't put a comma inside one category name.
- `needsReview` (boolean, present-`true`-or-absent, never `false`) and
  `lastConfirmed` (`YYYY-MM-DD`) are app-managed review-tracking fields —
  leave them out when authoring or generating a new record.

## 2. The one-way door: `accepted` is locked

Once a decision's `status` moves past `proposed` (to `accepted`,
`deprecated`, or `superseded`), the app treats its **content** (`title`,
`context`, `decision`, `consequences`, `date`) as immutable — a later update
to the same `id` with a different content is a course change that should be
expressed as a *new* decision that `supersedes` this one, not a silent edit.
Status itself only ever moves forward: `proposed → accepted →
deprecated | superseded`; `deprecated`/`superseded` are final. When
generating a course-correction, prefer:

```json
{ "id": "adr-0007", "status": "superseded", ... }  // the old one, now closed
{ "id": "adr-0008", "supersedes": "adr-0007", ... }  // the new decision
```

`links` and `categories` are classification, not content, and stay editable
on a locked record.

## 3. Ids

The app mints sequential-stable ids `adr-0001`, `adr-0002`, … that survive
every rename. When ADDING a new decision to an existing project's file,
continue that numbering (or use any unique string — the app does not require
the `adr-NNNN` shape, only uniqueness). When UPDATING an existing decision,
use its existing `id` exactly.

## 4. Minimal example

```json
{
  "schemaVersion": 1,
  "kind": "crayon-c4-decisions",
  "createdAt": "2026-08-25T00:00:00.000Z",
  "project": "Example Shop",
  "adr": {
    "adrs": [
      {
        "id": "adr-0001",
        "title": "Use PostgreSQL for order storage",
        "status": "accepted",
        "date": "2026-08-01",
        "context": "Orders need transactional writes and relational queries across customers, line items, and payments.",
        "decision": "Store orders in PostgreSQL rather than a document store.",
        "consequences": "Schema migrations are required for structural changes; we gain strong consistency and joinable reporting queries.",
        "categories": ["data"],
        "links": [
          {
            "target": { "kind": "c4-node", "nodeId": "sys-order-db" },
            "name": "Order Database",
            "elementType": "Container"
          }
        ]
      }
    ]
  }
}
```

This example — and any other complete `crayon-c4-decisions` JSON block in
this guide — is checked in CI against the published schema and the app's own
import path, so it is guaranteed to import cleanly.

## 5. Two ways to deliver decisions

- **A stand-alone decisions file** (the shape above) — the only thing it
  changes on import is the `adr` slice.
- **A whole project export** (`crayon-c4.schema.json`, see the sibling
  `AUTHORING-GUIDE.md`) with its own `adr` field set — the Decisions
  screen's Import accepts this too and extracts the `adr` slice
  automatically, so "give me the decisions from that project" does not
  require exporting them separately.

## 6. Where this fits

- JSON Schema: `crayon-c4-decisions.schema.json` (next to this guide) — the
  `adr` field is `$ref`'d straight from `crayon-c4.schema.json`'s
  `$defs/AdrData`, so the two contracts cannot drift apart.
- Field-level reference (TypeScript shapes, full validation rules): see
  `docs/reference/07-adr-schema.md` in the CRAYON-C4 repository.
- Import surface: CRAYON-C4 → open a project → **Decisions** → **Import…**.
