# reviewer annotate

```
shadcn-maestro reviewer annotate --input <file|-> [--cwd <path>] [--json]
```

An annotation is a reading of one map subject (a screen, a region or a component): what it is for, why, and the source that shows it. Every accepted annotation starts as `pending` until an [independent review](/cli/review) confirms it.

## Input

The JSON must match the [annotation schema](/cli/schemas#annotation). Fields:

| Field | What to put |
| --- | --- |
| `subjectId` | A screen, region or component id from the map, e.g. `screen:src/pages/Customers.tsx` |
| `expectedMapRevision` | The `revision` printed by `reviewer`; a newer map rejects the submission |
| `expectedAnnotationRevision` | `null` for a first annotation; the current revision to replace one |
| `purpose` | The function of the subject in context, e.g. "list filters" or "primary navigation" |
| `rationale` | Why the evidence supports that purpose |
| `evidence` | `kind` (`source` or `browser`) and `refs`: source references copied from the map |
| `author` | `host` and `session` of the agent execution writing the annotation |
| `sourceHashes` | Path → SHA-256 of every file the subject depends on, as read from the map |

Example, for the Customers screen shown in [reviewer](/cli/reviewer):

```json
{
  "subjectId": "screen:src/pages/Customers.tsx",
  "expectedMapRevision": "f59569dccc26dfb1",
  "expectedAnnotationRevision": null,
  "purpose": "Customer list page: header, search filter and the customers table",
  "rationale": "The screen renders PageHeader, a filter input and a table of customers.",
  "evidence": {
    "kind": "source",
    "refs": [
      {
        "end": {
          "column": 12,
          "line": 44
        },
        "fileHash": "e5044cd33fec21c42e7c2e33329cc1c4ba37009361a821a7b7e9cb1fb0675899",
        "relativePath": "src/pages/Customers.tsx",
        "start": {
          "column": 5,
          "line": 17
        },
        "symbolId": "src/pages/Customers.tsx#Customers"
      }
    ]
  },
  "author": {
    "host": "claude-code",
    "session": "author-session-1"
  },
  "sourceHashes": {
    "src/components/PageHeader.tsx": "9a5d7415b1cf0c729f88df5a07e6d9854e736ceb967b741f01deab214e5bd567",
    "src/pages/Customers.tsx": "e5044cd33fec21c42e7c2e33329cc1c4ba37009361a821a7b7e9cb1fb0675899"
  }
}
```

## Result

```json
{
  "schemaVersion": 1,
  "command": "reviewer annotate",
  "status": "ok",
  "data": {
    "annotationId": "annotation:screen:src/pages/Customers.tsx",
    "revision": 1,
    "status": "pending",
    "evidenceKind": "source",
    "identity": "observed",
    "mapRevision": "f25a810a99ff4ad3",
    "schemaValidation": "passed",
    "semanticReview": "pending"
  },
  "issues": [],
  "nextAction": "Request an independent review of this revision with shadcn-maestro reviewer review --input <file>"
}
```

The annotation is saved as `pending`. `identity` is `observed` when the host exposes its session (`CLAUDE_CODE_SESSION_ID` in Claude Code, `CODEX_SESSION_ID` in Codex) and `declared-only` otherwise. Submitting writes the map, so its revision changes: read it again before the next annotation.

## Errors

All return `status: "error"` (exit `2`) and nothing is saved.

| Issue | Cause | What to do |
| --- | --- | --- |
| `invalid_input` | The file or stdin is not readable JSON | Fix the input |
| `invalid_annotation` | The JSON does not match the schema; the message lists each failure | Fix the fields |
| `identity_mismatch` | `author.session` differs from the session the host exposes | Declare the session of this execution |
| `no_map` | There is no map yet | Run `shadcn-maestro reviewer` |
| `stale_map` | `expectedMapRevision` is not the current revision | Refresh the map, re-read the source, resubmit |
| `unknown_subject` | `subjectId` is not in the current map | Use an id printed by `reviewer` |
| `stale_source` | `sourceHashes` do not match the subject's current dependencies | Refresh the map and resubmit |
| `invalid_reference` | An evidence ref does not point to a mapped file at its current hash | Copy the refs from the current map |
| `stale_annotation` | `expectedAnnotationRevision` is not the current revision | Read the current annotation and resubmit against it |
| `map_update_failed` | The map could not be written | Fix the reported problem and retry |
