> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blobhub.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Utilities

> Diagnose a setup with doctor, and install shell completion

`doctor` and `completion` support the rest of the binary rather than doing anything to a blob: `doctor` reports on
the local setup — credentials, reachability, key scope, currency — and `completion` prints a shell completion
script. Neither takes a manifest, and `completion` needs no credentials at all.

## `blobhub doctor`

Check credentials, permissions, API reachability, key scope, and CLI currency.

Reach for it when another command fails in a way its error code alone does not explain, or immediately after
installing on a new machine. It reports on the setup a command would have run under, without running one.

### Synopsis

```bash theme={null}
blobhub doctor [--profile <name>] [--api-key <key>] [--api-url <url>]
```

| Flag        | Default                                                                  | Description                                  |
| ----------- | ------------------------------------------------------------------------ | -------------------------------------------- |
| `--profile` | the default profile                                                      | Profile to diagnose.                         |
| `--api-key` | from the environment, then the profile                                   | API key, overriding profile and environment. |
| `--api-url` | from the environment, then the profile, then `https://api.blobhub.io/v1` | API URL, overriding profile and environment. |

The three overrides are [`whoami`](/cli/auth#blobhub-whoami)'s, so a key can be diagnosed before it is stored.

### What it does

Seven checks run in a fixed order, each contributing exactly one row:

```text theme={null}
✓ python        3.12.4
✓ credentials   profile 'default' at /Users/you/.blobhub/credentials.yaml
✓ api           https://api.blobhub.io/v1 reachable (118ms, HTTP 401)
✓ key           valid -- Ada Lovelace (<user id>)
✓ scope         full
! version       0.1.0 -- 0.2.0 is available
✓ allowlist     no stale cache entries
```

Rows are marked `✓` pass, `✗` fail, `!` warn, `-` skip.

Under `--json` the payload carries `checks` — one entry per row, holding `name`, `status` (`ok`, `fail`, `warn` or
`skip`) and `detail`, the text the rendered row prints after the check's name — and `ok`, which is `false` exactly
when some row is `fail`. Rows come in the order above, and the envelope's `schema_version` sits alongside.

| Check         | `✓`                                                        | `✗`                                                                                                | `!` or `-`                                                    |
| ------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| `python`      | 3.12 or newer                                              | older than 3.12                                                                                    | —                                                             |
| `credentials` | a key resolved, from a flag, the environment, or a profile | no key from any source, a named profile that is not stored, a loose file mode, or a malformed file | —                                                             |
| `api`         | the URL answered at all, `401` included                    | network error or timeout                                                                           | —                                                             |
| `key`         | `GET /v1/users/me` accepted it                             | rejected, or could not be validated                                                                | `-` when no key resolved                                      |
| `scope`       | `full`, or `restricted` for an org- or blob-scoped key     | —                                                                                                  | `!` on `SCOPE_UNVERIFIED`; `-` when the key check did not run |
| `version`     | running the newest published release                       | —                                                                                                  | `!` when a newer release exists, or when PyPI cannot say      |
| `allowlist`   | no cached entry past its staleness window                  | —                                                                                                  | `!` on `ALLOWLIST_STALE`, naming each stale entry             |

The report leaves a few things unsaid.

**It never raises.** Every check is wrapped, so a failure — an unreadable credentials file, a surprise from the
filesystem — becomes that check's `fail` row carrying its error code, and every later check still runs. A
diagnostic that dies on the first problem cannot report the second.

**It runs with no credentials at all.** Where every other command resolves a key or exits, `doctor` resolves the
URL and the key independently: a missing key is the `credentials` row's failure and the `key` and `scope` rows'
skip, while `api` and `version` still run against the default URL. That state is precisely what the command
exists to report.

```text theme={null}
✓ python        3.12.4
✗ credentials   no API key from flags, environment, or credentials file
✓ api           https://api.blobhub.io/v1 reachable (104ms, HTTP 401)
- key           skipped (no credentials)
- scope         skipped (no credentials)
✓ version       0.1.0 (latest)
✓ allowlist     no stale cache entries
```

**It resolves the profile name before the key**, in the same order every other command does. A `BLOBHUB_PROFILE`
naming a profile that is not stored fails the `credentials` row even when `BLOBHUB_API_KEY` is set — which is the
honest report, since that combination exits `1` on every command that resolves credentials properly.

**The version check talks to PyPI, not to BlobHub**, with a two-second timeout, and deliberately does not carry
your API key to that third-party host. An unpublished package, a timeout or any network error all report `latest
unknown`, and never fail the run.

### Exit code

`1` if any row is `✗`, otherwise `0`. A `!` or `-` row never changes it.

`doctor` is the one command that can exit non-zero without printing an `error:` line, because its failure is a
report rather than an operation that failed.

### Errors

`doctor` raises nothing — that is the point of it. These codes appear **inside a row's detail** instead:

| Code                               | Row                                                                   |
| ---------------------------------- | --------------------------------------------------------------------- |
| `PROFILE_NOT_FOUND`                | `credentials`, when a named profile is not stored.                    |
| `INSECURE_CREDENTIALS_PERMISSIONS` | `credentials`, when the file is readable by group or other.           |
| `CREDENTIALS_NOT_FOUND`            | `credentials`, when the file is present but unparseable or malformed. |
| `SCOPE_UNVERIFIED`                 | `scope`, when the scope probe failed.                                 |
| `ALLOWLIST_STALE`                  | `allowlist`, once per stale cache entry, with its age in days.        |

## `blobhub completion`

Print a shell completion script for bash, zsh, or fish.

### Synopsis

```bash theme={null}
blobhub completion <shell>
```

| Argument | Default  | Description                   |
| -------- | -------- | ----------------------------- |
| `shell`  | required | One of `bash`, `zsh`, `fish`. |

### What it does

Writes a completion script to stdout, preceded by a comment naming the install one-liner for that shell. It needs
no credentials and makes no network call.

Append it to your shell's startup file, or drop it where the shell looks for completions:

```bash theme={null}
# bash
blobhub completion bash >> ~/.bashrc

# zsh
blobhub completion zsh >> ~/.zshrc

# fish
blobhub completion fish > ~/.config/fish/completions/blobhub.fish
```

Then start a new shell. There is no `--install` flag: writing into a startup file is invasive, and `>>` already
does it in a way you can read first.

**This is the one command exempt from `--json`.** Its output is a shell script meant to be piped into a file, and
wrapping a script in a JSON envelope would make the only use of the command impossible — so it writes to stdout
directly. Passing `--json` changes nothing about what it prints.

### Errors

None. The shell argument is a closed set, so an unsupported value is a usage error — exit `2` — caught before the
script is generated:

```text theme={null}
error: 'tcsh' is not one of 'bash', 'zsh', 'fish'.
```

## See also

* [Authentication](/cli/auth) — the credentials `doctor` reports on.
* [Concepts](/cli/concepts) — the platform behaviours behind several of the codes `doctor` surfaces.
* [Error codes](/cli/error-codes) — what each code in a `doctor` row means when a command raises it for real.
