---
title: "CLI"
description: "Look up any `hcpx` command with its arguments, JSON output and exit codes, plus the access commands, the store layout and environment variables."
canonical: https://harnesscontextprotocol.io/docs/reference/cli
---

# CLI

> Look up any `hcpx` command with its arguments, JSON output and exit codes, plus the access commands, the store layout and environment variables.

`hcpx` is the reference CLI and the bootstrap Invoker for the reference
runtime, described by its own pack, `hcp-cli`. With `--json` every command
prints a single JSON object, and agents should start with `hcpx commands`. The
binary also answers to `hcp`
([One binary, two names](/docs/quickstart#one-binary-two-names) says when to use
which).

```sh
bunx @harnesscontextprotocol/cli help
# or, from a checkout of the hcp repository
bun packages/cli/src/hcp.ts help
```

The package is a private preview on GitHub Packages, and
[Install the CLI](/docs/quickstart#install-the-cli) shows how to reach it.

## Conventions

- Exit `0` on success, `1` on any failure. `hcpx check` also exits `2` when it
  finds warnings only.
- Failures print `{ "ok": false, "error": "…" }`. Most also carry a stable
  `code`, a `hint`, and `next`, the commands to run instead. See
  [Error codes](/docs/reference/errors#error-codes).
- Without `--json`, objects are pretty-printed and strings (Skill text) print raw.
- The store is `$HCP_HOME` (default `~/.hcp`). See [Store](#store).
- The bootstrap pack `hcp-cli` is installed the first time a command opens the store.

## Commands

### `hcpx doctor`

Reports runtime health.

```json
{ "ok": true, "cli": "hcpx", "protocol": "hcp", "version": 1, "home": "~/.hcp",
  "sandbox_default": true, "installed_count": 3, "activated": ["hcp-cli", "transit"],
  "connected": [], "bootstrap": "hcp-cli" }
```

### `hcpx availability [pack_id]`

Prints the four availability flags for every installed pack, or for one. The
alias is `avail`.

```json
{ "ok": true, "home": "~/.hcp", "sandbox_default": true,
  "packs": [{ "pack_id": "transit", "status": ["activated", "executable"],
    "installed": true, "activated": true, "connected": true,
    "verbs": [{ "verb_key": "plan", "operation": "read", "land": "personal", "executable": true }],
    "capabilities": ["verb.exec.read"] }],
  "activated": ["hcp-cli", "transit"], "installed": ["hcp-cli", "transit"] }
```

An unknown `pack_id` yields one row with `status: ["unavailable"]`.

### `hcpx list`

Lists installed packs with their adapter kind, command count, activation and
directory.

### `hcpx lint <pack_dir>`

Loads the directory and runs the pack lints, exiting `1` on any issue.

```json
{ "ok": false, "pack_id": "ledger", "issues": [
  { "kind": "missing_verb", "key": "transfer", "message": "verb \"transfer\" missing from policy.json" } ] }
```

[Errors](/docs/reference/errors#lint-issues) lists the issue kinds.

### `hcpx check <pack_dir> [--probe] [--agent|--json] [--init-evals] [--strict] [--no-eval] [--timeout ms]`

Grades structure, the quality rules, live CLI probes (`--probe`) and the cases
in `hcp.eval.json` when it exists (`--no-eval` skips them). `--agent` prints a
prioritised fix list for coding agents and `--json` the full report, while
`--init-evals` writes a starter eval file (never over an existing one) and
exits. `--timeout` limits each probe and eval case (default 10000 ms). It exits
`0` when clean, `2` on warnings only and `1` on errors, and `--strict` makes
warnings exit `1`. See [Check and evaluate](/docs/packs/check).

```json
{ "ok": false, "pack_id": "gh", "score": 8, "grade": "F",
  "summary": { "errors": 7, "warnings": 2, "info": 0 },
  "findings": [ { "id": "R014", "severity": "error", "where": { "file": "surface.json", "pointer": "/verbs/list/cli" },
    "message": "\"gh list\" is not a command of this CLI …", "fix": "Point \"list\".cli at a subcommand that exists …" } ] }
```

### `hcpx eval <pack_dir> [--json] [--timeout ms]`

Runs the cases in `hcp.eval.json` through the reference runtime and prints pass
or fail per case with latency and approximate output tokens, then p50 and p95
for the run. Exit `1` when any case fails, the file is missing, or the pack
fails lint (then no case runs). `--json` returns `{ ok, pack_id, evals }`, with
`evals` as in `hcpx check --json`.

### `hcpx install <pack_dir|github:…|npm:…>`

Lints, then copies the pack directory into `$HCP_HOME/packs/<pack_id>/` and its
`HARNESS.md` to `$HCP_HOME/skills/<pack_id>/SKILL.md`. Any lint issue fails the
install, and a path without `surface.json` fails with `code: "no_pack"`.

From GitHub, `hcpx install github:owner/repo[@ref][//path]` or a `github.com`
URL clones the repository, falls back to its tarball, and sends `GITHUB_TOKEN`
when set. From npm, `hcpx install npm:@scope/name` runs `npm pack` and installs
the directory named by `"hcp": { "pack": "." }` in the package's `package.json`,
or the package root; `hcpx install npm:./path/to/pack` installs a local package.

When a GitHub or npm source cannot be fetched and the catalog lists a gold
template for it, the CLI installs the template and says so in `note`.

```json
{ "ok": true, "installed": "transit", "dest": "~/.hcp/packs/transit",
  "verbs": ["find", "plan", "show", "status", "follow"],
  "next": ["hcp activate transit", "hcp availability transit"] }
```

### `hcpx uninstall <pack_id>`

Removes the pack directory, and refuses to remove `hcp-cli`.

### `hcpx activate <pack_id> [pack_id…]`

Adds packs to `state.activated` and copies each `HARNESS.md` to
`$HCP_HOME/skills/<pack_id>/SKILL.md`.

```json
{ "ok": true, "activated": ["hcp-cli", "transit"], "skills": ["~/.hcp/skills/transit/SKILL.md"] }
```

An unknown id fails with `code: "not_installed"`, a "did you mean" when an
installed pack has a similar id, and `next` commands to search or install.

### `hcpx deactivate <pack_id> [pack_id…]`

Removes packs from `activated` and `connected`.

### `hcpx connect <pack_id>`

Runs the runtime's connect step for an activated pack and needs the
`pack.connect` grant. An inactive pack fails with `not activated: <id>`.

```json
{ "ok": true, "connected": "ledger", "all": ["ledger"] }
```

### `hcpx commands [pack_id]`

Lists every command of the activated packs, or of one pack, with its
description, `read` or `write`, whether it needs confirmation, what the current
access settings decide (`access`: allow, ask or deny), its arguments with
examples, and a line ready to run.

```json
{ "ok": true, "packs": [ { "pack_id": "transit", "about": "Plan public-transport journeys…",
  "commands": [ { "command": "plan", "description": "Route options between two places with duration, changes, and fare, fastest first.",
    "operation": "read", "access": "allow",
    "args": [ { "name": "from", "required": true, "description": "Origin place name or id from find", "example": "Central" } ],
    "run": "hcp exec transit plan --json -- from=Central to=Harbour" } ] } ] }
```

### `hcpx exec <pack_id> <verb_key> [--json] [-- k=v …] [--args '{…}']`

Runs a command through the full pipeline. Arguments after `--` become `args`
(`from=Central to=Harbour confirm=true`), and `--args` takes a JSON object for
typed values or text with spaces.

```sh
hcpx exec transit plan --json -- from=Central to=Harbour
hcpx exec transit plan --json --args '{"from":"Central","to":"Harbour"}'
hcpx exec ledger transfer --json -- amount=2.80 payee=demo-transit confirm=true
```

The runtime checks arguments first, so an unknown name or a missing required
argument fails with the valid names and a "did you mean". The command returns
the [result envelope](/docs/specification/execute#62-result-envelope) without
duplicating the raw output and exits `1` when `ok` is `false`. With no command,
`hcpx exec <pack_id>` returns that pack's command list.

### `hcpx search [query] [--class class]`

Searches the community catalog at
`https://harnesscontextprotocol.io/api/v1/packs`, or `HCP_CATALOG_URL` when set,
and caches the answer in `$HCP_HOME/catalog.json` for an hour. `source` is
`remote`, `cache`, or `bundled`: the snapshot shipped in the CLI, used when the
origin is unreachable (4 s timeout) and nothing is cached.

```json
{ "ok": true, "source": "bundled", "count": 1, "packs": [{ "id": "transit", "class": "public-read" }] }
```

### `hcpx catalog [pack_id]`

Lists catalog entries, or the entry for one `pack_id`.

### `hcpx init <id> [--class public-read|gated-write] [--template transit|ledger|echo] [--dir path]`

Writes a self-contained pack directory: the three files, a `package.json`
that depends on the CLI, and a demo `bin/` for wrap templates. Gold `--template`
values keep their gold `id`. `cli_bin` names the CLI that starts it on this
machine (see [One binary, two names](/docs/quickstart#one-binary-two-names)).

```json
{ "ok": true, "dir": "./weather", "pack_id": "weather", "template": "public-read",
  "files": ["package.json", "surface.json", "policy.json", "HARNESS.md", "bin/cli.mjs", "README.md"],
  "cli_bin": "hcpx", "next": ["hcpx check ./weather --probe --agent", "hcpx install ./weather --json", "hcpx activate weather --json"] }
```

### `hcpx wrap <bin> [--id pack_id] [--class public-read|gated-write] [--dir path]`

Scaffolds a pack whose `wrap.bin` is an existing CLI on `PATH`, in `packs/<id>`
unless `--dir` says otherwise. It reads `<bin> --help` as an agent would (no
TTY, no colour, stdin closed) and drafts one command per usage line it can
parse: the `cli[]` form, the arguments, a guessed Policy row with `land: local`,
and `confirm: true` plus a suggested `preview` for commands that sound risky
(delete, send, publish, pay, and similar) or take the CLI's own confirmation
flag. `wrap.workspace.mode` is `project`, so the CLI runs in the caller's
project; `gated-write` sets Binding `local` and `public-read` sets `public`.

```bash
hcpx wrap mycli --class gated-write --dir ./mycli-pack --json
```

The result lists the `drafted` commands, `candidates` (subcommand names seen
when no usage line parsed), `json_support`, `warnings`, and the `next` steps:
review the draft against `<bin> <command> --help`, check each Policy row, then
`hcpx check <dir> --init-evals` and `hcpx check <dir> --probe --agent`. A CLI
not on `PATH` fails with `code: "bin_not_found"`.

### `hcpx share [pack_dir|github:owner/repo] [--path subdir]`

Lints a directory and prints a catalog row for
`hcp-docs/content/catalog/packs.json`; exit `1` when lint fails. A `github:`
reference reads the pack from the public repository (`--path` for a
subdirectory) and reports the same row and issues.

[Share a pack](/docs/packs/share#catalog) covers the catalog and the PR.

### `hcpx skill <pack_id>`

Prints `HARNESS.md` for an activated pack. With `--json`: `{ ok, pack_id, skill }`.

### `hcpx generate`

Produces host-neutral output from activated packs (system-prompt block, tool
list, Skill copies, per-host configuration) without writing files.

### `hcpx mcp`

Starts a stdio MCP server whose `tools/list` returns one tool, named `hcp`.
`tools/call` takes `args` (string) or `argv` (string array) as CLI argv, never
through a shell, and runs it inside the server process with `HCP_MCP=1` set.
Every CLI a pack starts inherits that variable, so the access commands refuse.
A call starts no new `hcpx`, and `resources/list` offers only catalog, help and
skills. [MCP export](/docs/hosts/mcp) shows the host side.

### `hcpx adopt agent|claude|codex|cursor|opencode|mcp|grok [--write]`

Generates the host-neutral output and writes host configuration into the
current directory, or previews it without `--write`. `grokbot` is an alias of
`grok`.

| Target | Writes |
|--------|--------|
| `claude` | `.claude/skills/hcp/SKILL.md`, one `hcp` server in `.mcp.json`, and `.claude/settings.json` with `HCP_AGENT=1` and deny rules for the access commands |
| `codex` | The protocol Skill and an HCP section in `AGENTS.md`; prints the `~/.codex/config.toml` block (the server and `HCP_AGENT=1` for Codex's shell) and never edits files outside the repository |
| `cursor` | `.cursor/skills/hcp/SKILL.md`, `.cursor/mcp.json`, `.cursor/rules/hcp.mdc` |
| `opencode` | One plugin tool `hcp` in `opencode.json` |
| `grok` | `.grok/config.toml`, rule, Skill |
| `agent`, `mcp` | The generic plugin: `.hcp/plugin.json`, the Skill, and `.mcp.json` |

`HCP_HOME` goes into host config only when you set it explicitly, so committed
config works on every machine. A `.hcp/no-adopt` file opts a workspace out of
adopt, and [Adopt in hosts](/docs/hosts) covers each host.

### Access commands

The commands that change [access](/docs/concepts/access) refuse with
`human_only` inside an agent (`HCP_AGENT=1`, or through `hcpx mcp`).

| Command | Does |
|---------|------|
| `hcpx access` | Effective mode, rules, approval authority, where each comes from, and ignored project settings |
| `hcpx mode [manual\|auto\|run] [--pack id] [--project]` | Show or set the mode, globally or for one pack |
| `hcpx allow\|ask\|deny <pack.command\|pack.*\|*> [--op read\|write] [--when k=v]… [--max k=n]… [--note text] [--project]` | Add a rule. `--project` writes `.hcp/access.json` and cannot add allow rules |
| `hcpx rules [rm <n>] [--project]` | List rules with scope and index, or remove one |
| `hcpx approvals` | Requests waiting for a person |
| `hcpx preview <pack_id> <command> [-- k=v …]` | The approval card a person would see, and the exact command |
| `hcpx approve <id>` / `hcpx reject <id>` | Decide one request; an approval covers one run of exactly that command and those arguments for 15 minutes |
| `hcpx audit [--pack id] [--limit n]` | Recent decisions from `$HCP_HOME/audit.jsonl` |

`hcpx commands` adds `access` (allow, ask, deny) to every command.

### `hcpx help`

Usage text. With `--json`, `{ ok: true, help: string[] }`.

## Store

```text
$HCP_HOME/                 default ~/.hcp
  packs/<pack_id>/         installed pack directories (verbatim copies)
  skills/<pack_id>/SKILL.md
  state.json               { "activated": [], "connected": [], "grants"?: HcpGrant[] }
  access.json              user access settings (mode, packs, rules, approvals)
  approvals.json           pending and decided approvals
  audit.jsonl              one line per command decision
```

Without `grants` in `state.json`, the CLI uses permissive grants (every
capability, every pack). Set `grants` to test denials locally, as
[Testing](/docs/packs/check#testing) shows.

## Environment

`HCP_PROJECT_ID` sets the project scope for `brain`-land commands. Without it,
the enclosing git repository is the project.

| Variable | Effect |
|----------|--------|
| `HCP_HOME` | Store location |
| `HCP_CATALOG_URL` | Catalog search origin (default: the docs site's `/api/v1/packs`) |
| `HCP_MCP` | Set to `1` inside `hcpx mcp` and every CLI it starts; `hcpx mcp` refuses to recurse, and access commands refuse with `human_only` |
| `HCP_AGENT` | `1` marks an agent's shell; access commands refuse with `human_only`. `hcpx adopt claude` sets it |
| `HCP_MODE` | Access mode for this process: `manual`, `auto`, or `run` |
| `HCP_APPROVALS` | `human` or `agent`: who can satisfy an ask |
| `HCP_PROJECT_DIR` | Working directory for packs with `wrap.workspace.mode: project` |
| `HCP_CLI` | The command the host plugins start for each call, for example `hcpx` or `bun /path/to/packages/cli/src/hcp.ts` |
| `GITHUB_TOKEN` | Sent when `hcpx install github:…` falls back to downloading a tarball |
| `HCP_SANDBOX` | Set by the runtime in the child process: `sandbox` or `native-local`. Not read by the CLI |

The CLI always runs the reference runtime in sandbox mode, with `allowBins`
holding every installed pack's `wrap.bin`, the names `hcpx` and `hcp`, and the
executable running the CLI.

## Sitemap

- [Documentation](https://harnesscontextprotocol.io/docs)
- [Packs](https://harnesscontextprotocol.io/packs)
- [Glossary](https://harnesscontextprotocol.io/docs/reference/glossary)
- [llms.txt](https://harnesscontextprotocol.io/llms.txt)
- [llms-full.txt](https://harnesscontextprotocol.io/llms-full.txt)
- [OpenAPI](https://harnesscontextprotocol.io/openapi.json)
- [MCP](https://harnesscontextprotocol.io/mcp)
