Skip to content
Docs
Download Markdown
In this article

Use the Humanbased CLI

Inspect the supported command inventory and work with an organization-approved build.

Download Markdown

The hb command is a terminal client for CampaignA developer's data-production project and its settings API operations and delivered-record reads. humanbased is an alternate executable name. The repository's current package identifies itself as 0.1.0-next.3; that source version is not evidence of a publicly downloadable release. Ask your organizationThe Developer-side unit that holds Campaigns, data access, and funds's administrator or Humanbased support for an approved executable and the environment it supports.

If your organization has authorized a checkout of the Humanbased monorepo, developers can build that checkout with Node.js 20 or newer and the repository's pnpm workspace:

pnpm install --frozen-lockfile
pnpm --filter @humanbased/cli build
node packages/cli/dist/hb.js --version

Run those commands from the repository root. For the examples below, replace hb with node packages/cli/dist/hb.js when using the source build. A source build is a developer route, not a public package installation.

Discover this build before using it

hb --version
hb --help --json
hb config profiles set production --environment production --api-url https://api.humanbased.ai
hb config profiles use production
hb config profiles list --json

The JSON help inventory and profile commands make no network request. The profile records an API origin, not a credential; the CLI has no default destination. For staging, create a separate profile with --environment staging --api-url https://api.staging.humanbased.ai. Check the current profile before each environment change.

Use hb auth login for the supported browser sign-in flow, or provide an authorized organization key through HB_API_KEY as described below. Then run:

hb auth status
hb auth whoami --json
hb capabilities --json

Check the selected environment, API origin, organization, and granted capabilities. A key supplied through HB_API_KEY takes precedence over a saved session. The CLI refuses a missing or mismatched destination rather than guessing one.

Choose a credential

A person can use hb auth login on a supported build to approve a sign-in in the browser. The resulting CLI session has narrower authority than a full portal session. For unattended automation, supply an organization API Key through the runtime's secret mechanism as HB_API_KEY or --token-stdin. Do not place the Key in a command line, repository, profile, or agent prompt. Keys and browser sessions are different credentials with different permissions.

The server still decides whether the selected credential can read or change a particular Campaign. A capability in a local help listing is not proof of a grant. A 403 calls for hb auth whoami --json, a check of the active organization, and review of that Campaign's permissions—not a broader retry with another person's credential.

Read first and check the result

For a read-only starting point, list the Campaigns visible to the selected identity:

hb campaign list --limit 5 --json

The machine response is one JSON envelope on standard output. Check its error.code and the process exit code; progress goes to standard error. An empty data.items means no Campaign was visible in that scope. If data.has_more is true, pass the returned data.next_cursor as --cursor for the next page. --all deliberately walks multiple pages, so use it only when that larger read is intended.

Exit codeMeaning
0The command met its completion rule; a receipt read can still report a failed write.
1The request completed, but the command's completion rule did not hold: a document that fails validation, a plan that cannot be applied, or a campaign records pull --all export that stopped early.
2Invalid command arguments or a malformed request.
3 or 4Missing credential or insufficient permission.
5Conflict or outcome requiring a person's decision.
6Transient failure, or output that could not be delivered; follow the command's retry guidance.
7–10Backend failure, spend limit, wait timeout, or contract mismatch; inspect error.code.
130Interrupted.

When you finish with a browser session, use hb auth logout. hb auth sessions list and hb auth sessions revoke let you inspect and revoke saved sessions; an API Key is managed separately by its organization.

Commands for Campaign writes and launch

Every Campaign write follows the same order: write a candidate file, validate it, plan it, then apply it under a request key you choose. Each command below wraps the Campaign API operation for that step; that page carries the request, receipt, and error contract.

StepCommandGrant
Start a candidate around a templatehb campaign init --template <template-id> --out campaign.jsoncampaign:read
Start from an existing versionhb campaign init --from-version <campaign-id> --out campaign.jsoncampaign:read
Validate the candidatehb campaign validate --file campaign.jsoncampaign:author
Plan a new Campaignhb campaign plan --create --file campaign.json --out plan.jsoncampaign:author
Plan a change to a Campaignhb campaign plan <campaign-id> --file campaign.json --out plan.jsoncampaign:author and campaign:read
Create the Campaignhb campaign create --file campaign.json --plan plan.json --idempotency-key <your-key>campaign:author
Apply the changehb campaign apply <campaign-id> --file campaign.json --plan plan.json --idempotency-key <your-key>campaign:author
Propose a launchhb campaign launch propose <campaign-id>campaign:launch
Run a confirmed launchhb campaign launch execute --proposal <proposal-id> --idempotency-key <your-key>campaign:launch

