🛂 Kite PassportBuy with an agent

Troubleshooting

The Kite Passport CLI exit-code table and the state and environment gotchas that most often trip up a buyer agent.

Most of what looks like a bug is the envelope telling you exactly what to do next. Read this page in order: the envelope contract first, since it's how every kpass command tells an agent what happened and what to run next; the exit-code table second, since it's the one signal that's reliable even without --output json; then the state and environment gotchas that account for most of what actually goes wrong on the buyer surface.

The envelope contract

Every kpass command run with --output json returns the same envelope shape, with command-specific fields spread alongside it rather than nested under a data key:

{
  "_version": "1",
  "status": "<status>",
  "hint": "<human-readable summary>",
  "next_command": "<exact command to run next, or empty>"
}
statusMeaning
successThe operation completed.
human_action_requiredThe agent is correctly blocked on a human — an OTP, an email link, a passkey approval. Not an error.
pendingIn progress, not yet resolved. Keep polling.
expiredA time-limited resource — a login code, an approval link — ran out before it was used.
errorThe operation failed.

Read hint and next_command before deciding what to do next — an agent that just checks the exit code and stops misses the whole point of the envelope, which is that next_command is usually the literal command to run. This is the same "envelope scripts the agent" pattern the coding-agent quickstart and purchase lifecycle walk through end to end.

update_available

Any envelope may also carry an update_available field when a newer CLI bundle exists. When you see it, run kpass upgrade — it doesn't require re-authenticating or interrupting whatever else is in progress, and there's no reason to defer it past the current command.

Exit codes

Exit codes are the more reliable signal when you can't parse the JSON body — a crashed process, a truncated pipe, a non-JSON invocation. Rely on them for flow control; use the envelope's hint for what to tell a human.

CodeNameMeaning
0SUCCESSCommand succeeded, or status is human_action_required/pending — check the envelope, not just the code.
1NETWORKNetwork error or backend unreachable. Retriable when the envelope's retriable field says so — see the note below. Also carries funding_submission_incomplete after fund (a retriable partial result, not a network drop) — see the recovery playbook.
2USAGEMissing or invalid flag, bad argument, malformed input. Refused locally before anything was sent.
3AUTHSee the three cases below — the fix depends on which one you hit.
4NOT_FOUNDThe referenced resource doesn't exist: user, agent, session, agreement.
5RATE_LIMITEDToo many requests. Wait and retry; the error message suggests how long.
6FORBIDDENA scope or policy check refused the request — for example session_scope_forbidden, or a session's own budget or asset limits. Not an auth problem; a new session with the right scope fixes it.
7CONFLICTYou signed against a state that has since moved, or an id that's already taken (revision_conflict, idempotency_conflict, illegal_transition, terms_hash_mismatch). Re-read the current state, rebuild the command, and retry once.
8PROTOCOLA local refusal — canonicalization, signing, or verification failed on this machine, and nothing was sent. Never retry the same bytes; fix the input or local state and rebuild the command from scratch.
10BEHINDA newer CLI bundle is available. Run kpass upgrade.

Exit 3, AUTH — three distinct cases

Exit 3 covers three situations that look similar but need different fixes:

CaseWhat happenedFix
Expired JWTYour login session timed out.Re-authenticate: kpass login init --email <you> --output json, then kpass login verify.
Invalid or expired agent tokenThe bind token in agent.json no longer works.Mint a new bind token for the agent from the dashboard (Agents → agent detail → Runtimes) and bind again.
Agent owned by a different userYou're logged in as a different account than the one that owns this agent.Log back in as the owning user, or register a new agent under the current one.

Retriability isn't always known

Error envelopes carry an optional retriable field: true, false, or absent. Absence isn't the same as false — it means no server ever ruled on the request (every local refusal, every transport failure that didn't reach the backend). Exit 8 is always in that absent-or-false territory; a request that never left the machine has nothing for a server to have judged retriable.

State & environment gotchas

.kite-passport/ is project-anchored, per agent

kpass state lives in a ./.kite-passport/ directory discovered by walking up from the current directory until it hits a .git/ boundary — there's no home-directory fallback, and unlike kagent, the buyer surface has no --config-dir flag to point somewhere else. One runtime key lives per directory (./.kite-passport/runtime.key), so running a coding agent from a fresh, empty project directory for each buyer identity is the way to keep separate agents from colliding on the same state. Reusing a directory means reusing whatever agent and runtime key it already holds.

Export KITE_PASSPORT_BASE_URL on every command

The CLI resolves its backend in this order: --base-url on the command itself, then KITE_PASSPORT_BASE_URL if exported, then the compiled-in default (https://passport.dev.gokite.ai). A coding agent typically runs each shell command as its own process, and an exported variable from one invocation does not carry into the next — so if you're targeting anything other than the compiled-in default, export it on every single kpass call, not once at the start of a session. See environments for the full precedence table and base URLs.

A binding stuck pending

kpass agent status reporting pending instead of active means the runtime bound via the direct bind path — no token, registered against a public agent id — and it's waiting on the owner. There's no CLI verb that approves it. Open the dashboard at Agents → agent detail → Runtimes and approve the pending row, or see approvals and monitoring for the full mechanics. If you'd rather avoid the wait entirely, mint a bind token from the same page and use the token-bind path instead — that binding is active immediately.

An empty wallet on dev

kpass wallet balance returning nothing to fund with is expected on a fresh dev account — Kite's own faucet drop cannot fund the Arc testnet dev settles on. Use Circle's faucet instead: see getting test USDC for the exact steps.

Still stuck?

kpass status --output json is always safe to run and gives a complete diagnostic of where your session, agent, and binding currently stand, including its own next_command. When in doubt, start there before chasing an individual error.

On this page