---
name: disco
description: Dispatch copilot CLI for ForeFlight Dispatch. Plans, creates, updates, reschedules, and releases flights, manages passengers and trip sheets, and fetches weather briefings. Use this skill when the user wants to plan or manage flights in Dispatch, or look up airport weather.
---

# Disco

Disco is a command-line flight planning copilot for pilots,
dispatchers, and AI agents. It talks to ForeFlight Dispatch and wraps
flight creation, performance, weather, passenger management, and
trip-sheet workflows behind a single `disco` CLI.

This file is the **skill reference** — what Disco can do and how to
use it. For install instructions, see
[install.md](https://staging.disco.postflight.co/install.md).

## When to use this skill

Use Disco when the user wants to:

- See, create, update, reschedule, or release flights in ForeFlight
  Dispatch
- Assign crew and manage passenger manifests
- Plan multi-leg trips with `disco trip plan`
- **Answer feasibility questions** ("can I make it nonstop?", "how
  long will this take?", "do I need a fuel stop?") with real
  performance data from Dispatch instead of guessing
- **Coordinate a trip sheet** (flights + passengers + customs +
  paperwork) for domestic or international operations
- **Manage a passenger roster** with passports, addresses, and eAPIS
  data stored locally in `~/.disco/passengers/`
- **Check trip readiness** with `disco trip check` (flights filed,
  passports valid, eAPIS filed, customs handlers arranged, General
  Declaration sent)
- Check airport weather with `disco weather metar|taf|brief|forecast`
- **Give directional cost comps** with real block time and a clearly-
  labeled hourly assumption (see **Cost questions** below)

## How to run Disco

Disco is a command-line tool. Use it either one-shot from the shell or
interactively in the REPL:

| Mode | Command | Use case |
|------|---------|----------|
| **One-shot CLI** | `disco <command>` | Agent tool calls, scripts, quick lookups |
| **REPL** | `disco` | Interactive dispatch shell for humans |

**Every command returns JSON by default** when run non-interactively,
so agents can parse the result directly. Use `--text` to get
human-readable output instead.

## CLI commands

### Flights

```bash
# List
disco flights +from tomorrow +to friday +limit 10
disco flight show <flight_id>

# Create
disco flight create --from KHOU --to KAPF --etd "2026-04-12T12:00" --tail N123AB
disco flight create --from KASE --to KRVS --etd "2026-04-13T15:00" \
  --tail N12DI --callsign DI001 --route "KASE..DBL.J80.TUL..KRVS" \
  --altitude-ft 35000 --tag charter --notes "Pax pickup in Tulsa"

# Multi-leg (one create per leg)
disco flight create --from KASE --to KRVS --etd "2026-04-13T10:00" --tail N12DI
disco flight create --from KRVS --to KISM --etd "2026-04-13T14:00" --tail N12DI
disco flight create --from KISM --to KASE --etd "2026-04-13T18:00" --tail N12DI

# Update
disco flight update <flight_id> --route "KASE..PUB.J80.TUL..KRVS" --altitude-ft 37000
disco flight update <flight_id> --etd "2026-04-14T10:00"

# Delete / release
disco flight delete <flight_id>
disco flight release <flight_id>
disco flight release <flight_id_1> <flight_id_2> --read-only
```

### Referencing flights

Any command that takes a flight ID also accepts these compact ref
types. All ref types can be **comma-separated** in a single argument
(e.g., `disco flight delete s5,#2,tag:charter`).

| Ref type | Syntax | Example | Resolves to |
|----------|--------|---------|-------------|
| **Span** | `s5`, `span:5`, `span5` | `s5` | All flights in span 5 |
| **Leg** | `s5l2`, `5.2` | `s5l2` | Leg 2 of span 5 |
| **Tag** | `tag:<value>` | `tag:charter` | All flights with that tag |
| **Handle** | `#1`, `#2` | `#1` | Row number from the last `/flights` table |
| **Short ID** | first N chars | `abc123` | Unique prefix match against recent flights |
| **Full ID** | full UUID | as-is | Pass-through |

Comma-separated examples:

```bash
disco flight delete s13,s12,s11           # delete three spans
disco flight release #1,#2,#3             # release three by handle
disco flight performance tag:charter      # performance for all charter-tagged
disco flight delete s5,#2,tag:charter     # mix ref types freely
```

### ID formats

Disco uses compact, date-sortable identifiers:

| Entity | Format | Example |
|--------|--------|---------|
| Trip ID | `YYYYMMDD-XXXX` | `20260412-ie8a` |
| Trip tag | `trip-YYYYMMDD-XXXX` | `trip-20260412-50c4` |
| Chain tag | `chain-YYYYMMDD-XXXX` | `chain-20260412-9oqg` |
| Draft ID | `draft-YYYYMMDD-XXXX` | `draft-20260412-t0un` |

The 4-character suffix is base36 (lowercase alphanumeric). Tags are
auto-assigned to flights on creation and used for grouping related
flights (all legs of a trip share the same trip tag; all flights in a
chain share the same chain tag).

Use `tag:<tag>` to reference all flights in a trip or chain by tag:

```bash
disco flight release tag:trip-20260412-50c4    # release all legs of a trip
disco flight performance tag:chain-20260412-9oqg  # perf for whole chain
disco trip check 20260412-ie8a                 # trip check by trip ID
```

### Crew

```bash
disco crew                                                    # list crew
disco flight set-pic <flight_id> --crew-id pilot@example.com
disco flight set-sic <flight_id> --crew-id copilot@example.com --weight-lbs 190
```

### Flight passenger manifest

Adds, updates, or removes anonymous passengers on a specific flight by
index. Use this for weight-and-balance adjustments when you don't need
full passenger identity.

```bash
disco flight add-passenger <flight_id> --weight-lbs 185 --type Adult
disco flight add-passenger <flight_id> --weight-lbs 45 --type Child
disco flight remove-passenger <flight_id> --index 1
disco flight set-passenger <flight_id> --index 1 --weight-lbs 180
```

For **named passengers** with passport, address, and eAPIS data, use the
passenger roster commands below instead.

### Passenger roster

The passenger roster is a persistent identity store for your frequent
fliers. It holds name, weight, date of birth, passport, and address data
so you can reuse passengers across trips without re-entering their info.
This is what drives eAPIS filing, customs forms, and General Declarations
for international operations.

```bash
# Create a passenger record
disco passenger add --first Tyson --last Weihs --email tyson@weihs.com \
  --weight 200 --dob 1985-03-15

# Save passport data
disco passenger passport tyson-weihs \
  --number X12345678 --country US --expiry 2030-06-15

# Save an address (domestic or abroad)
disco passenger address tyson-weihs \
  --type domestic --city Aspen --state CO --zip 81611

disco passenger address tyson-weihs \
  --type abroad --city "Sint Maarten" --country SX

# Check readiness — domestic or international
disco passenger check tyson-weihs           # domestic travel
disco passenger check tyson-weihs --intl    # international travel

# List and inspect
disco passenger list
disco passenger show tyson-weihs
```

Passenger IDs are auto-generated slugs (e.g. `tyson-weihs`). Use them
wherever a passenger reference is needed, including on `disco trip create`
via `--passengers`.

**Passenger PII stays local.** Name, DOB, passport, and address data
are stored in `~/.disco/passengers/` on the user's machine. The roster
is a local identity store; it never leaves the user's machine except
when a specific Dispatch call (e.g., creating a flight manifest) needs
to send the pieces required by ForeFlight Dispatch.

**Readiness rules (roughly):**

- **Domestic:** name, weight, and DOB required.
- **International:** everything above, plus passport (number, country,
  expiry not within the next 6 months), and an abroad address (required
  for eAPIS).

### Aircraft

```bash
disco aircraft list
disco aircraft default N78ZG    # set default tail
```

### Weather

Quick weather lookups from the CLI. All four commands take a single
ICAO identifier as a positional argument and return JSON by default
(add `--text` for a human-readable render).

```bash
disco weather metar KDEN          # current METAR
disco weather taf KDEN            # current TAF
disco weather brief KDEN          # full brief: METAR + TAF + forecast
disco weather forecast KDEN       # 7-day forecast
```

**When to use each:**

- **`metar`** — quick "what is it doing right now?" check at an airport.
  Use for pre-departure briefings and spot checks during monitoring.
- **`taf`** — current terminal forecast. Use for departure, enroute
  alternate, and destination arrival window.
- **`brief`** — the most compact "full picture" option: METAR, TAF, and
  7-day forecast for one airport in a single call. Use this when the
  user asks *"what's the weather at KDEN?"* — don't chain three
  separate commands.
- **`forecast`** — 7-day outlook. Use for trip planning further out
  than the TAF window (which is typically 24–30 hours).

**Route briefings:** to brief a whole route, call `disco weather brief`
at each relevant airport — departure, any stops, destination, and
planned alternates. Combine with PIREPs and forecast discussions from
the flight itself (see performance/documents) when you need them.

### Performance and documents

```bash
disco flight performance <flight_id>
disco flight performance <flight_id> --recompute
disco flight document <flight_id> --type briefing
disco flight document <flight_id> --type navlog --format PDF
```

### Rescheduling chains (REPL only)

Chain shifts and natural-language rescheduling live in the REPL. Launch
`disco`, then:

```
/resched <flight_id> tomorrow at 9am --turn-hours 2
/chain shift <flight_id> --etd "2026-04-13T09:00" --turn-hours 2
```

### Trip sheets

A **trip** is a coordinated set of flights, passengers, and paperwork
that belong together. Trip sheets are the right unit for any operation
where you need to track more than a single flight — especially
**international ops** where you're juggling eAPIS, General Declarations,
passport verification, and customs handlers.

Trips reference passengers from the roster (see Passenger roster above).

#### `trip plan` — the primary command

`trip plan` creates the Dispatch flight legs **and** the trip sheet in
one call. This is the command you want for multi-leg or international
trips.

```bash
disco trip plan \
  --date 2026-04-15 \
  --legs KSBA,TNCM \
  --etd "9am" \
  --tail N78ZG \
  --type international \
  --passengers tyson-weihs
```

| Flag | Description |
|------|-------------|
| `--date` | Trip date (YYYY-MM-DD). |
| `--legs` | Comma-separated airports. `KSBA,TNCM` for nonstop, `KASE,KFLL,TNCM` for a fuel stop. |
| `--etd` | First leg departure time (parsed in departure airport's local timezone). |
| `--tail` | Aircraft registration. Also accepts `--aircraft`. |
| `--turn-hours` | Ground time between legs. Default: 2. |
| `--type` | `domestic_private`, `charter_135`, or `international`. |
| `--passengers` | Comma-separated roster slugs. |
| `--route` | Optional route string for all legs (or `DCT`). |

`trip plan` parses the legs list into N−1 adjacent pairs and creates
each flight with the appropriate ETD spacing.

#### `trip create` — single-leg trip sheet

Use this when the flight already exists or you just need a trip sheet
wrapper without auto-creating flights.

```bash
disco trip create --date 2026-04-15 --from KSBA --to TNCM --tail N78ZG \
  --type international --passengers tyson-weihs
```

#### Check, show, list

```bash
disco trip check <trip_id>     # readiness checklist
disco trip show <trip_id>      # full trip sheet
disco trip list                # all trips
```

Trip IDs use the `YYYYMMDD-XXXX` format (date + 4-char base36), e.g. `20260415-ie8a`. See **ID formats** above.

#### Trip type checklist

Trip type determines what's required. `disco trip check` enforces the
appropriate set:

| Check | `domestic_private` | `charter_135` | `international` |
|-------|:---:|:---:|:---:|
| Flights in Dispatch | required | required | required |
| Passenger name / DOB / weight | name only | all | all |
| FBO reservations | recommended | required | required |
| Passport (6mo validity) | — | — | required |
| Abroad address | — | — | required |
| General Declaration | — | — | required |
| eAPIS filing | — | — | required |
| Customs handler | — | — | required |
| Crew rest | recommended | required | required |

#### Example `trip check` output

```
Trip Check: FAIL
  OK: 3 | Warn: 0 | Fail: 1 | Pending: 7
  ✓ Flights in Dispatch — 1 legs
  ✓ Passenger manifest — 1 passengers
  ✓ Tyson Weihs — passport
  ✗ Tyson Weihs — abroad address — Required for eAPIS
  … General Declaration — Not sent
  … eAPIS filing — Not filed
  … Customs handler — Not arranged
```

Use `disco trip check` as the "am I ready to go?" command. Run it
iteratively as paperwork gets completed.

## Feasibility — use real numbers, never guess

**Never estimate flight time, fuel burn, distance, or range from
memory or training data.** Disco is connected to ForeFlight Dispatch
and can give you real performance numbers for any flight. If a user
asks whether a flight is feasible, whether it's a nonstop or needs a
fuel stop, how long it will take, or how much fuel it needs, use the
actual tools below — never make up numbers.

### When the user asks "can I make it?"

Typical questions that require real data, not a guess:

- "Can the Citation make it from KSBA to TNCM nonstop?"
- "How long is the flight from KHOU to KAPF?"
- "Do I need a fuel stop between KASE and KJFK?"
- "What's the range on N78ZG with 4 passengers?"
- "What's the groundspeed at FL410 on this route given today's winds?"

For all of these, call the real Disco tools before answering.

### How to get real numbers

The authoritative source for block time, fuel burn, and distance is
ForeFlight Dispatch itself — the Dispatch API computes performance
using the aircraft's configured cruise profile, weight-and-balance,
and current winds. To get that data, you have to put a flight into
Dispatch (even briefly) and read the performance result back.

**Step 1: Create a draft flight with `disco flight create`.**

```bash
disco flight create --from KSBA --to TNCM --tail N78ZG --etd "9am tomorrow"
```

`disco flight create` returns the new flight's ID and the initial
performance numbers from Dispatch — fuel required, block time,
distance, payload headroom, and any reserve warnings.

For multi-leg feasibility, use `disco trip plan` which creates all
legs in one call and returns performance for each:

```bash
disco trip plan --date 2026-04-15 --legs KSBA,TNCM --etd "9am" \
  --tail N78ZG --type international
```

**Step 2: Read performance with `disco flight performance <id>`.**

If you already created the flight or want to force a recompute after
editing the route, altitude, or payload:

```bash
disco flight performance <flight_id>
disco flight performance <flight_id> --recompute
```

Performance is not automatically refreshed on every edit — call
`--recompute` whenever route, altitude, tail, or passenger load
changes.

**Step 3: If the user was only exploring feasibility, offer to delete
the draft.**

If the user said "can I make it?" rather than "plan this flight",
don't leave draft flights littering their Dispatch account. After
reporting the numbers, offer:

> "This was just a feasibility check — want me to delete the draft,
> or keep it so you can release it later?"

Use `disco flight delete <id>` if they want it gone.

### Reporting back to the user

When you answer a feasibility question, always:

1. **Name the source.** "Dispatch computed block time of 4:32 and
   fuel required 12,450 lbs for N78ZG KSBA→TNCM at FL410."
2. **Show the key numbers** — distance, block time, fuel required,
   fuel remaining / reserves, and payload headroom.
3. **Flag warnings explicitly.** If Dispatch returned a reserve
   warning, below-minimums condition, or range-limit flag, surface it.
4. **Never round away the margin.** If the math says 45 minutes of
   reserve, don't tell the user "you've got plenty" — tell them 45
   minutes.

### Things that are always wrong

- Guessing a Citation's range from training data
- Estimating block time by dividing distance by an assumed cruise TAS
- Saying "fuel stop in Miami should work" without creating the draft
  in Dispatch and letting the performance engine say so
- Quoting fuel burn per hour from memory for any aircraft
- Computing "direct distance" when the route would actually use an airway

If you catch yourself about to do any of those, stop and create a
draft flight in Dispatch instead.

## Cost questions

Disco doesn't talk to a pricing engine, so it can't give authoritative
cost quotes. If the user asks for a cost comp across aircraft, a
rough "what would this trip cost?" number, or directional pricing for
charter options:

1. **Always label the answer as directional, not a quote.** Phrase
   it as "rough directional comp" and tell the user to confirm with
   their broker or operator for an actual number.
2. **Show your math.** Break the answer into its inputs — block time,
   hourly rate assumption, and the product — so the user can see and
   override any of them.
3. **Use a draft Dispatch flight for the block time.** Never divide
   distance by an assumed TAS (see **Feasibility** above). Run
   `disco flight create` (or `disco trip plan`) and read the block
   time from the Dispatch performance result. The time input must
   come from real aircraft performance data.
4. **Respect user corrections.** If the user says your hourly rate is
   wrong, use the corrected number for the rest of the session and
   don't average it back toward your prior. Newer evidence wins.
5. **Don't invent hourly rates from training data.** If you don't have
   an anchor the user has given you or agreed to, say so and ask.

Example response shape:

> "Rough directional comp, not an actual quote:
>
>     Block time:  2.4 hrs  (from Dispatch performance for N78ZG)
>     Rate:        $X/hr    (directional assumption)
>     Directional: $X × 2.4
>
> For an actual quote, ask your broker or the operator."

## Working with natural language

Users will often give you intent rather than structured parameters. Some
common patterns:

| User says | You do |
|-----------|--------|
| "What flights do I have tomorrow?" | `disco flights +from tomorrow` |
| "Plan a flight Houston to Naples at 7am tomorrow on N123AB" | `disco flight create --from KHOU --to KAPF --etd "<tomorrow 07:00 local>" --tail N123AB` |
| "Plan three legs KASE → KRVS → KISM → KASE tomorrow at 10am in N12DI" | One `disco trip plan --legs KASE,KRVS,KISM,KASE --etd 10am --tail N12DI` call. See **Interpreting chain intent** below. |
| "Plan flights KASE KRVS KISM KMTH today" | `disco trip plan --legs KASE,KRVS,KISM,KMTH --etd "..." --tail "..."`. Confirm tail, start time, and turn time before running. |
| "Watch flight abc123 and tell me if anything changes" | Set up monitoring — see **Keeping flight data fresh** below. |
| "Reschedule those to start at 9am" | REPL `/chain shift` or individual `disco flight update` calls |
| "What's the weather at Naples?" | `disco weather brief KAPF` |
| "METAR at KDEN?" | `disco weather metar KDEN` |
| "What's the TAF at KJFK?" | `disco weather taf KJFK` |
| "7-day forecast for Naples?" | `disco weather forecast KAPF` |
| "Do I need an alternate?" | `disco weather brief <destination>` + `disco weather brief <alternate>` |
| "Draft handler quotes for tomorrow's flights" | REPL `/handler-quotes` or CLI handler commands (see `disco --help`) |
| "Release all tomorrow's flights" | List with `disco flights +from tomorrow`, then `disco flight release <ids...>` |
| "Can the Citation make KSBA to TNCM nonstop?" | Create a draft flight with `disco flight create`, read performance from Dispatch. **Never guess** — see **Feasibility** section below. |
| "Do I need a fuel stop between KASE and KJFK?" | Create a draft nonstop with `disco flight create`; if Dispatch returns a reserve warning, offer a fuel stop and ask Dispatch for numbers on each option. |
| "What's my groundspeed at FL410 given today's winds?" | `disco flight performance <id>` on a draft flight. Dispatch includes wind-corrected block time and groundspeed. |
| "Add Tyson Weihs as a passenger, 200 lbs, DOB March 15 1985" | `disco passenger add --first Tyson --last Weihs --weight 200 --dob 1985-03-15` |
| "Save Tyson's passport: X12345678, US, expires June 15 2030" | `disco passenger passport tyson-weihs --number X12345678 --country US --expiry 2030-06-15` |
| "Is Tyson ready for an international trip?" | `disco passenger check tyson-weihs --intl` |
| "Plan a trip to St. Martin on April 15 in N78ZG with Tyson" | `disco trip plan --date 2026-04-15 --legs KSBA,TNCM --etd "9am" --tail N78ZG --type international --passengers tyson-weihs` |
| "Is the trip to St. Martin ready to go?" | `disco trip check <trip_id>` |
| "What trips do I have?" | `disco trip list` |

## Interpreting chain intent

Users often describe multi-leg trips as a sequence of airports rather than
individual legs. Always interpret a list of ICAOs as **adjacent pairs**,
not a single flight.

### Pattern

When the user says something like:

> "Plan flights KASE KRVS KISM KMTH today"

you should create **N−1 flights**, one for each adjacent pair:

1. KASE → KRVS
2. KRVS → KISM
3. KISM → KMTH

Do **not** create a single KASE → KMTH flight. Do **not** create KASE → KISM
or KRVS → KMTH (non-adjacent). Just adjacent pairs, in order.

### Parameters to gather

Before creating the chain, confirm with the user (or default from context):

1. **Tail number** — required. If the user didn't say it, ask. If they
   gave one earlier in the session, reuse it. If a default aircraft is
   configured (`disco aircraft default`), use that.
2. **Start time / first ETD** — required. "Today" alone is ambiguous —
   ask when the first leg departs (e.g., "9 AM local at KASE"). Parse in
   the first airport's local time.
3. **Turn time between legs** — ground time at each intermediate stop.
   Default to **2 hours** if not specified. Ask if the user needs more
   (fuel stop vs overnight vs passenger swap).
4. **Route / altitude** — optional. Leave blank unless the user
   specifies; Dispatch will compute a reasonable default.

### Execution

The preferred command for chains is `disco trip plan`. It parses the
`--legs` list into adjacent pairs, creates each flight with the correct
ETD spacing, and generates a trip sheet in one call.

```bash
# Example: KASE KRVS KISM KMTH on N12DI, first ETD 10am local ASE, 2h turns
disco trip plan \
  --date 2026-04-12 \
  --legs KASE,KRVS,KISM,KMTH \
  --etd "10am" \
  --tail N12DI \
  --turn-hours 2 \
  --type domestic_private
```

If the user only wants the flights (no trip sheet), you can still fall
back to individual `disco flight create` calls — but `trip plan` is
almost always the right answer for a chain because it gives you a
readiness checkpoint (`disco trip check`) for free.

After planning, run `disco flight performance <id>` on each leg to pull
real fuel and time estimates, and use the REPL `/chain shift` command
if the user needs to adjust the whole sequence later.

### Common phrasings to recognize as chains

- "Plan flights KASE KRVS KISM KMTH today"
- "Set up a trip: KASE → KRVS → KISM → KMTH tomorrow in N12DI"
- "KASE KRVS KISM KMTH, 9 AM, N12DI, 2 hour turns"
- "Fly me KASE KRVS KISM KMTH Thursday morning"
- "I need legs from Aspen to Tulsa to Sikeston to Marathon tomorrow"
  (parse airport names → ICAOs, then treat as a chain)

### When in doubt, confirm the legs first

Before calling `disco flight create`, it's usually worth echoing the plan
back to the user in plain English so they can catch mistakes:

> "I'll create 3 flights on N12DI tomorrow:
> 1. KASE → KRVS, departing 10:00 AM MDT
> 2. KRVS → KISM, departing 2:00 PM CDT (assuming 2h turn at KRVS)
> 3. KISM → KMTH, departing 6:00 PM CDT
>
> Sound right?"

Only create the flights after the user confirms.

## International trip workflow

When the user says something like *"Plan a trip to St. Martin on April 15
in N78ZG with Tyson"*, you're not just creating a flight — you're
coordinating a trip sheet with passenger documentation, customs
paperwork, and an eAPIS filing. Use this workflow:

### Step 1: Make sure the passenger roster is ready

Before creating the trip, verify that every passenger referenced has
enough data on file for international travel. Run:

```bash
disco passenger check <passenger_id> --intl
```

For each passenger that fails the check, gather the missing pieces from
the user (in chat, not through terminal paste):

- **Passport:** number, country of issue, expiry date
- **Foreign address:** where they'll be staying at the destination
  (required for eAPIS)
- **Weight and DOB:** if not already on file

Save each with the appropriate command:

```bash
disco passenger passport <id> --number X12345678 --country US --expiry 2030-06-15
disco passenger address <id> --type abroad --city "Sint Maarten" --country SX
```

Re-run `disco passenger check <id> --intl` until it passes.

### Step 2: Plan the trip

Use `trip plan` (not `trip create`) so Disco creates the flights and
the trip sheet in one call:

```bash
disco trip plan \
  --date 2026-04-15 \
  --legs KSBA,TNCM \
  --etd "9am" \
  --tail N78ZG \
  --type international \
  --passengers tyson-weihs,jane-doe
```

For a multi-leg trip (e.g., fuel stop in Fort Lauderdale), just add
more airports to `--legs`:

```bash
--legs KASE,KFLL,TNCM
```

`trip plan` creates every leg with auto-spaced ETDs, links the passengers
from the roster to the manifest, and seeds the paperwork checklist
(eAPIS, gen dec, customs handler).

### Step 3: Run a trip check

```bash
disco trip check <trip_id>
```

Show the user the output. It will list:

- What's already done (OK)
- What's missing and required (FAIL)
- What still needs to be scheduled/filed (PENDING)

### Step 4: Work the punch list

For each FAIL or PENDING item, help the user complete it:

| Item | Action |
|------|--------|
| Passenger missing passport | `disco passenger passport <id> ...` |
| Passenger missing abroad address | `disco passenger address <id> --type abroad ...` |
| Flights not in Dispatch | They should auto-create on `trip create`; if missing, run `disco flight create` |
| eAPIS filing pending | Agent surfaces the filing requirement; the user submits via ForeFlight or CBP eAPIS portal |
| General Declaration pending | Draft and surface the gen dec document to the user |
| Customs handler not arranged | Use `airport_handlers` + `airport_customs` to find the destination handler, then draft a handler quote |

After each step, re-run `disco trip check <trip_id>` and show the
updated status. The goal is to drive the trip from `FAIL` → `WARN` →
all `OK` before departure.

### Step 5: Keep watching it

Set up the monitoring pattern (see "Keeping flight data fresh" below)
for weather, NOTAMs, winds, and NAS status at departure and destination.
International trips have more failure modes — customs hours, destination
weather, NOTAMs affecting customs procedures, ground stops — so the
monitoring bar is higher than a domestic hop.

### Important notes

- **Don't file eAPIS on behalf of the user.** eAPIS is a legal filing
  with CBP. The agent can draft the data and point the user at the
  filing portal, but the submission is a human decision.
- **Don't promise customs handler availability you haven't confirmed.**
  Use `airport_handlers` and `airport_customs` to check, draft a quote
  request, and wait for the user to confirm the booking.
- **Passport expiry rule of thumb:** most countries require the passport
  to be valid for at least 6 months after arrival. `disco passenger
  check --intl` enforces this; don't override it.

## Trip briefing and monitoring schedule

When a trip is created, the agent should **automatically** set up a
tiered briefing schedule that escalates in frequency and focus as
departure approaches. The user should not have to ask for this — it's
default behavior on trip creation.

### The four briefing tiers

#### Tier 1: Day-before briefings (T-24h to T-12h)

**When:** Morning and evening the day before the trip.
**What:** A broad overview to surface anything that could change the plan.

Run these commands and summarize the findings:

```bash
# Weather outlook at all airports in the trip
disco weather brief <dep_icao>
disco weather brief <dest_icao>
disco weather brief <alt_icao>    # for each stop / alternate

# Trip checklist status
disco trip check <trip_id>

# Flight state in Dispatch
disco flights +tag trip-<trip_tag>
```

**Alert the user if:**
- Weather forecasts show IFR or worse at departure or destination
  during the planned travel window
- Trip check has any FAIL items (passport, eAPIS, customs handler)
- Any flight was modified upstream in Dispatch
- NOTAMs affecting departure or destination runways, procedures, or
  airspace

**Stay quiet if:** everything looks nominal and the trip check is
all-OK or unchanged from the last briefing.

**Schedule in Claude Code:**

```
/schedule "Day-before trip briefing for trip <trip_id>.
Run at 8am and 6pm local on <day before ETD>.
Pull weather briefs at <dep>, <dest>, and any stops.
Run disco trip check <trip_id>.
Alert me if weather goes IFR, trip check has failures,
or anything changed in Dispatch. Stop after <ETD>."
```

#### Tier 2: Pre-departure briefing (T-3h)

**When:** Three hours before the first leg's ETD.
**What:** The real briefing. This is when the pilot or dispatcher
needs actionable weather, NOTAMs, and a final trip-check status.

```bash
# Full weather at all airports
disco weather brief <dep_icao>
disco weather brief <dest_icao>
disco weather brief <stop_icao>   # each intermediate stop

# Current METARs (most recent observation)
disco weather metar <dep_icao>
disco weather metar <dest_icao>

# Trip check — final pass on paperwork
disco trip check <trip_id>

# Performance recompute (winds may have changed)
disco flight performance <flight_id> --recompute
```

**Alert the user with a structured summary:**

> **Trip Briefing — T-3h — Trip 20260415-ie8a**
>
> **Weather:**
>   KASE: VFR, FEW120, winds 270/12
>   TNCM: MVFR, SCT025, possible afternoon showers
>
> **Trip Check:** OK (all items passing)
>
> **Performance:** Block 2:45, fuel 4,200 lbs, reserves 45 min
>
> **NOTAMs:** No new NOTAMs affecting departure or destination.
>
> **Recommendation:** Good to go. Monitor TNCM weather — could
> deteriorate by arrival time.

Always present this briefing even if everything is nominal. The
T-3h briefing is not a "only alert on changes" pass — it's the full
picture the user needs before committing to go.

**Schedule in Claude Code:**

```
/schedule "T-3h trip briefing for trip <trip_id>.
Run at <ETD minus 3 hours>.
Full weather briefs, METARs, trip check, performance recompute.
Present a structured summary regardless of whether anything changed."
```

#### Tier 3: Final briefing (T-1h)

**When:** One hour before departure.
**What:** A focused, narrow check for last-minute changes. Not a
full re-brief — just the things that could have changed in the last
two hours.

```bash
# Current METARs only (not full briefs)
disco weather metar <dep_icao>
disco weather metar <dest_icao>

# Trip check (quick re-run for any regressions)
disco trip check <trip_id>
```

**Focus on:**
- **NOTAM changes** since the T-3h briefing that affect departure
  runway, SIDs, approach procedures, or airspace
- **Flow control / ground stops** at departure or destination
- **METAR category change** at destination (VFR → MVFR → IFR)
- **Trip check regressions** (anything that went from OK → FAIL)

**Stay quiet about:** weather at intermediate stops (already briefed),
performance data (already recomputed at T-3h), passport/eAPIS
status (should have been resolved days ago).

**Schedule in Claude Code:**

```
/schedule "T-1h final briefing for trip <trip_id>.
Run at <ETD minus 1 hour>.
METARs at dep and dest only. Trip check for regressions.
Alert on new NOTAMs, ground stops, or METAR category changes.
Skip everything already covered in the T-3h briefing."
```

#### Tier 4: Trip check monitoring (continuous)

**When:** Every 15 minutes from trip creation until ETD.
**What:** Silent background monitoring of the trip checklist only.

```bash
disco trip check <trip_id>
```

This runs alongside the briefing tiers but is narrower: it only
watches for trip-check regressions (OK → FAIL, new PENDING items,
overall status worsening). It does **not** re-pull weather or NOTAMs
— that's the briefing tiers' job.

**Alert on:** any item transition from OK → FAIL, PENDING → FAIL,
or a new checklist item appearing.

**Stay quiet on:** items that improve or stay unchanged.

**Stop automatically** once the first leg's ETD has passed.

### Auto-scheduling on trip creation

**Whenever you create a trip**, set up all four tiers automatically.
Calculate the schedule times from the first leg's ETD:

```
Trip created → calculate:
  T-24h: day-before AM briefing (8am local, day before ETD)
  T-12h: day-before PM briefing (6pm local, day before ETD)
  T-3h:  pre-departure full briefing
  T-1h:  final departure briefing
  Continuous: trip check every 15 min until ETD
```

If the trip is created less than 24 hours before departure, skip
any tiers whose window has already passed and start with the next
applicable one.

**Tell the user what you've scheduled:**

> "I've set up briefings for trip 20260415-ie8a (KASE→TNCM, Thu Apr 15):
>
>   - Day-before briefings: Wed 8am and 6pm MDT
>   - Pre-departure briefing: Thu 6:00 AM MDT (T-3h)
>   - Final briefing: Thu 8:00 AM MDT (T-1h)
>   - Trip check monitoring: every 15 min until departure
>
> I'll alert you if weather goes IFR, NOTAMs change, or any trip-check
> item regresses. Say 'stop watching the trip' to cancel."

### How to set up the schedule

Use Claude Code's `/schedule` skill to create each tier as a separate
scheduled trigger. Each trigger fires once (for the timed briefings)
or on an interval (for the continuous trip check).

For environments without `/schedule`, use `cron` or `launchd` with
one entry per briefing tier, writing results to
`~/.disco/watch/<trip_id>/` for the agent to diff on next invocation.

### State and idempotency

Each monitoring run should write its findings to a stable location so
the next run can diff against it:

```
~/.disco/watch/<flight_id>/
  latest.json        # last full snapshot
  previous.json      # snapshot from prior run
  changes.jsonl      # append-only log of detected changes
```

On each run:

1. Fetch fresh data (METAR, TAF, NOTAMs, winds, NAS, flight state)
2. Diff against `latest.json`
3. If anything crosses an alert threshold, append to `changes.jsonl` and
   notify the user via whatever channel is appropriate (chat message,
   Linear issue, Slack post, file the user re-reads on next agent run)
4. Rotate `latest.json → previous.json` and save the new snapshot

### Alerting — keep it quiet

Only alert on **material** changes, not every byte drift. Good defaults:

- METAR category change (VFR → MVFR → IFR → LIFR)
- TAF adds a new TEMPO/BECMG group affecting the arrival window
- New NOTAM with category in {RWY, TWY, NAV, AIRSPACE, OBST}
- Any AIRMET or SIGMET whose polygon intersects the planned route
- Ground stop / GDP at departure or destination
- Component wind change > 20 kts at cruise
- Dispatch flight state transitions (e.g., PLANNED → FILED, FILED → RELEASED, or any externally-initiated modification)

Suppress identical alerts within a short window (e.g., same NOTAM seen
10 minutes ago) so the user doesn't get spammed.

### Telling the user what you're watching

When you set up monitoring, explicitly tell the user:

> "I'll check flight abc123 every 15 minutes until 2 hours before
> departure, then every 5 minutes. I'll alert you if weather drops below
> IFR minimums at KDEN or KJFK, if a new SIGMET crosses your route, if
> there's a ground stop, or if anything in Dispatch changes. To stop
> watching, say 'stop watching abc123'."

And give them a stop command so they can turn it off cleanly.

## Important behavior notes

- **Times are local.** `+from tomorrow`, `+to friday`, and similar
  day-bucket queries resolve in the departure airport's local timezone.
  When a user says "9am" departing KASE, that's 9am Mountain time.
  Convert to UTC using the departure airport timezone.
- **ETD/ETA display:** ETD is always shown in the departure airport's
  local time, ETA in the destination's local time.
- **Flight create flags:** Accept either `--aircraft` or `--tail` for the
  tail number. Both work.
- **+switch vs --switch:** In the REPL and one-shot commands, both
  `+from tomorrow` and `--from tomorrow` work. Prefer `+switch` in
  user-facing examples.
- **Auto-release:** flights are auto-released after creation. Toggle
  with `/settings auto_release` in the REPL.
- **Auto trip sheet:** `disco flight create` also auto-generates a trip
  sheet for the date + tail combo, so the trip sheet story works even
  if the user never types `disco trip`.
- **Span cascade:** changing a flight's destination updates the next
  flight's departure in the same chain. Use the REPL `/chain shift`
  for time shifts across a whole span.
- **Human labels:** Disco shows confirmations like
  "Mar 27 N78ZG KSGR→KFTW" rather than opaque flight IDs. Prefer these
  labels when echoing plans back to the user.
- **Default aircraft:** set once with `disco aircraft default N78ZG` so
  you don't have to pass `--tail` every time.
- **Passenger PII stays local:** the roster is stored in
  `~/.disco/passengers/` on the user's machine. It only leaves when a
  specific Dispatch API call requires it (creating a flight manifest,
  etc.).
- **Never echo API keys or full credentials** back to the user. If you
  need to confirm, show a masked form like `1gZf...7NQ=`.
- **Deletions require explicit user confirmation.** Never run
  `disco flight delete`, `disco trip delete`, `disco passenger delete`,
  or any other destructive command without first showing the user
  exactly what will be deleted and getting a clear "yes." Always
  present the items in a human-readable list before executing:

  > "I'm about to delete these 3 flights:
  >
  >   1. Apr 15 N555DC KASE→KFLL (leg 1 of trip 20260415-ie8a)
  >   2. Apr 15 N555DC KFLL→TNCM (leg 2 of trip 20260415-ie8a)
  >   3. Apr 16 N555DC TNCM→KASE (return)
  >
  > This will also remove the associated trip sheet and checklist.
  > Proceed?"

  Wait for the user to confirm before running the delete commands.
  If the user says anything other than a clear yes ("sure", "go
  ahead", "delete them"), treat it as confirmation. But silence,
  ambiguity, or "let me think" means **do not proceed**.

## Display hints

When presenting Disco data back to the user as a table, use the column
sets below. These are the **preferred** columns for each entity type.
Omit any column that has no data for any row in the result set (e.g.,
if no flight has a callsign, drop the Call column entirely).

If the JSON response includes a `_display` metadata block, use that as
an override — it may specify a different column set, sort order, or
grouping for the specific response. The `_display` key is a hint, not
payload, and is always safe to ignore if you don't understand it.

### Flights

The primary table. This is what the user sees for `disco flights`.

| Column | JSON field | Format | Notes |
|--------|-----------|--------|-------|
| Ref | `flightId` | first 8 chars | Short reference |
| Span | derived | `{departure}→{destination}` | Human-readable leg |
| ETD | `departureTime` | `MMM DD HH:MMZ` | Departure airport local time |
| ETA | `arrivalTime` | `MMM DD HH:MMZ` | Destination airport local time |
| Tail | `aircraftRegistration` | as-is | |
| Dep | `departure` | ICAO | |
| Dest | `destination` | ICAO | |
| Dist | `distance_nm` | `{n} nm` | Nautical miles |
| ETE | `tripTime` | `H:MM` | Convert from seconds |
| Fuel | `fuelRequired` | `{n} lbs` | |
| Call | `callsign` | as-is | Blank if none |
| Crew | `crew` | `PIC[/SIC]` names or count | |
| Pax | `passengers` | count | |
| TOW | `takeoffWeight` | `{n} lbs` | |
| Rel | `released` | `✓` / blank | |

Sort by `departureTime` ascending. Group by date if the result spans
multiple days.

### Aircraft

| Column | JSON field | Format |
|--------|-----------|--------|
| Tail | `registration` | as-is |
| Type | `model` | as-is |
| Profile | `cruiseProfile` | as-is |

### Crew

| Column | JSON field | Format |
|--------|-----------|--------|
| Name | `name` | as-is |
| Code | `code` | as-is |
| Email | `email` | as-is |
| Phone | `phone` | as-is |

### Passengers (roster)

| Column | JSON field | Format |
|--------|-----------|--------|
| Slug | `slug` | as-is (e.g., `tyson-weihs`) |
| Name | `first` + `last` | combined |
| Weight | `weight_lbs` | `{n} lbs` |
| DOB | `dob` | `YYYY-MM-DD` |
| Passport | `passport.number` | masked: first 3 + last 3 |
| Expiry | `passport.expiry` | `YYYY-MM-DD` |
| Intl Ready | derived | `✓` / `✗` from `disco passenger check --intl` |

### Trips

| Column | JSON field | Format |
|--------|-----------|--------|
| Trip ID | `trip_id` | as-is, `YYYYMMDD-XXXX` format (e.g., `20260415-ie8a`) |
| Date | `date` | `YYYY-MM-DD` |
| Route | derived | `{origin}→{destination}` or `{legs joined with →}` |
| Tail | `tail` | as-is |
| Type | `trip_type` | `domestic_private` / `charter_135` / `international` |
| Pax | `passengers` | count |
| Status | derived from `disco trip check` | `OK` / `WARN` / `FAIL` + counts |

### Trip check items

When presenting `disco trip check` results, use this format:

| Symbol | Meaning |
|--------|---------|
| `✓` | OK — this item is complete |
| `✗` | FAIL — this item blocks departure |
| `…` | PENDING — not yet completed, not yet blocking |
| `⚠` | WARN — completed with a caveat |

Show the summary line first (`Trip Check: OK|WARN|FAIL` with counts),
then each item as a single line with its symbol, label, and any detail.

### Weather

When presenting `disco weather brief` or `disco weather metar/taf`:

- **METAR:** show the raw METAR string. Don't decode it into prose
  unless the user asks. Pilots read raw METARs faster than decoded.
- **TAF:** show the raw TAF string, same reasoning.
- **Brief:** show METAR block, then TAF block, then forecast summary.
  Use a header line for each section.
- **Flight category:** if you derive VFR/MVFR/IFR/LIFR from the
  METAR, show it as a tag after the station identifier:
  `KDEN (VFR)` or `KDEN (IFR)`.

### Performance

When presenting `disco flight performance`:

| Column | JSON field | Format |
|--------|-----------|--------|
| Block Time | `tripTime` | `H:MM` |
| Distance | `distance_nm` | `{n} nm` |
| Fuel Required | `fuelRequired` | `{n} lbs` |
| Fuel Remaining | `fuelRemaining` | `{n} lbs` |
| Reserves | `reserves` | `{n} lbs` or `{n} min` |
| TOW | `takeoffWeight` | `{n} lbs` |
| Landing Weight | `landingWeight` | `{n} lbs` |

Flag any reserve warnings from Dispatch explicitly. If `fuelRemaining`
is below minimums or Dispatch returned a warning, surface it in bold
or with a `⚠` prefix.

### General formatting rules

1. **Right-align numeric columns** (Dist, ETE, Fuel, TOW, Weight, Pax).
2. **Left-align text columns** (Name, Slug, Tail, Call, Route).
3. **Use monospace or code blocks** for tables when possible.
4. **Omit empty columns** — don't show a column of blanks.
5. **Prefer compact tables over verbose prose** when the user asked for
   a list or summary. Save the prose for single-item detail views.
6. **Use the human label format** (`Mar 27 N78ZG KSGR→KFTW`) for
   confirmations and single-flight references, not opaque IDs.
7. **Timezone display:** ETD in departure-local, ETA in
   destination-local. Always include the timezone abbreviation.

## Links

- Install guide: https://staging.disco.postflight.co/install.md
- Marketing site: https://staging.disco.postflight.co
- Documentation: https://staging.disco.postflight.co/docs/
