In this section

capdag is both the reference implementation of this specification and a command-line product: a Unix-style tool that runs a single cap, runs a whole .machine graph, inspects the fabric, and scaffolds and develops cartridges. Every mode drives a real Bifaci host with the bundled cartridges registered, so a cap’s peer calls (model downloads, fabric lookups) work exactly as they do inside the engine.

Fabric binding

Every capdag invocation resolves caps, media, and aliases against one fabric registry. A shipped binary bakes that registry’s URL at build time (CDG_FABRIC_REGISTRY_URL); a runtime environment variable of the same name overrides the baked value. The schema base (CDG_SCHEMA_BASE_URL) is only ever paired with the fabric URL, never split. This is what makes a --staging build resolve disbind-pdf against the staging fabric rather than production.

Commands

capdag <cap-alias-or-urn> [cap args] [inputs...] [options]   Run one cap
capdag run <machine-file> [inputs...] [options]              Run a .machine file
capdag plan <files...> [--to <t>]... [options]               Discover targets / plan machines for a file set
capdag dag-viz <machine-file> [--mermaid|--dot]              Render the execution plan
capdag find <cap-alias-or-urn>                               Show the providing cartridge(s)
capdag resolve [--no-cache] <cap-alias-or-urn>...            Print cap definition JSON (array for >1)
capdag cache [clear|refresh]                                 Invalidate/renew the local fabric cache
capdag install <cap-alias-or-urn-or-cartridge-id>            Download + verify without running
capdag new <name> --<language> [-o <dir>]                    Scaffold a new cartridge project
capdag dev-install <project-dir>                             Install/update a dev cartridge under the dev slug
capdag self update                                           Replace this capdag with its channel's latest release

capdag <cap> …: run one cap (single-cap mode)

The default mode: a bare cap alias or URN is run as a Unix-style tool, driving the cap’s own declared interface.

  • Piped stdin, or input file path(s), feed the cap’s stdin arg.
  • The cap’s declared --flags and positional args are accepted natively.
  • --arg <name-or-media-urn>=<value> addresses any arg explicitly, by the name its definition gives it or by its media URN (repeatable; @<path> reads a file’s bytes for a binary arg). A name the cap does not declare is refused with the names it does.

Cap interface presentation. capdag <cap> --help prints that cap’s declared interface, structured by argument role rather than as a flat arg list:

  • Input: the cap’s MAIN input: the arg whose declared stdin source URN is the cap URN’s in= spec (identified by tagged-URN equivalence, never string comparison; see Input and output §”Argument roles”). Shown first: this is how the cap is fed: piped stdin, or positional input file path(s). Any additional flag/position routes the arg declares are listed alongside.
  • Required options: the non-main args that are required with no default_value. Every invocation must supply each of these; a missing one fails the pre-flight with an error that names the option’s flag (or positional slot, or --arg form), its media URN, and its description, grouped under “missing required options”. Defaulted options are never demanded or mentioned in that error.
  • Options: the remaining args, listed with their default values (or marked optional when defaultless).
  • Output (pipe discipline): a single scalar result streams RAW to stdout; sequences and fan-outs write files ({input}.{node}[.{i}].{ext}) and list their paths on stdout. Logs and progress go to stderr.

Abstract caps (the dispatch umbrellas convert-image, convert-audio, disbind, extract-frames and extract-audio-track) are narrowed here: capdag resolves the alias to the abstract cap, detects the input media, and narrows to the concrete cap via is_dispatchable (see Dispatch §”Abstract caps”). An ambiguous target is resolved with --to <ext|media-urn>; an unresolvable one fails hard.

Local dev fallback. If the token names a cap the fabric does not define, capdag falls back to a locally dev-installed cartridge’s own manifest (run by its alias) and runs that cap through the full host, provided the cap does not conflict with the fabric (no alias of it already means a different cap upstream). This is what lets a brand-new cap be developed and run before it is ever published. See Build and run a cartridge.

capdag run <machine-file> …

Run a .machine data-flow graph. Maps, gathers, fan-out and included machines are planned and executed by the shared orchestrator. Flags are recognized in any position: run m.machine input --force and run --force m.machine input are equivalent.

Inputs. A machine’s inputs are its input anchors (Machine notation).

  • --input <node>=<value> supplies the input the notation calls <node>: @<path> reads a file, anything else is the value itself (--input window=20). Given several times for one node, the values are a sequence. A name the machine does not have is refused with the names it does.
  • A positional path, or a live-source token, goes to the input its detected media conforms to most closely, among the inputs --input did not name. When it conforms to several equally the run is refused, naming them. An input given several paths takes them as one sequence.
  • A machine with exactly one input, given several paths and nothing else, is run once per path.
  • Every input must be given something; a machine that starts from a source (() -> step -> ..., or a step given only constants) takes none.

