In this section

What a capability is

When you right-click a file and the Transmute menu shows what the file can become, each entry is reachable through one or more capabilities: typed operations a cartridge can perform on a typed input to produce a typed output.

A capability is a contract, not a button in MachineFabric’s code. It specifies:

  • What it accepts: an input media URN (for example media:document;ext=pdf, media:audio;ext=wav, media:fmt=json;llm-generation-request;record).
  • What it produces: an output media URN (for example media:enc=utf-8;page, media:fmt=ndjson;llm-text-stream).
  • How it is named: a Cap URN of the form cap:in="media:X";<tags>;out="media:Y" that identifies the operation precisely enough for the planner to route to it.
  • What arguments it takes: optional parameters extracted from stdin, CLI positions, or flags.

CapDAG, the open protocol MachineFabric is built on, defines how capabilities are named, matched, and routed. This page covers what capabilities mean inside MachineFabric: what the Transmute menu shows, what the standard capabilities are, and what cartridges declare. For protocol-level details:

How the Transmute menu reaches a capability

Before the menu opens, FabricLoom does the following:

  1. It reads the file’s media type. A PDF becomes media:document;ext=pdf, a WAV becomes media:audio;ext=wav, and so on.
  2. The planner walks the capability graph. Every cap that accepts that input directly, plus every cap reachable through one or more chained cartridges, contributes a possible destination.
  3. The menu shows destinations, not steps, such as “render to image,” “transcribe,” and “summarize.” You pick the destination and the planner picks the route.
  4. The route is shown before it runs. For multi-step pipelines the graph appears so you can see the route before any data moves.
  5. Cartridges are invoked in order. Each one runs in the platform cartridge host (the macOS XPC service or the Linux/Windows host daemon), with progress streamed back live and results stored in your library.

When the same destination is reachable by more than one route, ranking picks the most specific match. A PDF-specific extractor beats a generic document extractor, and an LLM cap that names a specific model beats a generic one.

Standard capabilities

CapDAG ships a small set of standard caps that every cartridge can rely on. CAP_IDENTITY is mandatory, and the rest are common operations the registry has helpers for.

Mandatory

Cap URN Purpose
cap:effect=none (CAP_IDENTITY) Pass input through unchanged. Every cartridge must declare it. The runtime auto-registers a handler, so you only include it in the manifest.

Standard (optional)

Cap Purpose
CAP_DISCARD Accept any input, produce media:void. Default implementation provided.
CAP_ADAPTER_SELECTION Inspect content and return the media URNs that describe it. Used for file-type detection.

LLM, embeddings, models

The cartridge SDK exposes URN constants and builders for the LLM, embeddings, and model-management caps that MachineFabric routes through routinely:

  • LLM inference: CAP_LLM_INFERENCE_GGUF, CAP_LLM_INFERENCE_MLX, CAP_LLM_INFERENCE_CANDLE, CAP_LLM_INFERENCE_CONSTRAINED
  • LLM introspection: CAP_LLM_VOCAB, CAP_LLM_MODEL_INFO
  • Embeddings: CAP_GENERATE_EMBEDDINGS, CAP_EMBEDDINGS_DIMENSIONS
  • Vision: CAP_DESCRIBE_IMAGE
  • Models: download, list, status, contents, availability, path (URN builders in the standard library)

The associated payload media URNs:

Media URN Carries
media:fmt=json;llm-generation-request;record An LlmGenerationRequest: prompt, model spec, sampling params, optional constraints
media:fmt=ndjson;llm-text-stream An LlmStreamMessage stream: tokens, status, completion, tool requests, errors
media:fmt=json;llm-vocab-response;record An LlmVocabResponse
media:fmt=json;llm-model-info;record An LlmModelInfo

The full request, stream, vocab, and info shapes are in the Cartridge SDK reference. The dispatch rule that routes a generation request to the right backend (GGUF, MLX, or Candle) follows the same ranking logic as every other request: the request’s model_spec plus tags determines the candidate.

Document and content caps

