Configuration
Configuration, scripting and debugging.
Configuration
Three things can be set, and each has the same three sources. First match wins:
| flag | environment | file | |
|---|---|---|---|
| API key | --api-key <key> | CODESPAR_API_KEY | ~/.codespar/config.json |
| Project | --project <id> | CODESPAR_PROJECT | idem |
| API base URL | --base-url <url> | CODESPAR_BASE_URL | idem |
The file is written by codespar login, which prompts for an API key and
saves it. It does not open a browser.
# One project for one command
codespar servers list --project proj_abc123
# Or for the whole shell
export CODESPAR_PROJECT=proj_abc123There is no codespar config command. The file is plain JSON at
~/.codespar/config.json, so editing it or deleting it is the whole of
configuration management, and deleting it is how you reset the CLI.
Scripting
--json is global: it works on any command and forces machine-readable output
even in a TTY. Human-readable messages go to stderr, so stdout stays clean
for a pipe.
# Servers in Brazil, as a newline-delimited list of ids
codespar servers list --country BR --json | jq -r '.[].id'What a script gets when a command fails
Every command exits 0 on success and 1 on failure. The one exception is a
bug inside the CLI, which exits 2 and prints a stack trace to stderr.
With --json, a failure is a document too. It goes to stdout, while the
human line stays on stderr:
{
"error": {
"kind": "cli",
"message": "Not logged in. Run `codespar login` or set CODESPAR_API_KEY."
}
}✗ Not logged in. Run `codespar login` or set CODESPAR_API_KEY.kind is there so a script can branch without reading prose:
kind | what happened | exit | also carries |
|---|---|---|---|
cli | the CLI refused before the API answered: no key, an --input that is not JSON, an argument the command itself rejects | 1 | |
api | the API answered with an error | 1 | status, body, and code when the API sends one |
timeout | a request or a stream passed its --timeout | 1 | |
internal | a bug in the CLI | 2 | the stack trace, on stderr |
{
"error": {
"kind": "api",
"message": "GET /v1/whoami → 401: unauthorized",
"status": 401,
"code": "unauthorized",
"body": {
"error": "unauthorized"
}
}
}One failure never becomes a document: the argument parser runs before --json
is read, so a missing argument, an unknown option or an unknown command writes
one line to stderr and leaves stdout empty.
error: missing required argument 'consumer'So a script reads the exit code first and parses stdout only after it knows
the command got far enough to write one:
if out=$(codespar wallet "$consumer" --json); then
echo "$out" | jq -r '.currencies[].available_minor'
elif [ -n "$out" ]; then
echo "$out" | jq -r '.error.message' >&2
else
# Empty stdout on a failure means the parser refused the line before --json
# was read, and the reason is on stderr. Piping an empty string into jq
# prints nothing, so a `//` fallback there never fires.
echo "check the arguments" >&2
fiDebugging
--base-url is the flag that answers "which API did this actually reach", and
codespar whoami answers the other four questions at once: whether the key is
valid, which organization and project it is bound to, which environment it acts
in, and which scopes it holds.
codespar whoami --jsonWhen a command answers nothing where you expected rows, the usual cause is a
live key reading a test project or the reverse. whoami shows which, and the
key prefix (csk_test_ or csk_live_) picks the environment on the same host.