Skip to main content

Building a bundle: composing marketplace assets

Manifest kind: humanos.bundle.v1 Type: BundleManifestV1 (@human/platform-extensions) Canon: kb/155

A bundle is the installable unit of the HUMΛN marketplace. It composes one or more members — agents, connectors, extensions, workflows, and muscles — into a single install, and it can declare its own extension points on top of those members: command palette entries, Companion prompt lenses, canvas renderers, workforce inbox renderers, proof gates, and install-time configuration.

Anatomy

kind: humanos.bundle.v1
id: org.example.my-suite
name: My Suite
version: 1.0.0
members:
  - kind: agent
    asset_id: human-agent-example
    version: "^1.0"
    required: true
  - kind: extension
    asset_id: human-extension-example
    version: "^1.0"
    required: true
install_order: [agents, extensions, connectors, workflows, muscles]
commands:
  - id: my-suite.show_status
    name: Show status
    description: View the current status of My Suite's automation
    icon: "lucide:Activity"
    category: Ops
    intent_triggers: ["show my suite status", "how is my suite doing", "my suite health check"]
    autonomous_ok: true

commands[] is mandatory (Canon Rule 6)

Every BundleManifestV1 must declare commands with at least one entry. This is Canon Rule 6 (kb/10 §COMPANION AS PLATFORM — Bundle-Contributed Commands): the Companion is the primary UI for the platform, and if your bundle's capabilities aren't registered as commands, users cannot find them — the command palette can't surface them, intent routing can't match them, and the Companion can't invoke them. An empty or missing commands[] array is a validation error, not a warning — validateBundleManifest() rejects it at publish time, at install time, and in CI.

Field by field:

Field Type Required Notes
id string yes Globally unique, namespaced <bundle-prefix>.<slug> (e.g. hitl.show_approvals). Regex: /^[a-z][a-z0-9_-]*\.[a-z][a-z0-9_.\-]*$/. Never rename across versions — intent routing and analytics key on it.
name string yes Display name in the palette. Verb-noun, short: "Show approvals", "Escalate to Human".
description string yes One line stating the user benefit, not the implementation ("View active escalation sessions requiring attention", not "Calls the session list endpoint").
icon string yes lucide:<IconName> scheme (PascalCase Lucide icon name) or an absolute URL to an icon image.
category string no Grouping label in the palette UI, Title Case (e.g. "Human-in-the-Loop", "Finance").
canvas_kind string no If the command opens a living canvas, the registered CanvasKind it opens (must match a kind registered in @human/companion-canvas). Omit for commands that respond conversationally.
intent_triggers string[] yes (may be empty at the schema level, but marketplace review requires ≥3) Natural-language phrases the intent classifier matches to invoke this command. Use diverse phrasing, not keyword permutations, and avoid overlap with other commands in your bundle.
autonomous_ok boolean no Default false. When true, the Companion may invoke the command without an explicit user confirm — reserve this for strictly read-only commands. If the command mutates state, spends money, or touches anything a human would want to approve, leave it false (or omit it).
shortcut string no Optional palette slash shortcut, e.g. /approvals. Lowercase, hyphenated, starts with /. Shortcuts share one global namespace per org.
capability_id string no Formal capability ID linking this command to a CapabilityReflexEntry in the registry. If omitted, the bundle compiler may synthesize one from id.

Extension points reference

Beyond members[] and commands[], a bundle can declare any of the following. Every one of these is a generic mechanism available to any bundle — first-party or third-party marketplace — with no bundle-ID-specific code anywhere in the platform.

Extension point Field What it does
Composed members members: BundleMemberV1[] The agents, connectors, extensions, workflows, and muscles this bundle installs together, in install_order.
Command palette commands: BundleCommand[] Command palette entries + intent-routing triggers. Mandatory (Rule 6, above).
Proof gates gates: ProofGate[] Measurable outcome definitions (hypothesis, event types, target metric, status thresholds) auto-registered via GateRegistry on install. Picked up by GrowthAgent for weekly measurement; LLM diagnosis stays opt-in per gate (diagnosis_config.enabled).
Canvas renderers canvas_renderers: BundleCanvasRendererEntry[] (paired with canvas_kind on a command) Companion Canvas renderers this bundle contributes. Module mode (mode: 'module') is a compiled-in, trusted React renderer resolved by componentRef — this is the path for first-party and reviewed marketplace bundles, not a sandboxed iframe. Sandboxed iframe mode (mode: 'sandboxed_iframe') is for untrusted marketplace UI: hash- and signature-verified bytes rendered inside a strict-sandbox iframe. Pick module mode whenever your renderer ships as part of the reviewed bundle package.
Workforce inbox workforce_module: WorkforceModuleBlockV1 Work-item renderer declarations (approval_gate, review_artifact, edit_artifact, guided_workflow) plus routing hints, so tasks your bundle creates render correctly in the Workforce Cloud inbox and route with the right urgency/escalation policy.
Prompt contributions prompt_contributions: Array<{ lens_id, name, description, applies_to } & ({ system_content } | { render_hook })> Companion system-prompt lens snippets injected when the listed Companion states (applies_to, e.g. 'intent_detection', 'companion_chat') are active. See the static-vs-render_hook distinction below — this is the field most bundle authors under-use.
Config overrides config_overrides (populated at install; not a manifest field — see below) Per-org, per-installation JSON configuration your bundle's runtime code reads back.
Install policy install_policy: 'all_orgs' | 'staff_only' | 'human_org_only' | 'opt_in' Controls which orgs can install (or automatically receive) this bundle. See below.
Capability tags capabilities?: string[] Opt-in vocabulary tags (e.g. 'escalation_routing') that let core runtime code detect cross-cutting bundle behavior generically instead of branching on your bundle's literal id. See below.

