An adapter is the executable boundary between DaggerML core and a backend. This page follows Codecs; Executors documents the optional contrib implementation used by the built-in adapters.
DML executable request and response contract
For a non-builtin Runnable, core locates runnable.adapter as an executable on PATH (or uses a fully specified executable path), writes one JSON request to its standard input, and reads one JSON response from standard output. Core does not import adapter plugins or know a contrib Executor abstraction at runtime. An adapter executable is therefore any CLI script that implements this stdin/stdout contract; it need not use AdapterBase.
remote is exactly {"root": str}; identifiers and scratch_uri are nonempty strings. Cleanup requires a DAG result_ref; cancel requires a node-argvargv_ref, while requested_by is a string or null. Invoke and cleanup return success, retry, or a nonempty failure code. Retry requires object adapter_state and may include nonnegative retry_after_ms; failure requires diagnostics. Cancel returns cancelled, retry, or failure. The runtime owns state persistence, result publication, lifecycle transitions, cache pointers, and cancellation coordination—an executable must not mutate them.
There is no wire poll operation. Repeated invoke requests carry saved adapter_state.
Delayed authoring and contrib adapters
funkify() creates a DelayedRunnable. When a DAG stages it, the delayed-action codec looks up its logical adapter key and calls that adapter’s resolve_runnable(uri, kwargs, sub). An adapter may construct the concrete Runnable directly. AdapterBase is a contrib semi-implementation: its default resolve_runnable() can optionally delegate to an executor; see Executors for that contrib convention.
Identity
Example
Owner
logical adapter key
local
delayed authoring and adapter registry
target URI
script
adapter or delegated executor resolution
adapter executable
dml-local-adapter
core runtime process dispatch
Contrib plugin distributions are needed where delayed work is authored and lowered. The selected adapter executable must be available to the runtime process; a Lambda adapter additionally needs its target Lambda deployed.
This minimal hook illustration constructs the Runnable directly; it is not a complete deployable backend.
from daggerml.contrib.adapters import list_adaptersassert {"local", "lambda"} <=set(list_adapters())
Contrib hooks and registration
AdapterBase supplies three hooks: resolve_runnable() optionally delegates to the contrib default described on Executors, send(**payload) performs one transport operation, and cli() exposes send() as an executable.
AdapterBase.cli() reads JSON from -i/--input and writes JSON to -o/--output; each accepts -, a local path, or an S3 URI. --poll is an ephemeral helper for a nested Docker or Batch adapter: it repeats invoke on retry, then drives nested cleanup after success. It never sends operation="poll" and cannot coordinate cancellation.
Register one class per installed entry point. The entry-point key is descriptive; lookup uses the class’s name. Discovery is lazy, retains loaded objects, warns on duplicates with the last registration winning, and raises DmlRepoError on a failed entry point without completing loading. daggerml.contrib.status.status() provides JSON-safe registrations and diagnostics.
Install plugin distributions for authoring and lowering and deploy the selected adapter executable for runtime dispatch. A Lambda transport also requires a deployed function that accepts and returns the same JSON payload.