Skip to main content
A compound tool bundles a short sequence of your existing host and connector tools into one capability the agent can call by name. Each step still runs through guard.bind, so approvals, grants, breakers, and audit apply per step — not to the compound as a whole. Use compound tools when a task always spans the same few primitive calls (fetch, transform, write) and you want the agent to reach for one intent name instead of chaining several. Extraction never writes this file — you author it.

When to use a compound

Reach for a compound when all three are true:
  • The steps are stable and belong together as a single user intent.
  • Each step is already a route or openapi tool in .vendo/tools.json, a connector tool, or a Vendo capability.
  • You want the agent to see one descriptor instead of several.
If any step needs branching a JSONata expression cannot express, or the flow is long-running or event-driven, use an automation instead.

The capabilities file

Compounds live in .vendo/capabilities.json. A compound entry inside tools.json is rejected at load with a pointer to this file.
A binding accepts 1–50 steps with unique id values. Each step targets one existing tool by name. args, if, and forEach are JSONata expressions evaluated against the root args and prior step results by id.

Steps

Every step runs if → forEach → args → invoke in that order.
  • if — skip the step when the expression is falsy.
  • forEach — invoke the step once per item, up to 1000 items. The item is available to args as the step’s context. Non-array values fail loudly.
  • args — the JSON object passed to the target tool after evaluation.
Prior step results are available by step id. Root inputs are available as args.

Risk

The compound’s declared risk must equal the maximum risk of its steps after overrides apply. Under- or over-declaring risk quarantines the entry.

Overrides

.vendo/overrides.json applies to compounds by name, field by field, the same way it applies to extracted tools. Use overrides to tighten risk, mark a compound critical, or disable it without editing the capabilities file.

Per-step approvals

Every step crosses guard.bind on its own descriptor.
  • A step that trips policy ask parks the whole compound with that step’s approval card. The user sees the real step name, arguments, and risk.
  • A standing grant for the step tool runs the walk under decidedBy: "grant" with the grant id in audit.
  • critical on a step forces an ask on every run, even under a standing grant.
  • The maxWritesPerRun breaker counts each write step and can trip mid-walk.
  • Policy block on any step halts the compound before that step runs.
Approving or granting the compound name never exempts its steps. Away runs follow the same rule: a compound-level grant leaves each step parked until it has its own step-level grant, and actAs only ever receives step grants.

Resume

When a step parks, the compound resumes from that step after the user decides. Completed steps do not re-run — Vendo re-issues the parked step call verbatim so the approval matches the original request. Resume state is in-memory, bounded to 1000 entries per registry with a 60 minute TTL. A process restart re-walks the compound from step 0 on the next call. With per-step approvals, a compound whose own policy decision is “ask” re-asks on each resume.

Quarantine

Vendo validates every compound at load. Entries that fail validation are quarantined: the name is reserved, the compound never appears in descriptors or dispatch, and boot succeeds. Common causes:
  • A step targets an unknown tool, a disabled tool, or another compound.
  • A step targets a fn: or registry-added tool.
  • The declared risk is not the maximum of the step risks.
  • Two capability sources declare the same name — this throws conflict instead of quarantining.
Fix the entry and it becomes available on the next load.