# `.usmatch` JSON format reference

Match Day's match file format. Used for AirDrop / iMessage / Mail / cloud sharing between iOS users and as the Match Builder's download artifact.

> **Schema version:** `1` (matches use v1; the stage JSON schema is v2 — different numbers, do NOT confuse them).

## Top-level fields

| Field | Required | Type | Purpose |
|---|---|---|---|
| `schemaVersion` | yes | integer | Must be `1` |
| `id` | yes | UUID string | Unique match identifier; stable across edits |
| `name` | yes | string | Human-readable match name (must be non-empty after trim) |
| `date` | yes | string (ISO 8601) | Match date, e.g. `"2026-05-30T00:00:00Z"` |
| `stages` | yes | array | Ordered list of stage entries; must have ≥1 entry |
| `notes` | no | string \| null | Match-wide free-text (start time, weather, cold-range reminder) |
| `venue` | no | object \| null | Facility info; see below |
| `matchDirector` | no | object \| null | MD attribution; see below |
| `myStageNotes` | no | array \| null | Per-stage shooter diary entries — leave null when authoring a match TO share (only populated when the shooter is reading) |
| `myMatchNote` | no | string \| null | Shooter's overall match reflection — same: leave null |
| `myResults` | no | object \| null | Shooter's results entry — leave null |
| `myGunID` | no | UUID string \| null | Shooter's gun reference — leave null |

## Stage entry shape

Each item in `stages[]` MUST have **exactly one** of `ref` or `inline` — never both, never neither.

```json
{ "ref": "CM 99-08" }
```

`ref` is the classifier code (with the space). Recipient resolves against their bundled classifier set. Compact; fails if recipient is on a too-old app version that doesn't have that classifier.

```json
{ "inline": { /* full Stage v2 JSON */ } }
```

`inline` embeds the entire Stage v2 JSON (the same shape produced by Stage Setter — see [Match Day stage schema](https://itsmatchday.app/schema/v2/stage.json)). Self-contained; recipient gets the whole stage regardless of their bundled set.

## Venue object

All fields optional. If you have ANY venue info at all, include the object; otherwise leave `venue: null`.

```json
"venue": {
  "name":      "Brazos Valley Shooting Club",
  "address":   "Bryan, TX 77803",
  "rules":     "USPSA handgun. Major power factor only. Holsters must be Level 3+.",
  "parking":   "Gravel lot, east side of range. Limited to ~20 vehicles.",
  "restrooms": "Portable restrooms at clubhouse.",
  "contact":   "MD: Jory Hanus, (979) 555-1234"
}
```

## Match Director object

```json
"matchDirector": {
  "name":  "Jory Hanus",
  "uspsa": "A12345",
  "email": "jory@example.com"
}
```

- `name` required if the object is present
- `uspsa` and `email` are optional

## Date format

Always ISO 8601 with a `Z` suffix (UTC). Examples:
- `"2026-05-30T00:00:00Z"` — Saturday May 30
- `"2026-06-07T14:30:00Z"` — Saturday June 7 at 2:30 PM UTC

If the user gives you a vague date ("next Saturday"), resolve it to a specific UTC ISO timestamp. Don't pass through "next Saturday" — the editor's date parser expects a real date.

## Complete minimal example

```json
{
  "schemaVersion": 1,
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "APSC Saturday Pistol",
  "date": "2026-05-30T00:00:00Z",
  "stages": [
    { "ref": "CM 99-08" },
    { "ref": "CM 99-28" },
    { "ref": "CM 99-42" }
  ]
}
```

That validates. Adding `notes`, `venue`, `matchDirector` is recommended but not required.

## Export validation

The web Match Builder's "Download .usmatch" button enforces:
1. `name` is non-empty after trim
2. `stages.length >= 1`
3. No stages are in a placeholder / inline-authoring-in-progress state (inline stages must be fully authored)
4. If `inline` stages are present, the user is routed through a credit-review dialog confirming designer attribution

The skill should pre-validate before driving the Match Builder so the user doesn't bounce off the validation dialog.

## What you should NOT include

- `myStageNotes`, `myMatchNote`, `myResults`, `myGunID` — these are shooter-side reflection/diary fields, populated when the user reads a match in the iOS app, not when authoring a match to share. The skill always emits these as `null` (or omits them entirely).
- A `stages[].inline.author` set to anyone other than the actual designer — credit attribution matters and the Match Builder's credit dialog will surface mismatches.

## Filename convention

The skill should write the `.usmatch` file with a clear name. Suggested template:

```
<YYYY-MM-DD>_<slug-of-match-name>.usmatch
```

Examples:
- `2026-05-30_apsc-saturday-pistol.usmatch`
- `2026-06-07_brazos-monthly.usmatch`

The `.usmatch` extension matters — iOS recognizes it for AirDrop handoff.
