.md

CLI

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

On this page

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 says when to use which).

Terminal
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 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.
  • Without --json, objects are pretty-printed and strings (Skill text) print raw.
  • The store is $HCP_HOME (default ~/.hcp). See 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 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.

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.

Terminal
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 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).

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.

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

TargetWrites
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
codexThe 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
opencodeOne plugin tool hcp in opencode.json
grok.grok/config.toml, rule, Skill
agent, mcpThe 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 covers each host.

Access commands#

The commands that change access refuse with human_only inside an agent (HCP_AGENT=1, or through hcpx mcp).

CommandDoes
hcpx accessEffective 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 approvalsRequests 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#

$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 shows.

Environment#

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

VariableEffect
HCP_HOMEStore location
HCP_CATALOG_URLCatalog search origin (default: the docs site's /api/v1/packs)
HCP_MCPSet to 1 inside hcpx mcp and every CLI it starts; hcpx mcp refuses to recurse, and access commands refuse with human_only
HCP_AGENT1 marks an agent's shell; access commands refuse with human_only. hcpx adopt claude sets it
HCP_MODEAccess mode for this process: manual, auto, or run
HCP_APPROVALShuman or agent: who can satisfy an ask
HCP_PROJECT_DIRWorking directory for packs with wrap.workspace.mode: project
HCP_CLIThe command the host plugins start for each call, for example hcpx or bun /path/to/packages/cli/src/hcp.ts
GITHUB_TOKENSent when hcpx install github:… falls back to downloading a tarball
HCP_SANDBOXSet 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.