Skip to main content
The CLI presentation layer wraps the same CoffeeOrderApp use cases behind an ergonomic command tree built with Effect’s Command and Flag modules. Every flag is statically typed; enum flags are validated at parse time and reject invalid input with a helpful message before any service code runs.

Running the CLI

Invoke the CLI through Bun from the repository root (or backend/):
bun run cli -- <command> [subcommand] [flags]
The double dash (--) separates Bun’s own flag parsing from the CLI’s arguments.
Run bun run cli -- --help or append --help to any subcommand to print usage information and the list of accepted flags.

Command tree

coffee
├── menu
│   └── list
├── order
│   ├── create
│   ├── get
│   ├── list
│   └── cancel
└── barista
    ├── start
    ├── ready
    └── pickup

Commands reference

coffee menu list

Show every item currently on the menu.
bun run cli -- menu list
Output — a JSON array of MenuItem objects:
[
  {
    "id": "espresso",
    "name": "Espresso",
    "kind": "espresso",
    "basePriceCents": 300,
    "availableMilks": ["none"],
    "availableTemperatures": ["hot"],
    "maxShots": 4
  },
  {
    "id": "latte",
    "name": "Latte",
    "kind": "espresso",
    "basePriceCents": 450,
    "availableMilks": ["whole", "oat", "almond", "none"],
    "availableTemperatures": ["hot", "iced", "extra-hot"],
    "maxShots": 4
  }
]

coffee order create

Place a new coffee order.
bun run cli -- order create \
  --customer-name "Alice" \
  --drink latte \
  --size large \
  --milk oat \
  --temperature hot \
  --shots 2
Flags
FlagAliasTypeRequiredDefaultDescription
--customer-name-cstringyesCustomer display name
--drinkenumyesDrink identifier (see below)
--sizeenumnomediumCup size (see below)
--milkenumnoMilk type (see below)
--temperatureenumnoServing temperature
--shotsintegernoNumber of espresso shots
--notesstringnoFree-text preparation notes
Valid enum values
FlagAccepted values
--drinkespresso, americano, latte, cappuccino, cold-brew, tea
--sizesmall, medium, large
--milkwhole, oat, almond, none
--temperaturehot, iced, extra-hot
Example output
{
  "id": "order-1",
  "customerName": "Alice",
  "drinkId": "latte",
  "drinkName": "Latte",
  "size": "large",
  "milk": "oat",
  "temperature": "hot",
  "shots": 2,
  "status": "pending",
  "priceCents": 660,
  "createdAt": "2026-04-10T09:00:00.000Z"
}

coffee order get

Fetch a single order by its ID.
bun run cli -- order get --order-id order-1
# Short form:
bun run cli -- order get -i order-1
Flags
FlagAliasTypeRequiredDescription
--order-id-istringyesOrder ID to fetch

coffee order list

List all orders. Pass --status to filter by lifecycle stage.
# All orders
bun run cli -- order list

# Only brewing orders
bun run cli -- order list --status brewing
Flags
FlagAliasTypeRequiredDescription
--statusenumnoFilter by order status (see below)
Valid values for --status pending, brewing, ready, picked-up, cancelled

coffee order cancel

Cancel a pending or brewing order.
bun run cli -- order cancel --order-id order-1
# Short form:
bun run cli -- order cancel -i order-1
Flags
FlagAliasTypeRequiredDescription
--order-id-istringyesOrder ID to cancel

coffee barista start

Move an order from pending into brewing.
bun run cli -- barista start --order-id order-1
# Short form:
bun run cli -- barista start -i order-1
Flags
FlagAliasTypeRequiredDescription
--order-id-istringyesOrder ID to start brewing

coffee barista ready

Mark a brewing order as ready for pickup.
bun run cli -- barista ready --order-id order-1
# Short form:
bun run cli -- barista ready -i order-1
Flags
FlagAliasTypeRequiredDescription
--order-id-istringyesOrder ID to mark as ready

coffee barista pickup

Record that a ready order has been picked up by the customer, transitioning it to picked-up.
bun run cli -- barista pickup --order-id order-1
# Short form:
bun run cli -- barista pickup -i order-1
Flags
FlagAliasTypeRequiredDescription
--order-id-istringyesOrder ID to mark as picked up

Example terminal session

The session below walks through the full happy path for a single order.
# 1. Browse the menu
bun run cli -- menu list

# 2. Place an order
bun run cli -- order create -c "Bob" --drink cappuccino --size small

# 3. Check its status
bun run cli -- order get -i order-1

# 4. Barista picks it up and starts brewing
bun run cli -- barista start -i order-1

# 5. Barista finishes and marks it ready
bun run cli -- barista ready -i order-1

# 6. Customer picks up the drink
bun run cli -- barista pickup -i order-1

# 7. Confirm the final state
bun run cli -- order get -i order-1
{
  "id": "order-1",
  "customerName": "Bob",
  "drinkId": "cappuccino",
  "drinkName": "Cappuccino",
  "size": "small",
  "milk": "whole",
  "temperature": "hot",
  "shots": 1,
  "status": "picked-up",
  "priceCents": 425,
  "createdAt": "2026-04-10T09:00:00.000Z"
}

Order status lifecycle

Valid transitions enforced by the domain layer:
pending ──► brewing ──► ready ──► picked-up
   │            │
   └────────────┴──► cancelled
Attempting an invalid transition (e.g., cancelling a picked-up order) causes the command to exit with an error message from InvalidOrderStatusTransitionError.

Build docs developers (and LLMs) love