Standard URN builders in the CapDAG library cover the common document operations:

  • disbind_urn(input_media): decompose a document into pages with text content
  • render_page_image_urn(input_media): render document pages as images
  • coercion_urn(source_type, target_type): generic format coercion
  • format_conversion_urn(in_media, out_media): JSON / YAML / CSV interconversion
  • generate_json_urn(lang_code), make_decision_urn(lang_code), make_multiple_decisions_urn(lang_code): structured-output LLM caps

For everything else (custom extraction, sentiment tagging, OCR, transliteration), cartridges define their own caps. The URN must parse (per CapDAG URN syntax), and the input and output media URNs it references must either exist in the registry or be proposed alongside the cartridge (Contributing).

# Examples of valid custom caps
cap:in="media:enc=utf-8;sentiment-input";out="media:sentiment-tag;enc=utf-8";tag-sentiment
cap:in="media:ext=png;image";analyze;target=faces;out="media:fmt=json;record"
cap:in="media:audio;ext=wav;speech";ml-model;out="media:enc=utf-8;record;transcription";transcribe

What a cartridge declares

Cartridges declare their capabilities in a CapManifest returned at startup. The host reads the manifest at install time to register the cartridge with the router.

The minimal Python shape is below. The Build your first cartridge tutorial builds this cartridge from the scaffold.

from capdag.bifaci.manifest import CapManifest, default_group
from capdag.cap.definition import Cap, CapArg, CapOutput, PositionSource, StdinSource
from capdag.standard.caps import CAP_IDENTITY
from capdag.urn.cap_urn import CapUrn, CapUrnBuilder

def build_manifest() -> CapManifest:
    tag_sentiment = Cap(
        urn=(
            CapUrnBuilder()
            .marker("tag-sentiment")
            .in_spec("media:enc=utf-8;sentiment-input")
            .out_spec("media:sentiment-tag;enc=utf-8")
            .build()
        ),
        title="Tag sentiment",
        aliases=["tag-sentiment"],
    )
    tag_sentiment.args = [
        CapArg(
            media_urn="media:enc=utf-8;sentiment-input",
            required=True,
            sources=[
                StdinSource("media:enc=utf-8;sentiment-input"),
                PositionSource(0),
            ],
            arg_description="UTF-8 text to classify.",
        )
    ]
    tag_sentiment.output = CapOutput(
        media_urn="media:sentiment-tag;enc=utf-8",
        output_description="One of 'positive', 'neutral', 'negative'.",
    )

    identity = Cap(
        urn=CapUrn.from_string(CAP_IDENTITY),
        title="Identity",
        aliases=["identity"],
    )

    return CapManifest(
        name="sentiment-tagger",
        version="0.1.0",
        channel="nightly",
        registry_url=None,
        description="Classify text as positive, neutral, or negative.",
        cap_groups=[default_group([identity, tag_sentiment])],
    )

The host enforces these rules:

  • CAP_IDENTITY is mandatory. Every cartridge’s manifest must list it. The Python runtime auto-registers a handler, so you only declare the cap.
  • channel and registry_url are fixed at build time. They must agree with the engine’s compile-time configuration and with the on-disk install record (cartridge.json). A mismatch is rejected at discovery time.
  • cap_groups are atomic registration units. A group succeeds or fails as a whole, which keeps related caps consistent.

Construct a Cap URN with the builder API (CapUrnBuilder().marker().in_spec().out_spec().build()) and not as a hand-written string. The runtime canonicalizes tags alphabetically, so a hand-written URN string will almost certainly not match the canonical form. See the Build your first cartridge tutorial for the pattern of building the URN once and keeping the resulting string.

Routing in practice

When MachineFabric needs a capability:

  1. It builds a request, which is a Cap URN describing what is needed.
  2. The router runs the dispatch predicate against every registered candidate and collects the eligible ones.
  3. Among eligible candidates, ranking picks the most specific.
  4. The selected cartridge is spawned if it is not already running, the request is sent over the Bifaci protocol (CapDAG’s binary frame protocol between host and cartridge), and the response is streamed back.
  5. For multi-step requests, the planner finds the path through the capability graph and the executor runs each step in order, in parallel where the graph allows.

If two candidates match with equal specificity, the first registered wins. A specialized cartridge for a specific file type therefore reliably overrides a more general one for that type, while the general cartridge remains available for everything else.