Docs
API 1.39
Status
Guides

The kaab CLI

Run jobs, push and lint programs, review proposals and manage schedules and webhooks from a terminal.

kaab is a single binary for Linux, macOS and Windows, built on the Go SDK. It runs jobs, keeps programs in files you can version and review, and answers parked jobs, so a terminal or a CI job can do what the panel does.

#When to use it

Use the CLI from a shell, a CI pipeline or a cron job on your own machine: to run a program and save its data, to lint and push program files from a repository, or to approve proposals in bulk. From application code, use an SDK instead; for building and testing a program interactively, the program builder is quicker.

#Install

With Go 1.24 or later:

go install github.com/kaabist/kaab-go/cmd/kaab@latest
kaab version

Each release is also built as archives for Linux, macOS (darwin) and Windows, on amd64 and arm64: kaab_<version>_<os>_<arch>.tar.gz (.zip on Windows), each with the binary, its licence and README, and a checksums.txt to verify them against. Unpack one and put kaab on your PATH. There is no Homebrew or winget package yet.

Shell completion comes with the binary:

kaab completion zsh > "${fpath[1]}/_kaab"   # also bash, fish, powershell

#Sign in

kaab auth login            # paste an sk_live_ or sk_test_ key
kaab auth status

The key is checked against the API and kept in your operating system's keychain (or, where there is none, in ~/.config/kaab/credentials.toml, readable only by you). A profile holds one live and one test key; --test uses the test one, --profile picks another profile. KAAB_API_KEY and KAAB_BASE_URL override any profile, which is what CI should use.

#Run a job

curl
response=$(curl -sS --fail-with-body "${KAAB_BASE_URL:-https://api.kaab.ist/v1}/jobs" \
  -H "Authorization: Bearer $KAAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Prefer: wait=30" \
  -d '{
    "url": "'"${SITE_URL:-https://shop.example.com}"'/p/1",
    "extract": {
      "title": "h1",
      "price": { "selector": ".price", "type": "money", "locale": "tr", "currency": "TRY" }
    }
  }')
echo "$response"
TypeScript
// One call: create the job and hold the request up to 30 s for its result (`Prefer: wait`).
const job = await kaab.jobs.create({
  url: `${site}/p/1`,
  extract: {
    title: "h1",
    price: { selector: ".price", type: "money", locale: "tr", currency: "TRY" },
  },
  wait: 30,
});
if (job.status !== "succeeded") throw new Error(`job ${job.id} is ${job.status}`);
console.log(`${job.id}: ${JSON.stringify(job.data)}`);
Python
# One call: create the job and hold the request up to 30 s for its result (Prefer: wait).
job = kaab.jobs.create(
    url=f"{site}/p/1",
    extract={"title": "h1", "price": {"selector": ".price", "type": "money", "locale": "tr", "currency": "TRY"}},
    wait=30,
)
if job.status != "succeeded":
    raise SystemExit(f"job {job.id} is {job.status}")
print(f"{job.id}: {job.data.to_dict() if job.data else None}")
Go
// One call: create the job and hold the request up to 30 s for its result (Prefer: wait).
body, err := kaab.Body[client.CreateJobJSONBody](map[string]any{
    "url": site + "/p/1",
    "extract": map[string]any{
        "title": "h1",
        "price": map[string]any{"selector": ".price", "type": "money", "locale": "tr", "currency": "TRY"},
    },
})
if err != nil {
    log.Fatal(err)
}
job, err := c.Jobs.Create(ctx, body, kaab.WithWait(30))
if err != nil {
    log.Fatal(err)
}
if job.Status != "succeeded" {
    log.Fatalf("job %s is %s", job.ID, job.Status)
}
fmt.Printf("%s: %v\n", job.ID, *job.Data)
CLI
data=$(kaab jobs run \
  --url "${SITE_URL:-https://shop.example.com}/p/1" \
  --extract '{"title": "h1", "price": {"selector": ".price", "type": "money", "locale": "tr", "currency": "TRY"}}' \
  --wait 30)
echo "$data"

More forms of the same command:

kaab jobs run --url https://shop.example.com/p/1 --extract @schema.json --wait 30
kaab jobs run --program acme-report@production --input report_id=42 --session acme --wait 60

A succeeded job prints its data as JSON on stdout and a one-line summary on stderr, so kaab jobs run … > data.json does what it says. --json prints the whole envelope instead.

Exit codeMeaning
0succeeded, or still running when --wait ran out
1the request failed (the API's code, message and request id are printed)
2the job failed or was canceled
3the job is parked: waiting for an input (kaab jobs input) or for attention (kaab jobs resume, kaab open job)

#Programs, proposals, schedules, webhooks

kaab programs lint report.json          # exit 1 on errors
kaab programs push report.json --publish
kaab programs pull acme-report@production -o report.json
kaab programs diff acme-report 3 4
kaab proposals list && kaab proposals approve prp_… --promote
kaab schedules create --program acme-report@production --cron "0 * * * *" --change-detection --field price
kaab webhooks create --url https://example.com/hooks --events 'job.*'
kaab credits && kaab usage --group-by program

kaab <command> --help describes every flag, and the CLI reference lists every command.

#Worked example

Run a shop's product page, https://shop.example.com/p/1, from a terminal and keep only the price:

export KAAB_API_KEY=sk_test_…
cat > schema.json <<'JSON'
{ "title": "h1", "price": { "selector": ".price", "type": "money", "locale": "tr", "currency": "TRY" } }
JSON
kaab jobs run --url https://shop.example.com/p/1 --extract @schema.json --wait 30 > data.json
echo $?   # 0

data.json holds the job's data: the title Kulaklık Klasik 101 and the price { "amount": 1337.4, "currency": "TRY" }. In a CI step, branch on the exit code: 2 means the job failed, 3 that it parked and somebody has to answer it.

#Pitfalls

  • A live key in CI by accident. KAAB_API_KEY wins over every profile; give CI an sk_test_ key for checks and a narrowly scoped live key only where it does real work.
  • Treating exit code 0 as "done". It also means the job was still running when --wait ran out. Use --json and read status when the difference matters.
  • Forgetting --publish. kaab programs push without it saves a draft version that no alias runs.
  • Shell globbing in --events 'job.*'. Quote event patterns.

#Reference

Was this page helpful?