prompt_contributions: static content vs. render_hook

Every prompt_contributions[] entry shares four fields — lens_id (unique lens identifier), name, description, and applies_to (the Companion states where the lens activates) — plus exactly one of two content sources:

system_content: string — a static string, written once at manifest-author time. This is baked into your bundle's source and is identical for every installing org. Use it when your prompt lens has no org-specific configuration to reflect — the same guidance applies no matter who installs the bundle.

prompt_contributions: [
  {
    lens_id: 'my-suite.summary-style',
    name: 'Summary Style',
    description: 'Always summarize before recommending an action.',
    applies_to: ['companion_chat'],
    system_content: 'When responding, lead with a one-sentence summary before any recommendation.',
  },
],

render_hook: { module: string; export_name: string } — a dynamically resolved function, for lenses that need real conditional logic instead of flat {{variable}} substitution. At install (and reseed) time, the platform runs (await import(module))[export_name](configOverrides) and uses the returned string as the prompt content. The exported function receives the installing org's configOverrides and can return a string synchronously or a Promise<string> — build different prose per org from the same bundle package, evaluated fresh every time the org's configuration changes:

// my-suite-bundle/src/prompt-lens.ts
export function buildSummaryStylePrompt(configOverrides: Record<string, unknown>): string {
  const style = (configOverrides.summary_style as string) ?? 'concise';
  return style === 'detailed'
    ? 'Always provide a detailed, multi-paragraph summary before any recommendation.'
    : 'Always summarize in one sentence before any recommendation.';
}
// bundle manifest
prompt_contributions: [
  {
    lens_id: 'my-suite.summary-style',
    name: 'Summary Style',
    description: "Adapts summary depth to the org's configured preference.",
    applies_to: ['companion_chat'],
    render_hook: { module: '@org/my-suite-bundle', export_name: 'buildSummaryStylePrompt' },
  },
],

If you find yourself trying to string-concatenate conditionals into a system_content template, or asking for a special case in core prompt-seeding code so your bundle's prompt can vary by org — stop, and use render_hook instead. It exists precisely so you never need either of those.

config_overrides: write-once at install, updatable after

config_overrides is populated on marketplace_installations at install time for every asset kind (agent, connector, extension, workflow, muscle, or bundle) — it's how your bundle's runtime code reads back the per-org settings a user configured during install (against your shared_config_schema, if you declared one).

After install, it is not frozen: PATCH /v1/orgs/{orgId}/installations/{installationId} merges a JSON body into an installation's config_overrides (a shallow JSONB merge — keys you send overwrite the same keys, everything else is untouched). This is the same generic route for every asset kind; there is no bundle-specific update endpoint to build or ask for.

install_policy: all_orgs is mechanically enforced, not opt-in code

install_policy controls which orgs can install — or automatically receive — your bundle:

  • 'all_orgs' (default) — any org can install; if your manifest also sets this exact policy, it will be automatically installed for every newly created org by a generic, org-creation-time hook that queries approved bundles for install_policy = 'all_orgs' and installs each one. You do not need to write, or ask HUMΛN to write, any code that names your bundle to get this behavior — declaring the field is enough.
  • 'staff_only' — only HUMΛN staff orgs may install.
  • 'human_org_only' — only the canonical HUMΛN internal org.
  • 'opt_in' — orgs must explicitly install; no automatic behavior.

capabilities: the generic alternative to a bundle-ID branch

If your bundle needs core platform runtime code to detect and react to something it does, declare a tag in capabilities: string[] rather than asking for your bundle's id to be special-cased. Runtime code checks entry.capabilities?.includes('your_tag') — never manifest.id === 'your.bundle.id'. This is the mechanism the first-party HITL bundle uses to advertise 'escalation_routing' so the Companion operator desk can offer HITL-aware routing without knowing the HITL bundle's ID:

prompt_contributions: [ /* ... */ ],
capabilities: ['escalation_routing'],

capabilities is distinct from reflex_capabilities (reflex/intent routing) and momentum_capabilities (recurring workflow loops) — it's a general-purpose, opt-in vocabulary any bundle can extend. A literal ID-equality branch in core install/lifecycle code (apps/api/src/services/**, apps/api/src/routes/**) fails CI (pnpm hardcoded-id-branches:check) unless it carries an adjacent @canon-deviation block explaining why no generic field fits yet.

Install behavior

The platform installs members in install_order, deduping shared members where policy allows, and records bundle_installations join rows. Uninstall rules must not remove a connector still required elsewhere (see install-bundle.ts policy in-repo).

Vetting

Submitting a bundle stores metadata.platform_extension_vetting with bundle_composition_review. If any extension member exists, global promotion should assume certified-grade review for the composed story — each extension member still has its own iframe/server-driven track.

CLI

human extension validate my-bundle.yaml
human extension publish my-bundle.yaml --dry-run

Brand Voice example

A full "brand voice" style suite (agents + connectors + extension + optional Companion module) is the reference mental model — see kb/155 and marketplace bundle listing UI in Command Plane.

If none of these extension points fit

The extension points above — members[], commands[], gates[], canvas_renderers[], workforce_module, prompt_contributions (static or render_hook), config_overrides, install_policy, and capabilities — cover composition, discovery, measurement, canvas UI, workforce routing, prompt customization, per-org configuration, org-wide rollout, and cross-cutting runtime detection. If none of these fit what your bundle needs: file a gap or open a plan — never ask for your bundle/asset ID to be special-cased in core code.

← All guides