cd /news/developer-tools/show-hn-open-source-origami-cli · home › topics › developer-tools › article
[ARTICLE · art-139782] src=github.com ↗ pub= topic=developer-tools verified=true sentiment=↑ positive

Show HN: Open-Source Origami CLI

BrainGrid released the Origami CLI, an open-source command-line tool that exposes all 120 v3 operations of the Origami API as commands, generated from Origami's published OpenAPI spec so the catalog stays current via `pnpm sync:v3`. The CLI validates enum values and required fields before sending requests, supports `--dry-run` to preview launch blockers, and reuses an `Idempotency-Key` across automatic retries to prevent duplicate campaign launches or list enrollments. It requires Node.js 18+ and installs via `npm install -g @braingrid/origami-cli`, with JSON, table, and CSV output modes for scripting.

read9 min views1 publishedSep 25, 2026
Show HN: Open-Source Origami CLI
Image: Michielbdejong (auto-discovered)

Every v3 operation is a command: campaigns, people, templates, leads, jobs, account.

Generated from Origami's published OpenAPI spec, so it covers the whole API and stays current.

Install · Quickstart · Commands · Origami docs · Contributing

<sub>Built by the team behind BrainGrid, Plansmith and Radial.</sub>

  • The whole API. All 120 v3 operations are commands, built fromOrigami's OpenAPI spec . When Origami ships a change,pnpm sync:v3 regenerates 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-run shows the exact blockers a real launch would hit.
  • Safe to retry. Every POST carries anIdempotency-Key that 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.--all follows 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.
npm install -g @braingrid/origami-cli     # puts `origami` on your PATH
npx @braingrid/origami-cli --help         # or run it without installing

Requires Node.js 18+. From source: pnpm install && pnpm build && npm link.

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>

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) scope

Inspect or rotate:

origami auth status                   # resolved profile (key masked) + plan
origami auth logout                   # forget the active profile's key

The key can also come from the environment (handy for CI):

export ORIGAMI_API_KEY=og_live_…
origami account

Origami is agentic: you send a brief, an agent researches it in the background and builds a table, then you read the rows.

origami run "Find 20 fintech CEOs in NYC" --model max

origami agents ask <agentId> "Only Series A and later, please"

origami tables rows <tableId>
origami tables rows <tableId> -o csv --out leads.csv     # export to a file

origami tables upsert <tableId> --match domain \
  --row '{"domain":"acme.com"}' --row '{"domain":"globex.com"}'
origami enrichments get <enrichmentRunId> --wait          # poll until settled

origami 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.

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), orcsv
--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.

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>
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.

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]

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).

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>

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

origami jobs list --status running
origami jobs wait <jobId>
origami jobs input <jobId> --answers "Only Series A and later"

origami account senders list --channel linkedin
origami account rate-limits
origami account exclusion-lists people add --email someone@example.com

How flags map to the API:

  • Path parameters are positional arguments; query parameters and top-level body fields are --kebab-case flags.origami <command> --help lists them with the spec's descriptions and ends with the HTTP call and its docs page.
  • Booleans take --flag or--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; --all followsnext_cursor to 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 copy
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:  / 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]
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)

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 events
origami config path
origami config show                                     # secrets redacted
origami config profiles
origami config use <profile>
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.json

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.

Code Meaning
0 success
1 API or runtime error
2 usage / configuration error (bad flag, missing key)
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
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 spec

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.

<sub>BrainGrid: the app builder that plans before it builds · Plansmith: the planning agent for the business side of software · Radial: the issue tracker for coding agents</sub>

MIT. origami-cli is an independent project and is not affiliated with or endorsed by Origami. "Origami" is a trademark of its owner.

── more in #developer-tools 4 stories · sorted by recency
── more on @braingrid 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-open-source-…] indexed:0 read:9min 2026-09-25 · —