---
title: "Configuration"
description: "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.

```bash
# One project for one command
codespar servers list --project proj_abc123

# Or for the whole shell
export CODESPAR_PROJECT=proj_abc123
```

There 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.

```bash
# 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`:

```json title="stdout"
{
  "error": {
    "kind": "cli",
    "message": "Not logged in. Run `codespar login` or set CODESPAR_API_KEY."
  }
}
```

```text title="stderr"
✗ 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` |

```json title="stdout"
{
  "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.

```text title="stderr"
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:

```bash
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
fi
```

## Debugging

`--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.

```bash
codespar whoami --json
```

When 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.

## Next steps

<NextStepsGrid items={[
  { label: "QUICKSTART", title: "Quickstart", description: "Install the SDK after you've explored the catalog via CLI.", href: "/docs/quickstart" },
  { label: "SERVERS", title: "Servers & Toolkits", description: "Browse the MCP server catalog.", href: "/docs/servers" },
  { label: "CONCEPT", title: "Authentication", description: "How API keys, service auth, and Connect Links fit together.", href: "/docs/concepts/authentication" },
  { label: "DEBUGGING", title: "Debugging", description: "Deep dive into tool-call logs and observability.", href: "/docs/debugging" },
]} />