A starter written by init --template leaves every value you must decide, such as the budget, the reward, and the caps, as a <DECIDE: …> placeholder. Replace each one before you validate. The CLI refuses to send a file that still contains a placeholder and exits 1 with PLACEHOLDERS_UNANSWERED.

validate and plan change nothing. Both exit 1 when the candidate is invalid or cannot be applied, so a script can stop there. plan --out saves the reviewed change set; create --plan and apply --plan re-plan before writing and refuse with PLAN_DRIFTED when the file or the base has changed since the review.

--idempotency-key names one write. Re-sending the same key with the same request never writes twice: the server answers with the first attempt's outcome. Choose a new key for a different change.

For an apply whose response was lost, inspect the original request key:

# Campaign-file apply (the default action)
hb campaign actions inspect --request-key <your-key> --json

# Template apply
hb campaign actions inspect --request-key <your-key> --action template.apply --json

The lookup searches one action at a time. Without --action it looks for campaignfile.apply, so a template apply needs --action template.apply; otherwise it reports no receipt, or the result of a different write that used the same request key. This lookup covers Campaign-file and template applies. It does not cover launch; for a lost launch response, resend the identical launch intent under the same idempotency key so the server can replay its first result. uncertain is an unresolved outcome requiring human review of the receipt steps and Campaign state, not a reason to try a new key.

Launching commits the Campaign's budget, so it takes three steps and two actors. hb campaign launch propose records a proposal and prints the address of the Developer portal's confirmation page; with --json the address is in data.confirmation_url. A person who can edit that Campaign signs in to the portal, reads the proposal, and selects Confirm this launch. Then hb campaign launch execute runs the confirmed proposal once. The CLI has no command that confirms, and a session from hb auth login can neither propose nor execute a launch: both commands need an organization API Key.

Confirm which environment you are pointed at

Confirm it before every write.

hb config profiles show --json

The environment and api_url in the output are what this profile says. The destination of the next command resolves field by field, each taking the first of these that has a value:

This valueFirst of these with a value
Which profile--profile → HB_PROFILE → the saved default profile
api_url--api-url → HB_API_URL → the profile selected above
environment--environment → HB_ENVIRONMENT → the profile selected above

--profile only decides which profile supplies the fallback; it ranks below HB_API_URL and HB_ENVIRONMENT. So --profile staging together with an HB_API_URL pointing at production follows the variable.

environment and api_url also have to agree: each environment admits only its own origins, and a mismatch refuses the command with ORIGIN_MISMATCH rather than printing a warning. An HB_API_URL left alone in the shell is therefore refused on the spot. The case that runs silently against the wrong environment is the other one: HB_API_URL and HB_ENVIRONMENT pointing as a pair at the same other environment — the two values agree, the profile takes no part, and hb config profiles show still reads staging.

The credential is a separate line. hb auth status reports which credential the next command would actually use, and says so when HB_API_KEY is shadowing a saved session.

What it doesCommandGrant
Every profile, with the current default markedhb config profiles list—
One profile; the current default when the name is omittedhb config profiles show <name>—
Create or replace a profilehb config profiles set <name> --environment <production, staging or local> --api-url <origin> --org <organization id>—
Make a profile the defaulthb config profiles use <name>—
Forget a profilehb config profiles remove <name>—

None of the five makes a network request, and none of them touches a credential. A profile records where to go and which organization to expect; the credential arrives per run from the environment or standard input. So changing environment means changing both the profile and the credential.

Sign in and sessions

None of these names a Campaign, so none of them takes a campaign:* grant; what the credential may actually do is still the server's decision.

StepCommandGrant
Sign in through the browserhb auth login—
See which credential the next command will usehb auth status—
Confirm the caller the server verifiedhb auth whoami—
What this release supports and what this credential may dohb capabilities—
List the terminals signed in as youhb auth sessions list—
Revoke one of those sessionshb auth sessions revoke <session-id>—
End this machine's sessionhb auth logout—

hb auth status makes no network request; it reads the session saved on this machine. The rest do.

Read commands

Before a write and after a launch, these confirm what the server actually recorded. None of them writes.