Outputs. A machine’s outputs are its output anchors. One output holding one value goes to stdout. Anything else is written as files in the output directory, one per item, named {input_stem}.{output}[.{index}].{ext}: {output} is the name the notation gives the output node, and each path written is printed to stdout. An output that was not produced, because the branch that makes it did not fire, writes nothing and is named on stderr. A machine that ends in a sink (... -> step -> ()) has no output.

Included machines. A machine header’s reference (Machine notation) is read as a path relative to the file that wrote it.

Everything else is in the file. A machine run from the command line is self-contained: every arg of every step is bound in the notation (to a node or a constant), or has a default. A required arg that is neither is a pre-flight error naming the step and the arg, and how to say it: a constant in the wiring, or a node supplied with --input.

How a run ends.

Exit Meaning
0 Completed: every output was produced, or was reported as not produced by a branch that did not fire.
1 Failed: the machine is not valid or cannot run as written, or a step failed and its policy did not tolerate it. No output is written, and nothing the run had persisted is left in the output directory.
2 Usage error: the invocation is incomplete or names something the machine does not have (an input given nothing, an unknown --input name, an unknown flag). Nothing ran.
3 Completed with tolerated failures: outputs were written; stderr lists each step that failed under on_error=absent, with its class, code and message.
130 Cancelled by the user.

A step that was skipped is named on stderr with the values it was waiting for, by the names the machine gives them.

Ctrl-C on a live run. The first Ctrl-C is the tap-off (15.2 §Runs stop): every live input is stopped and the CLI prints the verdict it was given: Input stopped: N host tap(s) closed, M feed request(s) stopped, M ended; the run is draining to complete outputs., or the refusal (Stop input refused: no live input is open on this run, or a feed that did not end within the drain timeout, named). The run then drains and emits its outputs. A second Ctrl-C, at any point (including while the first stop is still waiting for its evidence), aborts with a Cancel attributed to the user (exit 130). The same two controls apply to single-cap mode with a live source.

capdag plan <files...> [--to <t>]... [options]

