Install
npm install -g @openwop/cli
openwop --version
One-off, no install (handy in CI or a scratch shell):
npx -y @openwop/cli@latest --help
Requires Node 22+ to install (the one-line installer ensures it; the package's engines floor is ≥ 20). Channel adapters for Discord and WhatsApp are optional peer dependencies — install them only if you use those channels.
Point it at a host
The CLI reads OPENWOP_BASE_URL (or --base-url) and OPENWOP_API_KEY (or --api-key). Discovery needs no credential, so against the reference deployment these work straight away:
export OPENWOP_BASE_URL=https://app.openwop.dev/api
openwop capabilities # read /.well-known/openwop
openwop doctor # connectivity + advertised-capability check
Protocol calls — creating a run, listing runs — need an API key; without one the host answers 401. To get a key for the reference deployment, sign in at app.openwop.dev, open Access → API keys, and create a key with the CLI — act as me preset. It covers the protocol surface and workspace commands such as openwop agents list and openwop workflows register. Run workflows is for scripts that only start and read runs: the host answers 403 when such a key reaches a workspace command. Read only cannot start a run. The key is shown once, with the two lines the CLI reads:
export OPENWOP_BASE_URL=https://app.openwop.dev/api
export OPENWOP_API_KEY=owk_…
The key is read from --api-key, then OPENWOP_API_KEY, then openwop config set host.apiKey. The CLI sends it in the Authorization header. A key acts as the account that created it, expires after 90 days by default, and can be revoked on the same screen.
From CLI 1.4.0 you can skip copying a key. openwop login shows a short code; type it on the same Access → API keys page under "Sign in the OpenWOP CLI" and approve it. The host issues the CLI a 30-day key, saved to your config and listed in the app as CLI: <label>; openwop logout revokes it. Approve a code only if you just ran openwop login yourself.
export OPENWOP_BASE_URL=https://app.openwop.dev/api
openwop login
A new account starts with no workflows, so register one before you create a run:
cat > hello.json <<'JSON'
{"workflowId":"walk-hello","name":"Walk hello","nodes":[{"nodeId":"done","typeId":"core.noop","config":{}}],"edges":[]}
JSON
openwop workflows register hello.json
openwop runs create walk-hello --wait
To run against a host of your own instead, the quickstart starts one locally with a development key, and the install page covers a full deployment.
openwop onboard saves your host URL and stores your own model-provider key (BYOK) on the host. It does not sign you in or issue an OpenWOP API key.
The in-app command reference — with one-click copyable snippets, rendered against whatever host you're pointed at — lives at app.openwop.dev/cli.
How it behaves — the contract
Three properties hold for every command, so the CLI is safe to script against a shared host:
- Capability-honest, fail closed. A command drives a surface only when the host advertises it. When the host doesn't, the command fails closed with a legible message and a non-zero exit — never a stack trace, never a fabricated success.
- The host is the authority. Policy, RBAC, toggle/variant resolution, consent, approvals, and goal/proposal completion are all decided host-side. The CLI renders the host's decision; it never computes or asserts one locally.
- Secrets are refs, never values. BYOK keys, OAuth client secrets, SAML certs, and SCIM tokens stay host-side. The CLI handles refs and status only, and runs every response through a redactor before output — nothing secret is printed, logged, or written to local config.
Meaningful exit codes make commands scriptable: 0 ok, 3 escalated / pending, 1 failed (with per-group nuances documented in --help).
Command groups
Point at a host and run openwop --help for the live list. The groups cluster by area:
| Area | Groups |
|---|---|
| Setup & health | onboard · doctor · capabilities · config |
| Run lifecycle | runs · chat · interrupts · workflows · catalog · media |
| Agents & orchestration | agents · roster · workforces (fleet) · a2a |
| Governance & safety | approvals · governance (policy) · consent · toggles |
| Identity & access | users · profiles · auth (sso) |
| Extensibility & connections | packs · mcp · connections (conn) · providers · byok |
| Memory & workspace | memory · workspace · prompts |
| Automation & messaging | cron · webhooks · triggers · messaging · relay · notifications |
| Observability | analytics (usage) |
Agent-platform capabilities
Three higher-level capabilities for driving an agent platform — each capability-gated, so the group activates only when the host advertises it.
Reviewable learning — proposals
An agent's learned change is stored as an inert proposal. It does nothing until a human reviews it and applies it through the host's activation gate (which may route through an approval). The CLI renders the host's verdict and never activates locally.
openwop proposals list --state pending
openwop proposals revise prop_123 --artifact-json '{"systemPrompt":"…"}'
openwop proposals apply prop_123 # host materializes + routes through its activation mode
Standing goals — goals
A durable objective the host pursues across runs until a judge verdicts it satisfied or a bound stops it. Completion is the judge's verdict — there is no satisfy verb, and the CLI never declares victory from the client. A bounds-less goal is refused when the host requires bounds, so unattended continuation always terminates.
openwop goals create --objective "Keep the triage backlog under 20" \
--judge verifier --continuation schedule --max-iterations 50
openwop goals pause goal_123
Portability — export / import
Move reusable estate — agents, packs, schedules, rosters, templates — between hosts as a refs-only bundle. Secrets never travel as values; the bundle reports secretsToRebind references you bind at the destination. Always dry-run first; apply is idempotent and re-owns every entity to you.
openwop export --kinds agent --kinds schedule --out estate.json
openwop import estate.json --dry-run # preview creates/updates/skips/conflicts (no writes)
openwop import estate.json # apply
Trigger bridge — triggers
Bind an external webhook / email / form source to a workflow, then let a verified inbound event start a run with the payload as ctx.triggerData. The host verifies the source, drops duplicates, and tracks each binding's state (active, paused, failed, dead-lettered). The CLI registers the subscription and shows that state.
A webhook binding secret is returned once at creation; the CLI prints the fingerprint and never persists the value.
openwop triggers register --source webhook --workflow wf_intake --dedup --verification required
openwop triggers list --state active
openwop triggers get tgsub_123 # exit code reflects state: 0 active · 3 paused · 1 failed
Durable A2A tasks — a2a
When a host advertises a2a.durableTasks, every backing run carries a persisted A2ATaskState (taskId === runId) that survives caller disconnect, host restart, and HITL pauses. status shows what the host advertises; task reads one durable task's live state. The record is content-free — no run inputs, outputs, artifacts, or credentials — and the CLI renders the host's projection rather than deriving a state locally.
openwop a2a status
openwop a2a task <taskId> # exit: 0 completed · 3 in-progress/needs-input · 1 failed
Channel relay (optional)
The messaging and relay commands are a non-normative host extension: the CLI can run a local adapter that bridges a chat channel (Signal, iMessage, WhatsApp, Discord) into a workflow or agent on the host. The CLI pairs with the host over an authenticated session via a short code; channel-side auth lives only in the local adapter process and never reaches the host as a primary credential.
Source
@openwop/cli is on npm; source, docs, and the issue tracker are at github.com/openwop/openwop-cli. The CLI evolves additively within the current major.