hb 是用于 Campaign API 和交付记录读取的命令行客户端,humanbased 是同一程序的另一个命令名。仓库中的当前包版本是 0.1.0-next.3,不能据此认定已有公开下载版。请向组织管理员或 Humanbased 支持取得获准的程序及适用环境。
如果组织允许你使用 Humanbased monorepo 的源码,可在仓库根目录用 Node.js 20 或更新版本和 pnpm 构建:
pnpm install --frozen-lockfile
pnpm --filter @humanbased/cli build
node packages/cli/dist/hb.js --version使用源码构建时,把下文命令中的 hb 换成 node packages/cli/dist/hb.js。这条路径面向已获仓库权限的开发者,不代表公开包已发布。
先查看当前版本
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 --jsonJSON 帮助和 Profile(目标环境配置)命令不发送网络请求。Profile 记录 API 地址,不保存凭证;CLI 没有默认地址。测试环境应单独设置 --environment staging --api-url https://api.staging.humanbased.ai,切换环境前先查看当前 Profile。
可用 hb auth login 在浏览器完成该版本支持的登录,也可按下文提供组织授权的 Key。认证后再检查:
hb auth status
hb auth whoami --json
hb capabilities --json核对环境、API 地址、组织和凭证能力。通过 HB_API_KEY 提供的 Key 优先于已保存的会话。未配置目标或地址与环境不符时,CLI 会拒绝请求。
选择凭证
人在终端使用受支持版本的 hb auth login 时,需要在浏览器完成登录确认。CLI 会话的权限比完整门户会话窄。无人值守的程序应通过运行环境的密钥管理,以 HB_API_KEY 或 --token-stdin 提供组织 API Key。不要把 Key 放在命令行参数、代码库、Profile 或智能体提示词中。
服务器仍按具体活动Developer 组织的一组数据工作及其相关设置核对权限。命令出现在帮助列表里,不代表当前凭证获准执行。遇到 403 时,先用 hb auth whoami --json 核对身份、当前组织及目标活动,不通过换用他人的凭证扩大范围。
先读取,并检查每次结果
从只读操作开始:
hb campaign list --limit 5 --json标准输出只有一个 JSON 封套,应同时检查 error.code 和退出码;进度消息在标准错误输出。data.items 为空,表示本次范围没有可见活动。若 data.has_more=true,把返回的 data.next_cursor 传给下一次的 --cursor。--all 会连续读取多页,应在确有需要时使用。
| 退出码 | 含义 |
|---|---|
0 | 该命令按自身规则完成;成功读取回执不表示之前的写入成功。 |
1 | 请求已完成,但没有达到命令的完成条件:文件未通过验证、计划无法应用,或 campaign records pull --all 的导出提前停止。 |
2 | 命令参数无效或请求格式有误。 |
3、4 | 缺少可用凭证或权限不足。 |
5 | 冲突或需要本人决定的结果。 |
6 | 暂时性错误,或输出没有送达;按具体提示重试。 |
7–10 | 服务失败、支出限制、等待超时或契约不匹配;检查 error.code。 |
130 | 命令被中断。 |
浏览器会话用完后执行 hb auth logout。hb auth sessions list 和 hb auth sessions revoke 用于查看与撤销已保存会话;组织 API Key 另行管理。
写入与发布命令
每次写入都按同一顺序进行:先写候选文件,再验证、规划,最后用你自己选定的请求键应用。下表每条命令对应 Campaign API 的同一步操作,请求、回执和错误契约见该页。
| 步骤 | 命令 | 所需权限 |
|---|---|---|
| 围绕一个模板生成候选文件 | hb campaign init --template <template-id> --out campaign.json | campaign:read |
| 从已有版本生成候选文件 | hb campaign init --from-version <campaign-id> --out campaign.json | campaign:read |
| 验证候选文件 | hb campaign validate --file campaign.json | campaign:author |
| 规划新建活动 | hb campaign plan --create --file campaign.json --out plan.json | campaign:author |
| 规划对已有活动的修改 | hb campaign plan <campaign-id> --file campaign.json --out plan.json | campaign:author 和 campaign:read |
| 创建活动 | hb campaign create --file campaign.json --plan plan.json --idempotency-key <your-key> | campaign:author |
| 应用修改 | hb campaign apply <campaign-id> --file campaign.json --plan plan.json --idempotency-key <your-key> | campaign:author |
| 提出发布提案 | hb campaign launch propose <campaign-id> | campaign:launch |
| 执行已确认的发布 | hb campaign launch execute --proposal <proposal-id> --idempotency-key <your-key> | campaign:launch |
init --template 生成的文件把预算、奖励、上限等需要你决定的值留成 <DECIDE: …> 占位符。验证前逐项替换。文件里还有占位符时,CLI 拒绝发送,并以退出码 1 和 PLACEHOLDERS_UNANSWERED 结束。
validate 和 plan 只检查。候选文件无效或无法应用时,两条命令都以 1 退出,脚本可以在这里停下。plan --out 保存已复核的更改清单;create --plan 和 apply --plan 写入前会重新规划,文件或原版本在复核后发生变化时以 PLAN_DRIFTED 拒绝。
--idempotency-key 标识一次写入。用同一个键重发同一请求,服务端只返回首次尝试的结果,写入只发生一次。另一项更改请换新键。
应用配置的响应丢失时,用原请求键查看回执:
# Campaign 文件的应用(默认动作)
hb campaign actions inspect --request-key <your-key> --json
# 模板的应用
hb campaign actions inspect --request-key <your-key> --action template.apply --json此查询一次只查一种动作。不带 --action 时查的是 campaignfile.apply,所以模板的应用必须加 --action template.apply,否则会查不到回执,或查到另一次使用同一请求键的写操作的结果。此查询适用于 Campaign 文件和模板的应用操作,不包括 Launch。Launch 响应丢失时,以同一请求键重发相同的发布意图,让服务端返回首次操作的结果。uncertain 表示结果未定,需要人核对回执步骤和活动状态,再决定后续处理。
发布会锁定活动预算,所以分三步、由两方完成。hb campaign launch propose 记录一份提案,并打印 Developer 门户确认页面的地址;带 --json 时,地址在 data.confirmation_url。对该活动有编辑权限的人登录门户,阅读提案后选择 Confirm this launch(确认这次发布)。之后 hb campaign launch execute 把已确认的提案执行一次。CLI 没有确认命令;提案和执行都要用组织 API Key,hb auth login 的登录会话会被拒绝。
确认当前指向哪个环境
每次写入前都确认一遍。
hb config profiles show --json输出里的 environment 和 api_url 是这个 profile 写了什么。下一条命令的实际去处逐个字段单独算,每个字段取第一个有值的:
| 这个值 | 按顺序取第一个有值的 |
|---|---|
| 用哪个 profile | --profile → HB_PROFILE → 保存的默认 profile |
api_url | --api-url → HB_API_URL → 上面选中的那个 profile |
environment | --environment → HB_ENVIRONMENT → 上面选中的那个 profile |
--profile 只决定由哪个 profile 兜底,它排在 HB_API_URL 和 HB_ENVIRONMENT 后面。所以 --profile staging 配上一个指向生产的 HB_API_URL,走的是环境变量。
environment 和 api_url 还要彼此对得上:每个环境只认自己那几个 origin,对不上就以 ORIGIN_MISMATCH 拒绝执行,而非打一行警告。所以 shell 里单独残留一个 HB_API_URL 会当场被拒。会静默跑错环境的是另一种情形:HB_API_URL 和 HB_ENVIRONMENT 成对指向同一个别的环境 —— 这时两个值自洽、profile 整个不参与,而 hb config profiles show 仍然显示 staging。
凭证是另一条线。hb auth status 报下一条命令实际会用哪一份凭证,并在 HB_API_KEY 盖住已保存会话时明说这一点。
| 作用 | 命令 | 所需权限 |
|---|---|---|
| 列出全部 profile(本机保存的环境配置),并标出当前默认那个 | hb config profiles list | — |
| 看一个 profile 的内容;省略名字时看当前默认的 | hb config profiles show <名字> | — |
| 新建或替换一个 profile | hb config profiles set <名字> --environment <production、staging 或 local> --api-url <地址> --org <组织 id> | — |
| 把某个 profile 设为默认 | hb config profiles use <名字> | — |
| 忘掉一个 profile | hb config profiles remove <名字> | — |
这五条都不发网络请求,也都不碰凭证。profile 只记录去哪里、预期哪个组织;凭证每次运行时从环境变量或标准输入进来。所以换环境时,profile 和凭证要一起换。
登录与会话
这些命令都不指定活动,所以都不要 campaign:* 权限;凭证实际能做什么仍由服务端判定。
| 要做的事 | 命令 | 所需权限 |
|---|---|---|
| 在浏览器里登录 | hb auth login | — |
| 看下一条命令会用哪份凭证 | hb auth status | — |
| 确认服务端核出来的调用者 | hb auth whoami | — |
| 这个版本支持什么、这份凭证能做什么 | hb capabilities | — |
| 列出以你的身份登录的终端 | hb auth sessions list | — |
| 吊销其中一个会话 | hb auth sessions revoke <session-id> | — |
| 结束本机的会话 | hb auth logout | — |
hb auth status 不发网络请求,它读的是本机保存的会话。其余几条都要发请求。
读取命令
写入之前、发布之后,用这些命令确认服务端实际记录了什么。它们都不写入。
| 要回答的问题 | 命令 | 所需权限 |
|---|---|---|
| 这个活动现在是什么状态,这份凭证能对它做什么 | hb campaign get <campaign-id> | campaign:read |
| 它有哪些历史版本 | hb campaign versions list <campaign-id> | campaign:read |
| 某一版的文档原文 | hb campaign versions inspect <campaign-id> --version <版本号> --out version.json | campaign:read |
| 两版之间改了什么 | hb campaign versions diff <campaign-id> --from <版本号> --to <版本号> | campaign:read |
| 一个时间窗内的事件计数,以及它们的分母 | hb campaign observation <campaign-id> --from <ISO 时间> --to <ISO 时间> | campaign:read |
| 一份候选文件会报出多少奖励 | hb campaign feasibility --file campaign.json | campaign:author |
| 这个凭证能读到哪些活动 | hb campaign list --limit 5 | campaign:read |
| 一次写入的回执 | hb campaign actions inspect --request-key <你选的键> | campaign:author |
| 一个订阅里某活动已交付的记录 | hb campaign records pull <campaign-id> --subscription <subscription-id> | — |
records pull 的所需权限一栏是 —,但它要的是带数据权限的组织 API Key,浏览器会话会被拒绝;走法见本页「导出全部交付记录」。
versions list 按版本从新到旧返回,分页用 --limit 和 --cursor,--all 走完所有页。
versions inspect 省略 --version 时取最新那一版。--raw 多返回服务端自己的字段,适合排查;要改完发回去的那一份用 --out 写出来。
observation 的窗口按事件时间算:--from 含、--to 不含。每个计数都带分母,只看分子得不出比例。
feasibility 只报价,不创建任何东西,并且会说明哪些问题它答不了。
模板命令
模板决定候选文件里有哪些字段。hb campaign init --template <template-id> 引用的就是这里的模板。
| 步骤 | 命令 | 所需权限 |
|---|---|---|
| 看本组织可引用的模板 | hb template list | campaign:read |
| 看一个模板的字段契约 | hb template get <template-id> | campaign:read |
| 生成一份起始模板文档 | hb template init --kind <类型> --name <名字> --out template.json | — |
| 验证模板文档 | hb template validate --file template.json | campaign:author |
| 创建或更新模板 | hb template apply --file template.json --idempotency-key <你选的键> | campaign:author |
template init 只在本机写一份文件,不发请求,也不需要任何权限。
更新已有模板要同时给 --template-id 和 --base-hash,后者来自 hb template get;只给 --template-id 会被拒绝。少了它,两个人先后改同一个模板时,后写入的会覆盖前一个,而双方都看不出发生过覆盖。
模板的应用也有回执,但查的时候必须带 --action template.apply,否则查到的是另一次写操作的结果,或者什么都查不到。
这一页不含 hb dsa … 的八条命令(向活动设计助手咨询)和 hb agent runs,目前也没有其他页面介绍它们。
导出全部交付记录
hb campaign records pull 读取一个活动交付到某项订阅的记录。它固定从第一条开始读,订阅的增量读取位置保持原位。活动筛选只会在订阅已授权的范围内缩小结果:收费订阅的范围仍是此前已取得的那一段,读到的始终是已交付记录,而非活动的全部提交。先确认 hb --help --json 列出了这条命令;你的版本没有它时,改用 HTTP 数据接口逐页读取。
凭证与第一页
这条命令需要一把对该订阅有数据读取权限的完整组织 API Key,hb auth login 的登录会话会被拒绝。只有 Data 授权的 Key 也可以运行 hb capabilities;它会显示 Campaign API 目录不可用,这对本命令没有影响。按首次获取已授权数据设置 HB_API_KEY 和 HB_SUBSCRIPTION_ID,再把 Key 只交给这一条命令:
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不加 --all 时只读一页,并返回 data.next_cursor。--limit 是每页条数,默认 50,最多 200。命令只接受一个 Campaign ID。
导出所有页
--all 沿游标继续读取,直到服务端报告没有更多记录。把结果写进私有目录:
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' "$?"记录在 data.items。两项检查都通过,才把这个文件当作完整导出:退出码为 0,且 data.complete 为 true。
data 字段 | 含义 |
|---|---|
items | 本次命令读到的记录,顺序与服务端返回一致。 |
count | items 中的记录数。 |
pages_read | 本次命令请求的页数。 |
has_more | 命令停止时,服务端是否仍报告还有记录。 |
next_cursor | 之后可以续读的位置,或 null。 |
complete | 只有未传 --cursor、从第一条读到最后一页时才是 true。 |
pagination_stop_reason | null,或 --all 提前停止的原因。 |
完整结果与部分结果
完整导出的结果如下。两个示例都省略了 data.items 以及封套中的 requestId、context、notices,标识符只是示意。
{
"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
}部分导出以 1 退出。文件里仍保留已读到的记录,并说明停在哪里:
{
"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_reason | 发生了什么 | 你现在做什么 |
|---|---|---|
page_limit | 命令已读 1,000 页。按默认每页 50 条,就是 50,000 条记录。 | 从 next_cursor 续读。加 --limit 200 可让单次命令读到更多记录。 |
item_limit | 命令已读 100,000 条记录。 | 从 next_cursor 续读。 |
missing_cursor | 服务端报告还有记录,却没有返回游标。 | next_cursor 为 null,这个文件没有安全的续读位置。保留它供排查,再从第一条重新导出。 |
repeated_cursor | 服务端返回了本次命令已经用过的游标。 | next_cursor 为 null。重复的游标只会回到同一页,请从第一条或你此前保存的更早游标重新导出;再次出现时联系 hello@humanbased.ai。 |
续读部分导出
只有 data.next_cursor 是字符串时才续读。复制它的值,去掉 JSON 引号:
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' "$?"一次运行最多读取 100,000 条记录,较大的导出需要续读多次。每次续读保存为单独的文件:第 2 部分、第 3 部分,依此类推。续读结果覆盖了之前的文件,那一部分记录就丢失了。
续读文件只包含游标之后的记录。即使它读到最后一页并以 0 退出,data.complete 仍是 false。完整导出等于第一个文件的 data.items 依次接上每个续读文件的 data.items,各次命令使用同一个活动和订阅。
保护输出
| 导出的哪一部分 | 对你意味着什么 |
|---|---|
| 记录内容 | data.items[].data 按交付时的原样写出,外形像凭证的值也照样保留。按源数据的要求保管这个文件。 |
| 数字 | 记录内容里的数字保留原有位数,包括超出 JavaScript 安全整数范围的整数和长小数。数值需要这种精度时,用能保留它的解析器读取。 |
| 临时文件 | 读取期间,CLI 把记录暂存在系统临时目录里仅当前用户可读的文件中,命令结束时删除。请在那里留出整份导出所需的空间。 |
| 输出中断 | 管道关闭或目标位置写满时,命令以非零退出码结束,并在标准错误输出报告原因。已经写出一部分的 JSON 文件是残缺的:丢弃它,重新导出。 |
错误
退出码与 error.code | 原因 | 你现在做什么 |
|---|---|---|
1,PAGINATION_INCOMPLETE | --all 在还有记录时停止。 | 查看 data.pagination_stop_reason,按上文续读。 |
2,INVALID_ARGUMENT | Campaign ID 为空或是逗号分隔的列表,或某个 ID、游标外形像凭证。请求没有发出。 | 只传一个 Campaign ID 和真实的标识符。Key 只通过 HB_API_KEY 或 --token-stdin 提供。 |
3 | 没有可用凭证:Key 缺失、格式有误、过期或已撤销,或者用了登录会话。 | 提供完整的组织 API Key。 |
4 | Key 没有数据读取权限,或订阅在它的范围或组织之外。 | 按创建和使用 API Key检查 Key 的 Data 授权。 |
6 | 服务暂时不可用,或输出没有送达。 | 重新执行同一条命令;从头读取既不计费,也不移动读取位置。 |
接口操作和权限见 Campaign API。把一次限定范围的读取交给智能体,见通过智能体使用 Humanbased。