The unified configurable planner over a file set (the same PlanEngine/LiveCapFab the engine’s wizards drive). Before anything else, plan warms the fabric caches from the pinned manifest (the warm the engine performs at startup; cap fetches are atomic with their referenced media defs, which is what populates the extension index) and detects each input with the engine’s content-discriminated detection: extension candidates → baseline structural pick → static validation discrimination against a bounded content prefix. Detection is deterministic; an input whose extension the fabric does not know is a hard error naming the extension, never a silent bare media:.

  • Discovery (no --to): lists every reachable target for the set (convergent targets tagged with their apex), with step estimates.
  • --to <t>: t resolves as: registered media alias first (a bare token; alias names never contain :), else a media URN (contains :), else the file-extension shorthand (png → media:ext=png). The result is matched against the REACHABLE targets:
    • equivalent to a reachable node → plans to it directly;
    • more general, exactly one conforming node → narrows to it (stderr notes the resolution) and plans;
    • more general, several conforming nodes → there is no way to know which path the user wants, so every candidate machine is printed as runnable machine notation (grouped under # target: <urn> headers) and the command exits 0; the user chooses by saving the notation they want and capdag run-ning it;
    • nothing conforms → hard error (exit 1) pointing back at discovery.
  • Choosing: candidates are ranked and printed with their notation. --pick <rank> selects one; there is no default pick: --save / --run with several candidates and no explicit --pick refuse (exit 1) rather than silently act on candidate 0.
  • Knobs: --converge auto|combine|independent, --where auto|earliest|latest|source|target|depth=N, --mechanism any|generalize|collect|merge, --rank intent|shortest|cost, --depth, --max-paths, --max; any explicit knob switches the request to Configured mode.

capdag dag-viz <machine-file> [--mermaid|--dot]

Render the machine’s full execution plan (MachinePlan) as a diagram: steps, their other outputs, maps with their items, gathers, inputs and outputs, and typed edges. Included machines are drawn as the steps they are. --mermaid (default) emits Mermaid; --dot emits Graphviz DOT.

capdag find <cap-alias-or-urn>

Resolve a cap and print which registry cartridge(s) provide it (and whether a signed binary is available for this platform), without downloading anything.

capdag resolve [--no-cache] <cap-alias-or-urn>...

Print the cap’s canonical definition JSON, resolved through the baked fabric registry, the same definition every mirror uses. Cartridges use this to (re)generate the cap-def snapshots they embed. Passing several tokens prints a JSON array of cap defs (one process, one manifest read); cartridge snapshot generation resolves a whole cap-aliases.txt in a single batched call this way. --no-cache forces a fresh fetch, bypassing the version-keyed on-disk cache (which a mutable staging channel can leave stale).

capdag cache [clear|refresh]

Manage the version-keyed local fabric cache. clear purges it (in-memory and on-disk, manifest included); refresh (the default) purges and then re-fetches the manifest so the next command starts renewed. Use it after a channel re-publishes under the same manifest version.

capdag install <cap-alias-or-urn-or-cartridge-id>

Resolve, download, and verify a cartridge (signature chain + hashes) without executing anything, as a cache warm-up. Prints the installed binary path.

capdag new <name> --<language> [-o <dir>]

Scaffold a fresh cartridge project into <dir>/<name>/ (default <dir> is the current directory). Choose exactly one of --python, --rust, --go, or --swift; there is no default language. Each option renders the same starter capability contract through that language’s runtime and writes its build and development instructions. <name> must be a path-safe, lowercase slug ([a-z0-9] with -/_ separators). See Build and run a cartridge.

capdag dev-install <project-dir>

Install or update a dev cartridge under the per-user cartridge root’s reserved dev slug, so the host discovers it. capdag reads the project’s manifest (by running its entry’s manifest subcommand), verifies that none of its caps conflict with the fabric, then stages it at ~/.capdag/cartridges/dev/v{CARTRIDGE_REGISTRY_VERSION}/{channel}/{name}/{version}/ with a cartridge.json install record (registry_url: null). Re-running overwrites the same version directory; this is the update step of the edit/reinstall loop. <project-dir> defaults to ..

capdag self update

Replace this capdag — the executable and the bundled-cartridges/ beside it — with the latest release of the channel it was published on. Prints capdag <old> -> <new>, or capdag <version> is the latest release when there is nothing newer.

It reads the release manifest of the registry this capdag was published in, and installs a release only when all of this holds:

  • the manifest’s signature chains to the root keys built into this capdag: a certificate for the release key, signed by two of those roots, for this build’s signing environment and valid now, and the manifest signed by that release key;
  • the bundle has the size and the SHA-256 digest the manifest lists;
  • the executable in the bundle runs and reports the version it was published as.

Otherwise nothing is installed, the reason is printed, and the exit status is 1. The new bundle takes the place of the old one where the old one is: the cartridges first, then the executable. An update that is interrupted leaves a bundle that runs, and the next capdag self update puts back or clears what it left (in .capdag-update/, beside the executable). On Windows the running executable cannot be removed: it is left beside the new one as capdag.exe.old, and the next update removes it.

Two kinds of capdag are not updated this way, and say what updates them:

Installed with Update with
Homebrew brew upgrade machinefabric/tap/capdag
apt sudo apt update && sudo apt install --only-upgrade capdag
dnf sudo dnf upgrade capdag
Built from source build the newer source

A package manager’s capdag is recognized by the file installed-by its package puts beside the executable. A bundle installed where you cannot write is updated with the same rights that installed it. self is a subcommand, so a cap alias named self is run by its URN.

Global options

Option Applies to Meaning
-o, --output <dir> run, single-cap, new Output directory (run modes) / project parent (new)
--force run modes Overwrite existing output files
--arg <name>=<value> single-cap Explicit cap argument, by name or media URN (repeatable)
--input <node>=<value> run A machine input by the name the notation gives it (repeatable)
--to <ext|media-urn> single-cap Target output for narrowing an abstract cap
--dev-bins <binary>… run modes Host local cartridge binaries directly
--trace <file.trace> run modes Write a per-segment Bifaci protocol trace (JSONL)
--fabric <url> any Resolve this invocation against a different fabric registry origin (flag > env CDG_FABRIC_REGISTRY_URL > baked). Stripped from argv before dispatch, so it works in front of any subcommand. Repeating it with two different origins is an error. The shared-fabric assertion extends automatically: a cartridge registry declaring a different fabric is rejected.
--help, -h any Show usage; after a cap name, that cap’s interface (input / required options / options)

The per-user cartridge root

capdag hosts cartridges from ~/.capdag/cartridges/, using the same registry-, version-, and channel-partitioned tree every host uses: {registry_slug}/v{CARTRIDGE_REGISTRY_VERSION}/{channel}/{name}/{version}/. The dev slug is reserved for locally built cartridges (registry_url: null); see Cartridge anatomy for discovery and the slug/version layout.