@braingrid/origami-cli
v0.2.0
Published
The command line for the Origami API: every v3 operation (send, leads, jobs, account) as a command, generated from the published spec.
Readme
Why origami-cli
- The whole API. All 120 v3 operations are commands, built from
Origami's OpenAPI spec. When Origami ships a
change,
pnpm sync:v3regenerates the catalog; nothing is hand-maintained. - Checks before it sends. Enum values and required fields are validated before any request
leaves your machine.
launch --dry-runshows the exact blockers a real launch would hit. - Safe to retry. Every POST carries an
Idempotency-Keythat is reused across automatic retries, so a flaky network never launches a campaign or enrolls a list twice. - Built for scripts. JSON when piped, tables in a terminal, CSV on request.
--allfollows cursors to the end, and data goes to stdout while progress goes to stderr. - Async done right. Anything that returns a Job takes
--wait, which polls on the Job's ownnext_poll_at.origami jobs wait <id>picks up any Job later.
Install
npm install -g @braingrid/origami-cli # puts `origami` on your PATH
npx @braingrid/origami-cli --help # or run it without installingRequires Node.js 18+. From source: pnpm install && pnpm build && npm link.
Quickstart
origami auth login # paste an og_live_… key
origami send campaigns list --status draft # what's waiting to go out
origami send campaigns examples list <campaignId> # the copy each person will get
origami send campaigns launch <campaignId> --dry-run # blockers + held-back counts
origami send campaigns launch <campaignId> # go
origami send campaigns stats <campaignId>Authenticate
Create an API key under Settings → Developers in the Origami app. Keys
look like og_live_… and are parent-wide (they can act on your org or any of its projects).
origami auth login # prompts for a key (hidden input), verifies it
origami auth login --key og_live_… # non-interactive
echo "$KEY" | origami auth login # from a pipe / secret manager
origami auth login --project <id> # store a default project (child org) scopeInspect or rotate:
origami auth status # resolved profile (key masked) + plan
origami auth logout # forget the active profile's keyThe key can also come from the environment (handy for CI):
export ORIGAMI_API_KEY=og_live_…
origami accountThe core loop
Origami is agentic: you send a brief, an agent researches it in the background and builds a table, then you read the rows.
# 1. Run a brief (creates an agent, polls to completion, prints the table)
origami run "Find 20 fintech CEOs in NYC" --model max
# 2. If the agent asks a question, answer it (same agent + conversation)
origami agents ask <agentId> "Only Series A and later, please"
# 3. Read the rows it built
origami tables rows <tableId>
origami tables rows <tableId> -o csv --out leads.csv # export to a file
# 4. Bring your own data — upsert + enrich
origami tables upsert <tableId> --match domain \
--row '{"domain":"acme.com"}' --row '{"domain":"globex.com"}'
origami enrichments get <enrichmentRunId> --wait # poll until settledorigami run and origami agents create are the same flow; run is the friendly shortcut. Add
--no-wait to return the running run id instead of polling, then poll later with
origami agents run-get <agentId> <runId> --wait.
Global options
Place these after the command (kubectl-style):
| Option | Description |
| --- | --- |
| --api-key <key> | API key (overrides profile/env) |
| --project <id> | scope the request to a project (child org) via x-origami-project |
| --profile <name> | configuration profile |
| --base-url <url> | override the API base URL |
| -o, --output <format> | table (default in a terminal), json (default when piped), or csv |
| --fields <list> | comma-separated columns to show (table/csv) |
| --no-color | disable colored output (also honors NO_COLOR) |
| --debug | log HTTP requests to stderr |
| --timeout <ms> | per-request timeout |
| --max-retries <n> / --no-retry | control automatic retries on 429/5xx |
Data goes to stdout; status, progress, and hints go to stderr — so | jq and -o csv
pipelines stay clean.
Commands
run / agents
origami run "<brief>" [--model lite|max] [--workspace <id>] [--table <id>]... [--rows] [--no-wait]
origami agents list [--search <text>] [--all]
origami agents get <agentId>
origami agents ask <agentId> "<follow-up>"
origami agents runs <agentId>
origami agents run-get <agentId> <runId> [--wait] [--include stats,transcript]
origami agents tables <agentId>
origami agents cancel <agentId>
origami agents archive <agentId>tables
origami tables list [--workspace <id>] [--all]
origami tables get <tableId> [--include stats]
origami tables columns <tableId>
origami tables rows <tableId> [--filter '<col> <op> [value]']... [--sort <col>:<asc|desc>] \
[--flat] [--no-defaults] [--limit <=200] [--all] [-o csv] [--out file.csv]
origami tables row <tableId> <rowId>
origami tables cell <tableId> <rowId> <columnId>
origami tables upsert <tableId> --match <slugs> (--row '<json>'... | --file rows.csv) \
[--no-enrich] [--reenrich-updated] [--batch-id <uuid>]Filter operators: contains, not_contains, equals, not_equals, is_empty, is_not_empty,
greater_than, greater_than_or_equal, less_than, less_than_or_equal.
enrichments, documents, workspaces
origami enrichments list [--table <id>] [--all]
origami enrichments get <runId> [--wait]
origami documents list <workspaceId>
origami documents upload <workspaceId> <file...> [--mode table|append|document] [--table <id>]
origami documents get <workspaceId> <documentId> [--out <file>]
origami documents rename <workspaceId> <documentId> <name>
origami documents delete <workspaceId> <documentId>
origami workspaces list
origami workspaces create --name <name>
origami workspaces get <workspaceId>
origami workspaces delete <workspaceId> [--confirm]v3: send, leads, jobs, account
Each operation id is the command path: send.campaigns.people.list is
origami send campaigns people list, fetch_more becomes fetch-more. A group whose only
operation is get collapses into the group (origami send campaigns stats <id>), and an
argument-free get is its group's default (origami account, origami account credits).
# The send recipe, in order
origami send campaigns create --name "Q4 delivery leaders" --channels linkedin
origami send campaigns people upsert <campaignId> --list-id <listId>
origami send campaigns templates put <campaignId> --data @template.json
origami send campaigns settings patch <campaignId> --no-auto-lead-refill-enabled --require-message-approval
origami send campaigns senders add <campaignId> --sender-id <senderId>
origami send campaigns examples list <campaignId> # read the rendered copy per person
origami send campaigns launch <campaignId> --dry-run # blockers + held-back counts
origami send campaigns launch <campaignId>
origami send campaigns stats <campaignId>
# Leads
origami leads lists list
origami leads lists rows list <listId> --all -o csv > rows.csv
origami leads lists rows upsert <listId> --rows @rows.json --match-columns email
origami leads searches create --brief "…" --count 25 --wait
# Jobs: every 202 returns one; --wait on the command, or poll later
origami jobs list --status running
origami jobs wait <jobId>
origami jobs input <jobId> --answers "Only Series A and later"
# Account
origami account senders list --channel linkedin
origami account rate-limits
origami account exclusion-lists people add --email [email protected]How flags map to the API:
- Path parameters are positional arguments; query parameters and top-level body fields are
--kebab-caseflags.origami <command> --helplists them with the spec's descriptions and ends with the HTTP call and its docs page. - Booleans take
--flagor--no-flag(sendsfalse). Lists take commas or repeats (--ids a,b --ids c). Object fields take JSON inline,@file.json, or-for stdin. --data <json|@file|->supplies the whole body; flags override its keys. A body field that would shadow a global option gets abody-prefix (--body-fields).- Enums and required fields are checked before any request is sent.
- Every POST carries an
Idempotency-Key(yours via--idempotency-key, else a UUID) that is reused across automatic retries, so a retried launch or enrollment never runs twice. - List commands print one page and hint the cursor;
--allfollowsnext_cursorto the end. - Operations that return a Job accept
--wait(polls on the Job'snext_poll_at, default ceiling 30 minutes,--wait-timeout <s>to change it).
Regenerate the command catalog when Origami ships spec changes:
pnpm sync:v3 # fetches https://docs.origami.chat/openapi-v3.yaml → src/v3/catalog.ts
pnpm sync:v3 ./spec.yaml # or from a local copycampaigns, sequences (v2)
origami campaigns list (--workspace <id> | --table <id>)
origami campaigns create <tableId> "<instructions>" # agentic — drafts sequences, doesn't send
origami campaigns edit <campaignId> "<change>" # agentic
origami campaigns people <campaignId> [--status <csv>] [--all]
origami campaigns stats <campaignId>
origami campaigns launch <campaignId> [--dry-run] # also: pause / resume
origami campaigns delete <campaignId> [--confirm]
origami sequences list (--workspace <id> | --table <id> | --column <id>) [--status <s>]
origami sequences get <sequenceId>
origami sequences stop <sequenceId> [--dry-run]
origami sequences delete <sequenceId> [--force]scheduled, projects (v2)
origami scheduled list [--workspace <id>] [--enabled true|false]
origami scheduled create --workspace <id> --name <n> --prompt "<brief>" --cron "0 9 * * 1"
origami scheduled enable|disable|trigger <id>
origami scheduled runs <id>
origami projects list # parent-org only
origami projects create <name> [--monthly-credits <n>]
origami projects update <id> [--name <n>] [--monthly-credits <n|null>]
origami projects delete <id> [--confirm]
origami credits # credit balance (v3 shortcut)webhooks (local dev tools)
Origami webhooks are configured in the dashboard; these are local helpers for building a receiver.
origami webhooks verify --secret whsec_… --id <id> --timestamp <ts> --signature <sig> --file body.json
origami webhooks listen --port 9333 --secret whsec_… # verify + pretty-print inbound eventsconfig
origami config path
origami config show # secrets redacted
origami config profiles
origami config use <profile>Scripting
origami tables rows <id> -o json | jq '.[].website'
origami agents list --all -o csv > agents.csv
origami run "Find 50 founders" --rows -o json > result.jsonReliability
The client automatically retries 408/429/500/502/503/504 and network errors with exponential
backoff (honoring Retry-After), and polls runs on the API's Retry-After cadence (15s). Rate
limits: 300 req/min per IP, 100 req/min per org; concurrent agent runs are plan-tunable.
Exit codes
| Code | Meaning |
| --- | --- |
| 0 | success |
| 1 | API or runtime error |
| 2 | usage / configuration error (bad flag, missing key) |
Environment variables
| Variable | Description |
| --- | --- |
| ORIGAMI_API_KEY | API key (overrides the stored profile key) |
| ORIGAMI_PROJECT | default project id (x-origami-project) |
| ORIGAMI_BASE_URL | API base URL |
| ORIGAMI_PROFILE | default profile name |
| ORIGAMI_CONFIG_DIR | directory for the config file (default ~/.config/origami) |
| NO_COLOR / FORCE_COLOR | disable / force colored output |
Development
pnpm dev -- <args> # run from source (tsx)
pnpm typecheck # tsc --noEmit
pnpm test # vitest
pnpm build # tsup → dist/index.js
pnpm sync:v3 # regenerate src/v3/catalog.ts from the published v3 specContributing
Issues and pull requests are welcome. CONTRIBUTING.md covers setup, the test suite, and how the v3 catalog is regenerated. Please report security issues privately as described in SECURITY.md.
Built by the team behind
License
MIT. origami-cli is an independent project and is not affiliated with or endorsed by Origami. "Origami" is a trademark of its owner.
