@rulebase/cli
v0.5.0
Published
CLI for a Rulebase workspace. Push, read, and reconcile work items with JSON in and JSON out, sign in, and check which region your credentials belong to.
Maintainers
Readme
rulebase
CLI for a Rulebase workspace. JSON in, JSON out — built to be driven by an agent or a CI job as much as by a person.
npx @rulebase/cli doctor # which region is my key from?
npx @rulebase/cli work-items apply --file work-items.json # push a batch, get per-item resultsEvery work-items command is non-interactive, reads JSON from a file or stdin, writes
exactly one JSON envelope to stdout, and exits with a code you can branch on. Full guide:
docs.rulebase.co/guides/cli.
Why doctor exists
Rulebase runs separate US and EU deployments with separate credential stores. A valid API key sent to the wrong region returns:
{ "error": "Unauthorized" }Which is byte-identical to what a revoked or mistyped key returns. Nothing in the response distinguishes them, so people spend hours debugging a credentials problem they do not have.
doctor does not trust the region you give it. It tries both and tells you which one
answers:
api key rk_live_…32 chars
region us (requested)
US api rejected · mcp reachable
EU api authenticated · mcp reachable
Your key belongs to EU.
You asked for US, which rejected it. That 401 is indistinguishable
from a bad key, so use --region eu (or RULEBASE_REGION=eu).Commands
rulebase doctor [--region us|eu] # which region your key belongs to, and what is reachable
rulebase login --region us|eu # sign in to MCP through your browser (OAuth)
rulebase login --auth api-key # configure a REST API key
rulebase logout [--region|--all] # remove stored credentials
rulebase whoami [--region us|eu] # which workspace your credentials belong to
rulebase skills [...] # where to get the CX ops skills
rulebase work-items ... # work-item CRUD and batch apply (see below)Add --json to any of them for machine-readable output. Prompts and progress go to
stderr, so rulebase login --json | jq works.
Work items
The agent-facing half of the CLI: create, read, update, soft-delete, and batch-apply work
items over REST, against the canonical /v1/work_items endpoints.
rulebase work-items create --file item.json # create-only; duplicate external_id is a conflict
rulebase work-items get <id> # or --external-id TASK-9182
rulebase work-items list --status completed,pending --all # cursor paginated; --all follows every page
rulebase work-items update <id> --file patch.json # merges custom_attributes, external_id is immutable
rulebase work-items delete <id> --yes # soft delete; idempotent
rulebase work-items apply --file work-items.json # create/update/restore by external_id
rulebase work-items schema # bundled JSON Schema for the inputs aboveInput is a JSON object for the CRUD commands, and the canonical batch envelope — or a bare
array, which is normalized to it — for apply:
cat > work-items.json <<'JSON'
{
"work_items": [
{ "external_id": "TASK-9182", "agent_email": "[email protected]", "type": "fraud_review" },
{ "external_id": "TASK-9183", "type": "kyc_verification", "custom_attributes": { "risk_score": 12 } }
]
}
JSON
rulebase work-items apply --file work-items.json --dry-run # plan only, writes nothing
rulebase work-items apply --file work-items.json
# stdin works everywhere a path does
jq -n '{external_id:"TASK-9182",type:"fraud_review"}' | rulebase work-items create --file -Apply is keyed on external_id, so re-running the same input is safe: unchanged items come
back as unchanged, and an external_id you previously deleted comes back as restored.
Items you leave out are never deleted. Inputs are capped at 25 MB, and anything over the
API's 100-item limit is split into chunks automatically — index in the output is always
the position in your input.
Output and exit codes
{
"ok": true,
"data": { "dry_run": false, "results": [ { "index": 0, "external_id": "TASK-9182", "status": "created", "data": {} } ],
"summary": { "total": 1, "created": 1, "updated": 0, "unchanged": 0, "restored": 0, "error": 0 } },
"meta": { "region": "us", "chunks": 1, "chunk_size": 100 }
}Failures use {"ok": false, "error": {"code", "message", "details"}}. Progress goes to
stderr and never contains a secret, so ... | jq is always safe.
| Exit | Meaning |
|---|---|
| 0 | Success |
| 1 | A batch apply finished with at least one failed item (error.code is partial_failure; data.results is still complete) |
| 2 | Usage, malformed JSON, or input that fails schema validation — caught before any request |
| 3 | Credentials: missing, ambiguous across regions, or rejected (401) |
| 4 | Network failure or an API error (not_found, conflict, unprocessable, rate_limited, api_error) |
429s and transient network errors are retried with backoff, honouring Retry-After;
when the CLI gives up, error.details.retry_after carries the seconds the API asked for.
Work-item commands authenticate with an API key, never OAuth — see below. A key from
the wrong region returns the same 401 as a revoked one, so if unauthorized looks
wrong, run rulebase doctor.
Two credentials, two jobs
| | API key | OAuth login |
|---|---|---|
| Authenticates as | the organization | you |
| Good for | pushing data in over REST | MCP tool calls |
| Names your workspace | yes | yes |
| Names the authenticated user | no | yes |
| Configure with | rulebase login --auth api-key | rulebase login --region us\|eu |
Keeping these straight is most of what the CLI is for. Neither one substitutes for the other, and a 401 does not tell you which one you were missing.
The API key
Configure it once and the CLI uses it automatically:
export RULEBASE_API_KEY=rk_live_...
npx @rulebase/cli login --auth api-key
unset RULEBASE_API_KEY
npx @rulebase/cli doctor # uses the stored keyWithout RULEBASE_API_KEY, login securely prompts for the key with input hidden. The
key is never accepted as a command-line value because argv appears in shell history,
ps output, and transcripts. The environment variable always overrides a stored key,
which is useful for CI and one-off commands.
The key is verified against both regions before it is saved, so --region is optional.
If supplied, a mismatch is rejected with the correct region instead of storing a key
under the wrong workspace.
You only need a key to push data in. Reading a workspace over MCP needs no key at all —
see rulebase-setup
for connecting Claude Code, Codex or Cursor.
Signing in
npx @rulebase/cli login --region usOpens your browser, catches the redirect on 127.0.0.1, and stores the token alongside
API keys in ~/.rulebase/credentials.json with mode 0600. It refreshes on its own.
Login is per region, because the auth servers are separate (auth.rulebase.co and
auth-eu.rulebase.co) and a token from one is rejected by the other. So there is no
ambient "logged in", only "logged in to EU".
The token's audience is that region's MCP resource, not the REST API — so it authorises tool calls, and pushing data in still wants an API key.
Under the hood this is authorization code + PKCE (S256), with the CLI registering its own public OAuth client on first use via RFC 7591 dynamic registration. There is no client secret, which is what makes this safe to ship in a public npm package. The client id is cached per issuer so repeat logins do not create new client records.
--device selects the device-code flow,
which is the right shape for a headless box. Discovery advertises the grant, but the
registration endpoint currently issues clients for authorization_code and
refresh_token only, so --device needs a client provisioned out of band:
RULEBASE_OAUTH_CLIENT_ID=... npx @rulebase/cli login --region us --deviceFor CI, skip the store entirely:
RULEBASE_TOKEN=... npx @rulebase/cli whoami --region us # never written to disklogout deletes both locally stored credential types for a region. It is not a
server-side revocation; use --all to remove the complete local credential file.
Local credential security
Credentials stay local in ~/.rulebase/credentials.json. The directory is created with
mode 0700 and the file is created and rewritten with mode 0600. API keys are only
sent to Rulebase REST endpoints as Bearer tokens; production Rulebase endpoints use
HTTPS. Neither API keys nor OAuth tokens are printed by the CLI.
Environment
| Variable | Purpose |
|---|---|
| RULEBASE_API_KEY | Override the stored REST credential; also supplies API-key login |
| RULEBASE_REGION | Default region. Blank counts as unset |
| RULEBASE_TOKEN | Use a token without storing one, for CI |
| RULEBASE_CREDENTIALS_PATH | Move the credential file |
| RULEBASE_OAUTH_CLIENT_ID | Use a specific OAuth client instead of self-registering |
| RULEBASE_NO_BROWSER | Print the URL, do not launch anything |
| BROWSER / RULEBASE_BROWSER | Command used to open the URL |
| RULEBASE_RETRY_BASE_MS | Backoff base for retried requests, in ms (default 500) |
Development
npm run lint # parse every shipped file and assert it survives npm pack
npm test # subprocess tests against a mock API
npm run schema:check # bundled work-item schemas vs the published OpenAPI
npm run check # all threelib/work-items/schemas.json is a copy of the public OpenAPI's work-item input schemas:
it is what work-items schema prints and what the CLI validates against before sending.
npm run schema:check fails if it has drifted; --write accepts the upstream shape.
Skills
Skills live in a separate package so the catalog stands on its own:
npx rulebase-skills list