>_EXECUTIVE SUMMARY
stryke-docker is one of the opt-in connector packages in the stryke ecosystem. Docker client for stryke. Containers, images, networks, volumes, logs, exec, prune against any reachable Docker daemon (Docker Desktop, Linux daemon, Podman with the docker-API socket, remote DOCKER_HOST). The heavy bollard / tokio code ships as a Rust cdylib that stryke dlopens in-process on first use Docker.
bollard + tokio for full daemon-API coverage — opt-in so the stryke core binary stays under 40 MB.
~ARCHITECTURE
In-process cdylib design: the stryke side is a thin .stk wrapper that calls FFI symbols on the dlopen'd library. No subprocess, no pipe — calls return on the same thread that made them.
| Layer | Implementation |
|---|---|
stryke wrappers (lib/*.stk) | Thin .stk wrapper (Docker) exposing typed helpers across containers, images, networks, volumes, logs, exec, and prune; each serializes args to JSON and parses the response |
cdylib (libstryke_docker.{dylib,so}) | Single Rust cdylib crate; every public surface fn is an extern "C" fn docker__<verb>(*const c_char) -> *mut c_char |
| Process model | Library is dlopen'd once per stryke session on first use Docker; a shared tokio runtime + a bollard::Docker client cache keyed by DOCKER_HOST held in OnceCell reuse the same client + HTTP pool across calls; lives until the runtime exits |
| Build | Cargo with [lib] crate-type = ["cdylib"]; publish = false; the package itself ships via s pkg install -g . |
| Install path | ~/.stryke/store/docker@<version>/ after make install; use Docker from any stryke script resolves it |
| Tests | zunit-style under t/ with live-service variants when applicable |
| CI | GitHub Actions .github/workflows/ci.yml — cargo fmt + clippy + test, plus stryke pkg install verification |
$WHY OPT-IN (NOT BUILTIN)
bollard + tokio for full daemon-API coverage — opt-in so the stryke core binary stays under 40 MB.
The trade-off is intentional. The core stryke binary stays under ~40 MB precisely because each connector ships separately. Daily-driver work (one-liners, awk replacement, data scripting) doesn't need MongoDB drivers, AWS SDKs, or Spark Connect bindings linked in.
&FFI ENVELOPE
JSON in / JSON out across the FFI boundary. Each Docker::* wrapper serializes its args to a JSON dict and calls the matching docker__* symbol resolved out of libstryke_docker.{dylib,so}; the cdylib returns a JSON CString the wrapper parses. Dispatch is by symbol name — there is no verb field in the payload; the wrapper sends the call-specific keys (container, image, tail, …) plus an optional host connection override. The exports cover containers (including network attach/detach, TTY resize, exec inspect), images (including search + registry inspect), networks, volumes, exec, logs, and prune, plus the daemon-free parse/validate/build helpers; the authoritative list is [ffi].exports in stryke.toml (78 exported symbols). The returned CString is freed via the cdylib-exported stryke_free_cstring, wired automatically by stryke's cdylib loader.
# request shape (built by the .stk wrapper; dispatched by symbol name)
docker__stop({"container": "web", "timeout": 5})
# success — the per-fn result object, returned as-is (NOT wrapped in {"result": ...})
{"ok": true}
# failure — wrapper _decode() die()s with the message
{"error": "<msg>"}
A handler panic is caught (catch_unwind) and returned as the same {"error": "…"} shape, so a bad call cannot abort the host process. Null or malformed arguments decode to Value::Null rather than segfaulting — both paths are pinned by the crate's FFI safety tests.
+PERSISTENT STATE
Two process-lifetime singletons replace the v1 fork-per-call helper:
| Singleton | Role |
|---|---|
RUNTIME | One shared tokio multi-thread runtime drives every async daemon call; the blocking FFI entrypoints block_on against it. |
CLIENTS | bollard::Docker cache keyed by DOCKER_HOST (socket path / tcp url). The same client + underlying HTTP connection pool is reused across calls instead of reconnecting per operation. |
=SCOPE: DAEMON OPS vs PURE HELPERS
The surface splits cleanly. Daemon ops need a reachable socket and die on daemon errors. The pure helpers — the parse_* / valid_* / build_* / normalize_* / format_* family for Docker's CLI spec grammars (image refs, ports, mounts, env, labels, devices, tmpfs, restart policies, platforms, memory, durations, cpus, signals, ulimits) — touch no socket, are deterministic, and are what cargo test exercises without a live daemon.
| Capability | Status in 0.19.0 |
|---|---|
Snapshot ops (ps, inspect, logs, exec, lifecycle, stats --no-stream, prune) | shipped |
| Pure parse/validate/build helpers | shipped |
Streaming (logs_follow, events) | deferred — needs a callback FFI shape |
Registry-auth / tar (push, build) | deferred — needs auth / tar-stream design |
TLS client certs (DOCKER_CERT_PATH / DOCKER_TLS_VERIFY) | roadmap |
Calling a deferred op raises a die naming the op and the missing substrate — scripts fail loudly rather than returning partial data.
/SCOPE
See the README's "Why this is a package" + "API reference" sections for the authoritative scope. The package is intentionally narrower than its underlying SDK / driver — the goal is "useful from a shell pipeline", not "complete API coverage".
#PROJECT METADATA
| Item | Value |
|---|---|
| Version | 0.19.0 (stryke.toml / Cargo.toml; publish = false) |
| FFI exports | 78 docker__* symbols ([ffi].exports in stryke.toml) |
| License | MIT |
| Author | MenkeTechnologies |
| Repository | github.com/MenkeTechnologies/stryke-docker |
| Parent language | strykelang |
| Meta umbrella | MenkeTechnologiesMeta |
| Issues | github.com/MenkeTechnologies/stryke-docker/issues |