.md

Adapter

When to use wrap, composite, openapi or sense_only, the fields and safety rules of a wrap, and how a pack grows from pass-through to composite.

On this page

An Adapter is how a command runs, and it sits beneath the pack's identity. A pack can move from a wrap over a demo bin to the real CLI and then to composite while its id, commands, Policy, Skill, host projection and grants stay the same, which is why commands deserve good names from the start.

KindMeaningReach for it when
wrapSpawn an existing CLI with a rendered argvThe capability already exists as a binary. This is the default
compositeCall in-process (HTTP/SDK)You own the SDK, or spawn cost matters
openapiCommands bootstrapped from an OpenAPI documentYou want a large surface quickly and will review the Policy it infers
sense_onlyEmit triggers; no user commandsThe pack observes and never acts

Wrap#

Most packs start as a wrap, which leaves the wrapped tool unchanged.

verb_key ──► argv from cli[] / argv_template (no shell interpolation)
         ──► spawn allow-listed wrap.bin … --json
         ──► parse stdout · non-zero exit → { ok: false, error }
surface.json (fragment)
"kind": "wrap",
"wrap": {
  "bin": "../../bins/ledger.mjs",
  "argv_template": ["{{verb}}"],
  "agent_env": { "LEDGER_OUTPUT": "json" }
}
FieldMeaning
binThe executable. Relative paths resolve against the pack directory
argv_templateFallback argv when a command has no cli[]. {{verb}} expands to the command tail
agent_envEnvironment defaults the bin already understands. Pack-owned; runtimes never special-case bin ids

Arguments are templated into an argv and never into a shell string. The bin must be on the sandbox allow-list, and an unknown bin is denied, never looked up on PATH. The minted Binding reaches the bin as the env or files it already reads, and tokens never appear in Skill logs. A wrap declares named commands or an explicit pass_through bootstrap (HCP/1.1), and lint fails when it declares neither.

Pass-through is a bootstrap#

JSON
"pass_through": { "allowedSubcommands": ["status", "list"], "maxArgv": 6 }

Pass-through gets a binary under Policy in an hour. Then promote the hot path to named commands with Policy rows and drop the allow-list. A mega-command run does not conform.

Composite#

When the SDK is yours, calling in-process saves serialising across a process boundary. The hcp-cli bootstrap pack is composite, and so are most linked-channel packs once they settle, usually in steps:

pass_through ──► named 5–12 commands + policy.json ──► composite for hot paths

OpenAPI#

An openapi pack points at a document and lets tooling propose commands, with GET as read and mutating methods as write. Review the inferred Policy as a draft and still name the commands; HCP/1 requires no full codegen UI.

JSON
"kind": "openapi",
"openapi": { "url": "https://api.example.com/openapi.json" }

Sense-only#

A sense_only pack declares no user commands and at least one stimulus, and lint fails without a trigger ref. It fits pure ingress such as a webhook source or an event feed. Add connect or setup.* only when the upstream source needs a registration call, never bash to "install a webhook".