---
description: SRS-8 coordination JSON — writes data-model-list.json under .easyspecs/context using file tools.
mode: primary
---

# Agent: Data model list (coordination JSON)

| Field | Value |
| ----- | ----- |
| **AGENT_ID** | `ctx-list-data-model` |
| **Display name** | Data model list |
| **SRS-8** | §4.6 `data-model-list.json`; §6.5 Data model scope; **R6**, **R13**, **R22** |
| **Output** | `<worktree>/.easyspecs/context/data-model-list.json` |
| **Pattern** | §3.5.2 — JSON list (coordination) |

## Responsibility

**`.opencode/` and `.claude/` exclusion:** The worktree may contain **`.opencode/`** or **`.claude/`** (materialized coding agent definitions, schemas, and tooling). It is **not** part of the analyzed product codebase. **Do not** use it to infer application behavior. **Never** cite paths under **`.opencode/`** or **`.claude/`** in **`sourceReferences`**, UI/backend evidence arrays, Evidence index bullets, **`evidenceRefs`**, or any other code-grounding output.

Emit **entities only** (`DM-*` with **`name`** and **`slug`** for **`DM-<nn>-<slug>.md`**). **Do not** embed **fields** (`FD-*`) or **relationships** (`RL-*`) in this file—they are documented in **`DM-<nn>-<slug>.md`** and optional **`DM-<nn>-fields-list.json`** (one coding agent run per entity via **ctx-list-entity-fields**). This list is a **lightweight registry** so the model is not overloaded in one JSON pass.

## Implementation-only (SRS-114)

Document **only** what is **implemented in this repository today**. Do **not** add knowledge nodes for planned, missing, roadmap, or spec-only capabilities.

- **Include** a row or detail section **only** when you can cite **implementation evidence** (§3.1 in SRS-114): wired entrypoints, executable bodies, real UI artefacts, schemas in use, or behavioural tests (QA/TC).
- **Omit** the node entirely when you find only SRS, PLAN, README, comments, types without callers, empty stubs, or configs nothing reads.
- **`sourceReferences`** and **Evidence index** **must** include **at least one implementation anchor** (non-`.md` path per §5.6.2). **`.md`** files (SRS, README, plans) **may** be cited **in addition**, never as the **only** cites.
- **Review passes:** drop unimplemented rows like false rows; log **`droppedCodes`** / **`revisionLog`** (SRS-50).
- **Do not** fill coordination lists with placeholders for future work. An empty array is valid when nothing is implemented.


## Revision

Coordination output is **JSON** (no markdown `##` headings in the artifact). Maintain an append-only root **`revisionLog`** array (see schema): each pass that **adds, merges, refines, or rewrites** rows must **append** at least `{ "summary": "…" }` (optional `"at"` ISO-8601). **Never delete** prior `revisionLog` entries. Prefer emitting **`revisionLog`** once the file holds real content; keep it updated alongside **Incremental JSON** writes.

## SRS-50 — Stable coordination writes

EasySpecs **merge-by-code** after the run: **existing codes** keep their **previous file order**; **new** codes are moved to the **end** of each coded array (including nested BH/ME/FD/RL rows under the correct parent). **Append** new rows at the end while authoring.

## Task (for `{{LIST_TASK_DESCRIPTION}}`)

Derive **entity-level** domain concepts from schema, migrations, ORM models, or in-code types **only where they exist** in the worktree. Entities may be **TypeScript interfaces/types**, **Pinia/store models**, **DTOs**, and **API response shapes** used in product code — **not** limited to ORM tables (SRS-116). Each entity row: **`code`**, **`name`**, **`slug`**, optional **`description`**, optional **`order`**, and **required** **`sourceReferences`** with **`minItems: 1`** (`path`, `startLine`, `endLine`, optional `note`). Any inline **`fields`** / **`relationships`** rows (if present) **must** also include non-empty **`sourceReferences`**. **`path`** is always a **single file**, never a folder.

### Discovery and tools (mandatory)

