Adopt in a host
One command gives a coding agent the HCP Skill, the hcpx binary and one MCP tool, and an in-process loop gets one typed tool per command.
A host is an agent product such as an IDE assistant, a coding agent or a
TypeScript tool loop, and adopting HCP takes about as much work as adding an MCP
server. For a supported host one command is the whole integration: it writes one
Skill that teaches the CLI and one tool, hcp, that runs it, both generated
from the activated packs, and a pack activated later changes the Skill's catalog
without adding a tool. Pick your agent below, or embed the runtime if you build
your own loop.
Set up in one command#
hcpx activate transit ledger
hcpx adopt claude --write # or: codex, cursor, opencode, grok, mcp, agenthcpx activate transit ledger
hcpx adopt claude --write # .claude/skills/hcp + one hcp server in .mcp.jsonOn its next start, Claude Code asks you to approve the hcp server in the project .mcp.json. The Skill also teaches it to run hcp from its shell.
Claude Code setup in detailTo inspect what adopt would write, run any target with --json and without
--write (hcpx adopt cursor --json), or run hcpx generate --json. What a
host gets depends on whether its agent has a terminal.
| Host | What it gets | Adding a pack later |
|---|---|---|
| Coding agent with a terminal (Claude Code, Cursor, Codex, OpenCode, Grok Bot) | The agent plugin: one Skill and the hcpx binary, plus the one-tool MCP export | Changes the catalog the Skill points at; no new tools |
| MCP-only client | The same plugin exposed as one MCP tool, hcp | Same; tools/list stays [hcp] |
| In-process loop (AI SDK) | HarnessAgent: one typed tool per executable command, named <pack_id>__<verb_key> | Adds that pack's executable commands as tools |
Both shapes come from one generator, under the normative rules in Projections, and run through the same runtime, the open reference or a company's own, which holds Binding, grants and the sandbox.
activated packs ──► generateHarnessSurfaces() ──┬── .hcp/plugin.json one bash wrap (`hcpx`)
├── .hcp/surface.json catalog
├── Cursor Skill + .cursor/mcp.json
├── OpenCode one tool `hcp`
├── Grok Bot / Grok Build terminal → hcpx · one MCP tool
└── AI SDK HarnessAgent tool map (in-process)The agent plugin#
Every coding agent adopts HCP through the plugin, and its three faces reach the same runtime.
| Face | What it is |
|---|---|
| Skill | One SKILL.md that teaches lint, install, and exec |
| Bash | One binary, hcpx, also installed as hcp (two names) |
| MCP | One tool named hcp (served by hcpx mcp) that runs the same commands |
bun add -g @harnesscontextprotocol/cli
bun add @harnesscontextprotocol/plugin
hcpx adopt agent --writeDuring the preview both packages are on GitHub Packages, where
@harnesscontextprotocol/plugin is restricted, and
Install the CLI shows the .npmrc.
{
"id": "hcp",
"wrap": { "bin": "hcpx", "kind": "bash" },
"skill": ".hcp/skills/hcp/SKILL.md",
"mcp": { "command": "hcpx", "args": ["mcp"], "tool": "hcp" },
"home": "/home/you/.hcp",
"activated": ["transit", "ledger"]
}mcp.command and wrap.bin are hcpx, and adopt writes hcp instead only for
an older install that answers to no other name. The host targets (claude,
codex, cursor, opencode, grok, mcp) write this same plugin into the
paths each host reads, listed in Coding agents.
Embed the runtime in your own loop#
If you build your own agent loop, HarnessAgent wraps the runtime as a
tool-loop agent with grant-filtered tools, progressive Skill disclosure and
approval on write commands.
import { Hcp, HarnessAgent } from '@harnesscontextprotocol/sdk'
const hcp = await Hcp.create({ packDirs: ['./packs/transit'], sandbox: true })
await hcp.activate(['transit'])
const agent = await HarnessAgent.create({
hcp,
harness: 'my-product-v1',
runtime: 'ai-sdk',
model,
context: { skillLeadChars: 480 },
})
const run = await agent.send('Plan a route from A to B')
await run.wait()Each executable command becomes one tool named <pack_id>__<verb_key>, with
dots turned into underscores (transit__plan), and long results are compacted
between steps (Context optimization).
AI SDK has the options, approvals and events.
Adding native support to a new host#
A host with no adopt target can attach the plugin by hand: put the Skill where
the host reads Skills and hcpx on its PATH, or register MCP as
{ "command": "hcpx", "args": ["mcp"] }. Native intake takes little more work.
A host that meets the
host checklist:
- Presents packs in one of the two shapes: the
hcpxbinary plus its Skill, for hosts whose agent has a terminal, or one tool per executable command namedhcpToolName(pack_id, verb_key), for in-process loops. Both come fromgenerateHarnessSurfaces()or the catalog at.hcp/surface.json. - Executes through the runtime (
hcpx exec <pack> <verb>on the CLI face,Hcp.exec()in-process) and never spawns the wrap binary itself. - Exposes the Skill (the copied
SKILL.md) progressively, lead first and full text on demand. - Surfaces write commands as approvals and passes
confirm: trueonly after the user has agreed. - Reads availability before offering a tool, so the agent never sees a command it cannot run.
- Never embeds credentials, adds a second policy for the same command, or hand-registers tools that bypass the pack.
A host may also subscribe to Sense for chrome, such as an inbox badge or a
"credential stale" banner, through the runtime's sink, but it never owns mint.
New hcpx adopt <host> targets go through the
RFC process.
Why MCP is not the install path#
| Adding an MCP server | Adopting HCP | |
|---|---|---|
| Setup | A config fragment per server | hcpx install, hcpx activate, then hcpx adopt once |
tools/list | N tools per server | [hcp], or the hcpx binary |
| Credentials | The server holds them | The runtime mints them; the pack names a mode |
| Writes | Tool annotations hint at side effects | Policy confirm is enforced before exec |
MCP-only hosts use the single-tool export, hcpx mcp. It
runs every call through the runtime but installs no pack, because it only
forwards to a runtime that already has packs installed and activated. Native
adopt also keeps Policy, Binding, Sense and Skill visible to the host, so it can
show approvals and teaching correctly.
Context optimization#
Ten activated packs with ten commands and a one-screen Skill each are more text than an agent should see every turn, so the generated context loads them in layers.
┌──────────────────────────────────────────────┐
│ STABLE PREFIX (cache-friendly, rarely changes)│
│ · doctrine: activate packs, never hand-wire │
│ · pack / command index (executable only) │
│ · Skill leads (~480 chars each) │
│ · "call hcp__read_skill for full teaching" │
├──────────────────────────────────────────────┤
│ TOOLS │
│ · hcp__read_skill │
│ · <pack>__<verb> … grant-filtered │
│ · write commands: needsApproval │
├──────────────────────────────────────────────┤
│ CONVERSATION (compacted by prepareStep) │
└──────────────────────────────────────────────┘The prefix holds only what changes with the activated set, the pack index and
the Skill leads, so prompt caches stay warm across turns; your own
instructions follow it. Each lead is the first skillLeadChars characters of
the pack's HARNESS.md (default 480) and often the only part the agent sees
before it acts, which is why the Skill file guide
insists it stand alone. The always-present hcp__read_skill tool returns the
full Skill for a pack_id (the hot-path table, examples and anti-patterns),
which is progressive disclosure in the Agent Skills sense with no per-pack code
in the host.
Only commands that are executable for the current grants become tools
(executableOnly: true by default), so the agent never wastes steps on tools it
would be denied. Every operation: write command carries needsApproval: true,
which the host renders while the runtime still enforces confirm. Between
tool-loop steps, prepareStep shortens old tool outputs such as long list
results and verbose doctor reports, keeps hcp__read_skill results intact,
and can narrow activeTools to the packs the conversation is using.
type ContextOptimizationOptions = {
skillLeadChars?: number // default 480
// further knobs: compaction thresholds, activeTools narrowing
}The whole bundle comes from buildHcpContextBundle(hcp, options), which is also
what hcpx generate inspects and hcpx adopt writes for Cursor and OpenCode. A
hand-rolled context kit drifts from the packs, so regenerate it instead.
hcpx generate --json