A lightweight terminal UI for exploring and executing API requests from an OpenAPI spec. Built for developers who find Postman too heavy — milkman gives you the bits you actually use.
- Import any OpenAPI 3.x spec (YAML or JSON) and instantly browse all endpoints
- Arrow-key TUI — navigate endpoints, inspect parameters, and fire requests without leaving the terminal
- Example values pre-filled — request body and query params are populated from the spec's example values, so you can hit Enter and go
- Executes via
curl— see the exact curl command that ran, get formatted JSON output with status code and latency - Long response handling — responses over 100 lines are never dumped to the terminal; open them in a pager or your editor instead
- Per-project config — base URL, editor, and collection stored in
.milkman/alongside your project
- Bun v1.0+
curl(available on macOS/Linux by default)
git clone https://github.com/ajmccall/milkman.git
cd milkman
bun install
bun linkbun link registers the milkman command globally via ~/.bun/bin. Make sure ~/.bun/bin is in your PATH:
export PATH="$HOME/.bun/bin:$PATH"milkman import path/to/openapi.yamlParses the spec, writes the collection to .milkman/, and launches the TUI.
milkman config url https://api.example.comOr press c inside the TUI.
milkman config editor sublSupports any command that accepts a file path as its last argument — e.g. subl, code, vim, nano. Flags are supported too:
milkman config editor "code -n"milkman| Key | Action |
|---|---|
↑ / ↓ |
Navigate endpoint list |
↵ |
Select endpoint / confirm |
b / esc |
Go back |
i |
Import a new OpenAPI file |
c |
Change base URL |
q |
Quit |
| Key | Action |
|---|---|
o |
Open response in pager ($PAGER, defaults to less) |
e |
Open response in configured editor (writes to .milkman/last-response.json) |
Responses longer than 100 lines are not displayed inline — you'll see the line count and the options above instead.
milkman import spec.yaml
→ parses OpenAPI paths, methods, parameters, request bodies
→ resolves $ref pointers and allOf schemas
→ writes .milkman/collection.json and .milkman/config.json
TUI: select endpoint
→ shows method, path, summary, parameters and body fields
→ prompts for required inputs (pre-filled with spec examples)
→ builds and runs: curl -s -X POST "https://..." -d '{"key":"value"}'
→ displays formatted JSON response with status code and latency
→ long responses (100+ lines) open in pager or editor instead
src/
index.tsx # CLI entry point
types.ts # shared TypeScript types
lib/
parser.ts # OpenAPI → collection converter
storage.ts # .milkman/ read/write
executor.ts # curl command builder + runner
format.ts # JSON formatting and colour helpers
tui/
App.tsx # root ink component, view state machine
ListView.tsx # scrollable endpoint list
DetailView.tsx # endpoint detail (params, body schema)
ParamInputView.tsx # required param prompts before execution
ResponseView.tsx # response display
PromptView.tsx # generic text prompt (import / config)
.milkman/
config.json # base URL, editor command
collection.json # parsed endpoint collection
last-response.json # most recent response body (written when opening in editor)
- Bun — runtime and package manager
- ink — React for CLIs
- yaml — OpenAPI YAML parsing
- chalk — terminal colours
.milkman/ is intentionally per-project (not global), so each repo can have its own base URL and collection. Add it to your .gitignore if you don't want to commit it.