CapDAG separates the language-neutral cartridge runtime from cartridge-level data contracts. Use CapDAG to build and host a cartridge. Add a CapDAG Cartridge SDK when you need shared LLM payloads, prompt policy, page selection, retry policy, or other shared helpers.
Choose a package
| Language | Runtime and protocol | CapDAG cartridge package |
|---|---|---|
| Rust | capdag |
capdag-cartridge-sdk |
| Go | capdag-go |
capdag-cartridge-sdk-go |
| Swift / Objective-C | capdag-objc (CapDAG and Bifaci products) |
capdag-cartridge-sdk-objc |
| Python | capdag |
Runtime and cartridge contracts in one package |
The Rust, Go, Swift/Objective-C, Python, and JavaScript CapDAG implementations share URN, definition, dispatch, and planning contracts. Cartridge runtime scaffolds are available for Rust, Go, Swift, and Python; JavaScript currently provides planner and protocol-library parity, not a cartridge scaffold.
Start with Build your first cartridge. The CapDAG reference covers runtime behavior, input and output, peer invocation, and progress and logging.
Python runtime
Install Python 3.11 or newer and the public runtime:
python3 -m pip install capdag
The generated project from capdag new NAME --python is the canonical working
example. Its central pattern is:
from capdag.bifaci.cartridge_runtime import Request, WET_KEY_REQUEST
from ops import DryContext, Op, OpMetadata, WetContext
class MyOp(Op):
async def perform(self, dry: DryContext, wet: WetContext) -> None:
request: Request = wet.get_required(WET_KEY_REQUEST)
payload = request.take_input().collect_all_bytes()
output = request.emitter()
output.start(False)
output.finish(1.0, "complete")
output.emit_cbor(payload.decode("utf-8"))
def metadata(self) -> OpMetadata:
return OpMetadata.builder("MyOp").build()
take_input() transfers ownership of the input package and may be called only
once. collect_all_bytes() is appropriate for bounded scalar input; use the
stream APIs described in the CapDAG input/output reference when data must remain
incremental. emitter() returns the response emitter. A handler that delegates
work uses request.peer() and must collect peer responses with the appropriate
progress-forwarding method when that peer emits logs.
Build the manifest with CapManifest, Cap, CapArg, CapOutput, and declared
argument sources. Every manifest includes CAP_IDENTITY; the runtime provides
its handler. Build a custom Cap URN with CapUrnBuilder, retain its canonical
.to_string(), and register the operation under that exact value:
runtime = CartridgeRuntime.with_manifest(build_manifest())
runtime.register_op_type(CAP_URN, MyOp)
runtime.run()
The runtime constructs a new registered operation for each request. Keep
request state in local variables or WetContext, not on a reusable global.
Rust product SDK
capdag-cartridge-sdk re-exports capdag and adds these modules:
| Module | Contract |
|---|---|
llm |
LLM request, stream, vocabulary, model-information types, Media URNs, Cap URNs, and backend classification. |
prompt |
Prompt-strategy classification and the shared default system prompt. |
pages |
One-based page selection with ordered, deduplicated, clamped ranges. |
net_retry |
Shared bounded retry policy for transient HTTP failures. |
structured_queries |
Structured-query definitions, rendering, registry, and result types. |
LLM request
use capdag_cartridge_sdk::llm::LlmGenerationRequest;
let request = LlmGenerationRequest::with_defaults(
"Summarize this document",
"hf:Qwen/Qwen2.5-0.5B-Instruct",
);
let json = request.to_json();
prompt and model_spec are required. Optional fields are request_type,
system_prompt, request_id, max_tokens, temperature, top_k, top_p,
min_p, seed, grammar, json_schema, constraint, chat_template,
stop_sequences, max_context_length, batch_size, rope_freq_base,
rope_freq_scale, repeat_penalty, and hf_token. A Hugging Face token is
needed for a gated repository and is forwarded to the model download.
with_defaults selects generation and sets max_tokens=512,
temperature=0.7, top_k=40, top_p=0.9, min_p=0.05, seed=42,
max_context_length=0 (automatic sizing), batch_size=2048,
rope_freq_base=10000, rope_freq_scale=1, and repeat_penalty=1.1.
ConstraintSpec supports JSON Schema, regular expressions, grammars, and tool
calls. RequestType is Generate, GetVocab, or GetInfo; an absent value is
treated as Generate.
LLM stream and metadata
The output media type is media:fmt=ndjson;llm-text-stream. Each line is an
LlmStreamMessage: Token, Status, Complete, ToolRequest, or Error.
to_line() and from_line() serialize and parse one NDJSON record.
LlmVocabResponse carries vocab and optional vocab_size.
LlmModelInfo carries required model_spec and vocab_size, plus optional
context_length, embedding_dim, file_size_bytes, head_count,
layer_count, supports_chat, and supports_tools.
The corresponding media constants are:
MEDIA_LLM_GENERATION_REQUESTMEDIA_LLM_TEXT_STREAMMEDIA_LLM_VOCAB_RESPONSEMEDIA_LLM_MODEL_INFO_RESPONSE
The SDK also exports Cap URNs for GGUF, MLX, Candle, constrained inference, vocabulary, model information, embeddings, embedding dimensions, and image description. Use the constants rather than copying their serialized values.
backend_for_model_spec selects MLX for mlx-community or ;mlx, GGUF for a
spec containing gguf, and Candle otherwise.
Shared policies
parse_index_range accepts one-based N, A-B, and A- segments separated by
commas. It preserves written order, drops later duplicates, clamps an end past
the document, and rejects zero, backward ranges, malformed segments, empty
documents, and ranges that start after the last page. Returned indices are
zero-based. An absent or empty selection returns every page.
The default network retry policy makes four total attempts, starts at 250 ms,
caps exponential backoff at 10 seconds, and honors numeric Retry-After for at
most 30 seconds. The download policy makes five attempts with a 500 ms base,
30-second backoff cap, and 60-second Retry-After cap. Retryable HTTP statuses
are 408, 425, 429, 500, 502, 503, and 504; timeouts, connection failures, DNS
failures, and request-send errors are also transient. Authentication failures,
404s, other permanent responses, and the final failed attempt are returned to
the caller unchanged.
Prompt classification chooses chat templating only for
chat-template-jinja and chat-template-short. An absent or unknown template
uses raw completion text and drops any system prompt. The backend cartridge owns
template rendering; the SDK owns the shared decision.
Go product SDK
Install the module and import llm:
go get github.com/machinefabric/capdag-cartridge-sdk-go
import "github.com/machinefabric/capdag-cartridge-sdk-go/llm"
request := llm.NewGenerationRequestWithDefaults(
"Summarize this document",
"hf:Qwen/Qwen2.5-0.5B-Instruct",
)
body := request.ToJSON()
The Go package mirrors the Rust LLM request, constraint, tool, stream,
vocabulary, model-information, media-constant, Cap-constant, and backend
classification contracts. Optional request values use pointers. Parse a stream
record with llm.FromLine; serialize one with ToLine. The Rust SDK defines
these CapDAG-specific wire types.
Swift and Objective-C product SDK
Add capdag-cartridge-sdk-objc as a Swift package and import the product you
need:
import CapDAGCartridgeSDK
import CapDAGCartridgeSDKSwift
CapDAGCartridgeSDK depends on the CapDAG and Bifaci products from
capdag-objc. CSCartridgeCaps is an ordered, secure-codable collection of
CSCap values. addCap(_:) appends a capability, caps returns the ordered
values, and capUrns() returns their URN strings. Parse those strings with
CSCapUrn; do not route them by raw string comparison.
The Swift-only product mirrors RefinedDims, PromptStrategy,
classifyPrompt, and DEFAULT_SYSTEM_PROMPT from the Rust prompt module.
URN rules
Cap and Media URNs are Tagged URNs, not ad hoc MIME strings. Quotes around direction values are part of a canonical Cap URN, and tag order is normalized. Construct and parse URNs with the CapDAG APIs. See the normative Cap URN structure and Media URNs references.