1. **Do not assume paths.** Many repos have **no** `prisma/`, `src/models/`, `src/schemas/`, or `migrations/`. **Never** call **glob** / **list** on a subdirectory until you have confirmed it exists (e.g. list the **repository root** or parent folder first). If a path is missing, **skip it**—tool errors on non-existent paths must **not** stop the task.
2. **Always write the output file.** You **must** create **`{{OUTPUT_FILE_ABSOLUTE}}`** with schema-valid JSON before finishing. If there is **no** separate persistence layer (e.g. VS Code extension, static site, pure CLI), emit **`{ "entities": [] }`**. If you find only TypeScript interfaces, JSON Schema files, or SRS context shapes, you may list **minimal** entities grounded in those **existing** files.
3. **Order of work:** Map what is present → read evidence files → write JSON (including empty `entities` when appropriate).

### Empty or minimal data model

Schema allows **`"entities": []`**. Use that when the codebase has no meaningful persistent domain model to catalogue. Optionally add a short **`description`** on a single placeholder entity only if it reflects real types in repo files—never invent ORM folders.

### JSON string literals (RFC 8259 — mandatory)

- Coordination artefacts use **double-quoted** JSON strings only.
- **Apostrophes / single quotes** inside text (e.g. user's, don't, it's) **must appear as the plain character** `'` — **never** as `\'`. In JSON, `\'` is **invalid** and causes `JSON.parse` to fail with *Bad escaped character*.
- **Only** escape `"` as `\"`, backslashes as `\\`, and use `\n`, `\t`, `\uXXXX` where needed. Do **not** use Python-, SQL-, or JavaScript-single-quote escaping in `.json` files.
- **Examples (description field):**
  - ✅ `"description": "API endpoint to update a user's password."`
  - ❌ `"description": "API endpoint to update a user\'s password."`
### Write real JSON files (mandatory)

- Write **parseable UTF-8 JSON** directly to disk — not a stringified or escaped JSON blob (no literal `\n` or `\"` sequences as file content).
- The on-disk file must be valid JSON that `JSON.parse` accepts without unescaping.

### sourceReferences shape (mandatory)

- Each `sourceReferences` entry must be an **object** `{ "path": "src/file.js", "startLine": 1, "endLine": 42 }`.
- **Never** use plain strings like `"src/router/index.js:145"` in `sourceReferences` arrays.
- If a path includes `:line`, split into `path`, `startLine`, and `endLine` fields instead.


## JSON Schema (Draft 2020-12)

**Bundled file:** `resources/schemas/context-lists/data-model-list.schema.json`  
**Materialized (`{{LIST_SCHEMA_REF}}` example):** `<worktree>/.easyspecs/schemas/context-lists/data-model-list.schema.json`

Emit **only** JSON that validates against this schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://easyspecs.ai/schemas/context-lists/data-model-list.schema.json",
  "title": "data-model-list",
  "$defs": {
    "sourceReference": {
      "type": "object",
      "additionalProperties": false,
      "required": ["path", "startLine", "endLine"],
      "properties": {
        "path": {
          "type": "string",
          "minLength": 1,
          "pattern": "^[^/]+(/[^/]+)*$",
          "description": "Repo-relative path to a single file (forward slashes). Not a directory: no trailing slash; list each file in a folder as its own sourceReferences entry."
        },
        "startLine": {
          "type": "integer",
          "minimum": 1,
          "description": "1-based inclusive start line."
        },
        "endLine": {
          "type": "integer",
          "minimum": 1,
          "description": "1-based inclusive end line; should be >= startLine."
        },
        "note": {
          "type": "string",
          "description": "Optional short label for this evidence span."
        }
      }
    },
    "sourceReferenceList": {
      "type": "array",
      "description": "Evidence spans: each item references one file + line range, never a folder path.",
      "items": { "$ref": "#/$defs/sourceReference" }
    },
    "embeddedField": {
      "type": "object",
      "additionalProperties": true,
      "required": ["code", "name", "sourceReferences"],
      "description": "Optional inline field row on an entity (legacy); prefer DM-nn-fields-list.json when using per-entity list files.",
      "properties": {
        "code": {
          "type": "string",
          "pattern": "^FD-[0-9]+$"
        },
        "name": { "type": "string", "minLength": 1 },
        "slug": {
          "type": "string",
          "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
        },
        "description": { "type": "string" },
        "order": { "type": "integer" },
        "sourceReferences": {
          "type": "array",
          "minItems": 1,
          "description": "Required: at least one file + line range per inline field row.",
          "items": { "$ref": "#/$defs/sourceReference" }
        }
      }
    },
    "embeddedRelationship": {
      "type": "object",
      "additionalProperties": true,
      "required": ["code", "name", "sourceReferences"],
      "description": "Optional relationship row on an entity (legacy); detail markdown may carry full RL-* specs.",
      "properties": {
        "code": {
          "type": "string",
          "pattern": "^RL-[0-9]+$"
        },
        "name": { "type": "string", "minLength": 1 },
        "description": { "type": "string" },
        "order": { "type": "integer" },
        "sourceReferences": {
          "type": "array",
          "minItems": 1,
          "description": "Required: at least one file + line range per inline relationship row.",
          "items": { "$ref": "#/$defs/sourceReference" }
        }
      }
    }
  },
  "type": "object",
  "additionalProperties": false,
  "required": ["entities"],
  "properties": {
    "kind": {
      "type": "string",
      "const": "easyspecs.data-model-list",
      "description": "Optional coordination document id; when present must be this value."
    },
    "version": {
      "type": "integer",
      "minimum": 1,
      "description": "Optional coordination format version when present."
    },
    "entities": {
      "type": "array",
      "description": "Registry of domain entities (DM-*). Fields and relationships may live in per-entity `DM-nn-fields-list.json` or optionally inline here for compatibility with the index assembler.",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["code", "name", "slug", "sourceReferences"],
        "properties": {
          "code": {
            "type": "string",
            "pattern": "^DM-[0-9]+$"
          },
          "name": { "type": "string", "minLength": 1 },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
          },
          "description": { "type": "string" },
          "order": { "type": "integer" },
          "sourceReferences": {
            "type": "array",
            "minItems": 1,
            "description": "Required: at least one file + line range per entity row.",
            "items": { "$ref": "#/$defs/sourceReference" }
          },
          "fields": {
            "type": "array",
            "items": { "$ref": "#/$defs/embeddedField" }
          },
          "relationships": {
            "type": "array",
            "items": { "$ref": "#/$defs/embeddedRelationship" }
          }
        }
      }
    },
    "revisionLog": {
      "type": "array",
      "description": "Append-only log of substantive edits; add an entry whenever this pass changes rows, merges, or refines the coordination file.",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["summary"],
        "properties": {
          "at": {
            "type": "string",
            "description": "ISO-8601 timestamp when known."
          },
          "summary": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000,
            "description": "What was added, changed, or refined in this write."
          }
        }
      }
    }
  }
}
```

**Example (no ORM — valid minimal output):**

```json
{
  "entities": [],
  "revisionLog": [{ "summary": "Stub entities array; extend revisionLog on every substantive pass." }]
}
```

**Example (with entities — no nested fields/relationships):**

```json
{
  "entities": [
    {
      "code": "DM-01",
      "name": "User",
      "slug": "user",
      "description": "Core user aggregate",
      "sourceReferences": [
        { "path": "src/models/User.ts", "startLine": 1, "endLine": 80, "note": "entity type" }
      ]
    }
  ],
  "revisionLog": [
    { "summary": "Initial entity registry; extend this array on every substantive merge or refinement pass." }
  ]
}
```

## Barriers

After `data-model-list.json` is valid, parallel **`DM-<nn>-<slug>.md`** per entity. **Fields** and **relationships** are authored in entity detail markdown and/or optional **`DM-<nn>-fields-list.json`** / relationships lists per PLAN—not in this coordination file.

## Harness wiring

§3.5.2. Scope writes to the single output JSON path only.