QuestionCommandCapability
What state is this Campaign in, and what can this credential do to ithb campaign get <campaign-id>campaign:read
Which stored versions does it havehb campaign versions list <campaign-id>campaign:read
The document of one versionhb campaign versions inspect <campaign-id> --version <number> --out version.jsoncampaign:read
What changed between two versionshb campaign versions diff <campaign-id> --from <number> --to <number>campaign:read
Counts for one event-time window, with their denominatorshb campaign observation <campaign-id> --from <ISO timestamp> --to <ISO timestamp>campaign:read
What a candidate file would quote as rewardhb campaign feasibility --file campaign.jsoncampaign:author
Which Campaigns this credential can readhb campaign list --limit 5campaign:read
The receipt for one writehb campaign actions inspect --request-key <your-key>campaign:author
Records one Campaign delivered into one subscriptionhb campaign records pull <campaign-id> --subscription <subscription-id>—

records pull carries no campaign:* grant, but it does need an organization API Key with data access; a browser session is refused. The walk-through is under “Export every delivered record” on this page.

versions list returns newest first; page with --limit and --cursor, or walk every page with --all.

versions inspect takes the newest version when --version is omitted. --raw adds the server's own fields and suits diagnosis; write the copy you mean to edit and send back with --out.

observation measures by event time: --from is inclusive, --to exclusive. Every count carries its denominator, and a numerator alone is not a rate.

feasibility quotes and creates nothing, and it names what it cannot answer.

Template commands

A template decides which fields a candidate file has. hb campaign init --template <template-id> references a template from here.

StepCommandCapability
Templates this organization may referencehb template listcampaign:read
One template's field contracthb template get <template-id>campaign:read
Write a starting template documenthb template init --kind <kind> --name <name> --out template.json—
Validate a template documenthb template validate --file template.jsoncampaign:author
Create or update a templatehb template apply --file template.json --idempotency-key <your-key>campaign:author

template init writes a file on this machine. It makes no request and needs no grant.

Updating an existing template takes both --template-id and --base-hash, the second from hb template get; --template-id alone is refused. Without it, when two people edit the same template in turn, the later write replaces the earlier one and neither of them can see that it happened.

A template apply has a receipt too, but the lookup needs --action template.apply; without it you get another write's result, or nothing at all.

This page does not cover the eight hb dsa … commands, which consult the Campaign design assistant, or hb agent runs. No page documents them yet.

Export every delivered record

hb campaign records pull reads the records one Campaign has delivered into one subscription. It always replays from the first record, so it never moves the subscription's incremental reading position. The Campaign filter can only narrow what the subscription already authorizes: for a priced subscription that is the range already acquired, and in every case it is delivered records, not all of the Campaign's submissionsThe record created when work is submitted. Confirm that hb --help --json lists the command in your build; with a build that lacks it, page through the HTTP data API.

Credential and a first page

The command needs a full organization API Key with data access to the subscription. A session from hb auth login is refused. A Key with only the Data grant can still run hb capabilities; it reports the Campaign API catalog as unavailable, which has no effect on this command. Set HB_API_KEY and HB_SUBSCRIPTION_ID as in Get your first authorized data, then pass the Key to this one command:

printf 'Campaign ID: '
read -r HB_CAMPAIGN_ID
HB_API_KEY="$HB_API_KEY" hb campaign records pull "$HB_CAMPAIGN_ID" \
  --subscription "$HB_SUBSCRIPTION_ID" \
  --limit 5 --json

Without --all, the command reads one page and returns data.next_cursor. --limit sets the page size: 50 by default, 200 at most. The command takes exactly one Campaign ID.

Export all pages

--all follows the cursor until the server reports no more records. Send the result to a private directory:

HB_EXPORT_DIR="$(mktemp -d)"
printf 'Export directory: %s\n' "$HB_EXPORT_DIR"
HB_API_KEY="$HB_API_KEY" hb campaign records pull "$HB_CAMPAIGN_ID" \
  --subscription "$HB_SUBSCRIPTION_ID" \
  --limit 200 --all --json > "$HB_EXPORT_DIR/campaign-records.json"
printf 'Exit code: %s\n' "$?"

The records are in data.items. Treat the file as a complete export only when both checks pass: the exit code is 0, and data.complete is true.

data fieldMeaning
itemsThe records this command read, in the order the server returned them.
countThe number of records in items.
pages_readThe number of pages this command requested.
has_moreWhether the server still reported more records when the command stopped.
next_cursorWhere a later command can continue, or null.
completetrue only when the command started at the first record, without --cursor, and reached the last page.
pagination_stop_reasonnull, or the reason an --all read stopped early.

Complete and partial results

A complete export looks like this. Both examples omit data.items and the envelope's requestId, context, and notices; the identifiers are illustrations.

