Your first portable extension¶
This tutorial builds and installs a useful extension in about ten minutes. The
pack contains only hubuum-extension.jsonc; at runtime it relies on nothing but
hubuum-cli.
1. Generate a starter pack¶
From the repository root, create the read-only starter:
The command refuses to overwrite a directory and validates its generated
workflow against the current CLI before writing it. Use --name my-inventory
when the directory name should not become the pack name.
The other templates are:
minimal: one command and one built-inrunstep;read-only: typed configuration plus an inventory workflow;executable: a runnable process-protocol skeleton for cases that truly need an external program.
Portable templates are the default because they add no runtime dependency.
2. Read the whole manifest¶
Here is a complete minimal pack. JSONC permits comments and trailing commas, but keys and strings still use JSON double quotes.
{
"$schema": "../schemas/hubuum-extension.schema.json",
"schema_version": 1,
"kind": "portable",
"name": "my-inventory",
"version": "0.1.0",
"requires_cli": ">=0.0.9,<0.1.0",
"config": {
"objects_class": {
"type": "string",
"default": "Hosts",
"help": "Class included in the inventory"
}
},
"workflows": {
"snapshot": {
"output": { "shape": "rows", "type": "json" },
"steps": [
{
"id": "objects",
"kind": "run",
"run": ["object", "list"],
"with": {
"class": { "config": "objects_class" },
"all": true
}
}
],
"result": ".steps.objects"
}
},
"commands": {
"snapshot": {
"path": ["snapshot"],
"workflow": "snapshot",
"about": "List configured inventory objects"
}
}
}
The hierarchy has three jobs:
configdeclares site settings and their types.workflowsdeclares inputs, ordered steps, and the final output contract.commandschooses which workflows users can run and defines their CLI paths and options.
The private workflow name is snapshot. The installed command is
extension my-inventory snapshot.
3. Discover a built-in command contract¶
A run step calls a built-in command in-process. Do not guess the binding
names from its flags. Ask the CLI for the workflow-facing contract:
hubuum-cli extension contract object list
hubuum-cli extension contract object list --output json
hubuum-cli extension contract --list
For object list, the contract identifies class as a string, all as a
Boolean flag, and where as repeatable groups of three strings. It also says
whether the command may mutate data and whether authentication is required.
The keys under a step's with object must be these canonical input IDs.
Rendering options such as output and table-headers are deliberately absent.
They belong to the installed extension command, after the workflow produces its
semantic result.
4. Validate and explain¶
Run both authoring checks before installation:
hubuum-cli extension validate ./my-inventory
hubuum-cli extension explain ./my-inventory --workflow snapshot
validate checks the manifest, configuration defaults, built-in bindings,
types, call graph, mutation declarations, and limits. explain prints the
normalized WorkflowPlan: ordered steps, resolved bindings, effects, replay
safety, call depth, worst-case work, output declaration, and host limits.
Both commands are local and read-only. They do not require a Hubuum login and do not execute workflow steps.
5. Configure, install, and run¶
Pack manifests are JSONC. Local Hubuum CLI configuration remains TOML. Override this pack's default class in the normal CLI configuration:
Only this namespaced table is exposed to the pack, and only keys declared by the manifest are accepted.
Install and invoke the pack:
hubuum-cli extension install ./my-inventory
hubuum-cli extension my-inventory snapshot
hubuum-cli extension my-inventory snapshot --output json
hubuum-cli extension my-inventory snapshot \
\| JQ 'map(.name)' \
\| L 10
The final two operators are the ordinary Hubuum CLI semantic pipeline. They run
after the workflow's declared rows output has been validated.
6. Add an input¶
Suppose users should choose the class per invocation. Add this to the workflow:
Change the run binding to:
Then add the exactly matching command option:
"options": {
"class": {
"kind": "string",
"position": 1,
"required": true,
"help": "Class to list"
}
}
Validate again. The command now reads:
The workflow input and command option must match by declaration key, type, required state, and repeatability. This duplication is intentional: workflows remain reusable internal functions, while commands define a stable user-facing interface.
Where to continue¶
- JSONC language reference lists every field, shape, step, binding, limit, and naming rule.
- Portable workflow recipes gives copyable patterns and
an annotated
extension explainresult. examples/hubuum-recipesis a small, compile-checked feature tour.examples/hubuum-placementis the complete dependency-free Host, Jack, Room, and move example.