{
  "apiVersion": "humanbased.cli/v1",
  "command": "campaign.records.pull",
  "requestId": "e9dc2862-d165-44ce-b54a-42111284bd40",
  "context": {
    "profile": null,
    "apiOrigin": "https://api.humanbased.ai",
    "organizationId": "10571000020000000001"
  },
  "data": {
    "subscription_id": "784210003001",
    "campaign_id": "784210001001",
    "count": 1342,
    "pages_read": 7,
    "has_more": false,
    "next_cursor": null,
    "complete": true,
    "pagination_stop_reason": null
  },
  "notices": [],
  "error": null
}

A partial export exits 1. It still carries the records read so far, and it names why it stopped:

{
  "apiVersion": "humanbased.cli/v1",
  "command": "campaign.records.pull",
  "requestId": "e9dc2862-d165-44ce-b54a-42111284bd40",
  "context": {
    "profile": null,
    "apiOrigin": "https://api.humanbased.ai",
    "organizationId": "10571000020000000001"
  },
  "data": {
    "subscription_id": "784210003001",
    "campaign_id": "784210001001",
    "count": 100000,
    "pages_read": 500,
    "has_more": true,
    "next_cursor": "example-opaque-cursor",
    "complete": false,
    "pagination_stop_reason": "item_limit"
  },
  "notices": [],
  "error": {
    "code": "PAGINATION_INCOMPLETE",
    "httpStatus": null,
    "message": "The --all walk stopped while the server still reported more pages. The partial data and a continuation cursor, when available, are included.",
    "retryable": false,
    "nextAction": null,
    "details": null
  }
}
pagination_stop_reasonWhat happenedWhat to do now
page_limitThe command read 1,000 pages. At the default page size of 50, that is 50,000 records.Continue from next_cursor. Pass --limit 200 to read more records per run.
item_limitThe command read 100,000 records.Continue from next_cursor.
missing_cursorThe server reported more records and returned no cursor.next_cursor is null, so this file has no safe place to continue from. Keep it for diagnosis and run the export again from the first record.
repeated_cursorThe server returned a cursor this command had already used.next_cursor is null. Never resubmit the repeated cursor. Run the export again from the first record or from an earlier cursor you saved, and contact hello@humanbased.ai if it repeats.

Continue a partial export

Continue only when data.next_cursor is a string. Copy its value without the JSON quotes:

printf 'Part number, 2 for the first continuation: '
read -r HB_PART
printf 'Next cursor: '
read -r HB_CURSOR
HB_API_KEY="$HB_API_KEY" hb campaign records pull "$HB_CAMPAIGN_ID" \
  --subscription "$HB_SUBSCRIPTION_ID" \
  --cursor "$HB_CURSOR" \
  --limit 200 --all --json > "$HB_EXPORT_DIR/campaign-records-$HB_PART.json"
printf 'Exit code: %s\n' "$?"

One run reads at most 100,000 records, so a large export needs several continuations. Save each one to its own file: part 2, then part 3, and so on. A continuation saved over an earlier file loses that file's records.

A continuation holds only the records after the cursor. Its data.complete stays false even when it reaches the last page and exits 0. The whole export is the first file's data.items followed by the data.items of each continuation, with the same Campaign and subscription in every command.

Protect the output

Part of the exportWhat it means for you
Record contentdata.items[].data is written exactly as delivered, including any value that happens to look like a credential. Store the file under the same rules as the source data.
NumbersNumbers inside record content keep their original digits, including integers beyond JavaScript's safe range and long decimals. Use a parser that preserves them when your values need that precision.
Temporary fileWhile it reads, the CLI stages the records in a file in the system temporary directory that only the current user can read, and deletes it when the command ends. Leave enough free space there for the whole export.
Interrupted outputWhen the pipe closes or the destination fills up, the command exits with a non-zero code and reports the failure on standard error. A JSON file that was already partly written is incomplete: discard it and run the export again.

Errors

Exit code and error.codeCauseWhat to do now
1, PAGINATION_INCOMPLETEAn --all read stopped while more records remained.Read data.pagination_stop_reason and continue as described above.
2, INVALID_ARGUMENTThe Campaign ID is blank or a comma-separated list, or an ID or cursor looks like a credential. Nothing was sent.Pass one Campaign ID and the real identifiers. Supply the Key only through HB_API_KEY or --token-stdin.
3No usable credential: the Key is missing, malformed, expired, or revoked, or a sign-in session was used.Supply a full organization API Key.
4The Key has no data access, or the subscription is outside its scope or organization.Check the Key's Data grant in Create and use an API Key.
6The service was unavailable, or the output could not be delivered.Run the same command again; a replay charges nothing and moves no position.

For API operations and grants, see Campaign API. To hand one bounded read to an agent, see Use an agent with Humanbased.