>_EXECUTIVE SUMMARY
stryke-k8s is one of the opt-in connector packages in the stryke ecosystem. Kubernetes client for stryke. Get / apply / delete / scale / logs / watch / exec against any kubeconfig-reachable cluster (kind, k3s, minikube, EKS, GKE, AKS, OpenShift, vanilla). Opt-in package, kept out of the stryke core binary so the daily-driver install stays slim; ships as a Rust cdylib that stryke dlopens in-process on first use K8s.
Built on the kube crate (kube-client + kube-runtime). Drop-in replacement for kubectl one-liners that pipe through jq / yq / awk.
The surface splits into cluster operations (dispatched over FFI to the kube client) and pure helpers (selector/quantity/reference math computed locally, no cluster contact). Streaming-only ops (watch, logs_follow, exec) are deferred — the surface is defined but the wrappers die until the callback FFI ships.
~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 (K8s); exposes typed helpers that serialize args to JSON and parse the response |
cdylib (libstryke_k8s.{dylib,so}) | Single Rust cdylib crate; every public surface fn is an extern "C" fn k8s__<verb>(*const c_char) -> *mut c_char |
| Process model | Library is dlopen'd once per stryke session on first use K8s; a shared tokio runtime + a kube::Client cache keyed by kubeconfig context held in OnceCell; 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/k8s@<version>/ after make install; use K8s from any stryke script resolves it |
| Tests | Live round-trip under t/ (test_k8s.stk, test_stryke_k8s_surface.stk) against a kind/k3s cluster, in a per-run stryke-test-$$ namespace torn down at exit |
| CI | GitHub Actions .github/workflows/ci.yml — jobs: check, fmt (cargo fmt --all --check), clippy (-D warnings), test (ubuntu + macos), doc (cargo doc -D warnings), release-build (linux x86_64 + macos x86_64/aarch64), docs-gates, polish-gates |
+DEPENDENCIES
The cdylib links the Kubernetes client stack; core stryke links none of it. Versions are pinned in Cargo.toml.
| Crate | Version | Role |
|---|---|---|
kube | 0.95 | Kubernetes client + runtime (client, rustls-tls, config, runtime, derive) |
k8s-openapi | 0.23 | Typed Kubernetes API objects (latest feature) |
tokio | 1 | Async runtime (rt-multi-thread, macros, io-std/util, signal) |
serde / serde_json / serde_yaml | 1 / 1 / 0.9 | JSON-over-FFI envelope + YAML manifest rendering (preserve_order) |
futures-util | 0.3 | Stream combinators for async list/log paths |
anyhow / once_cell / parking_lot | 1 / 1 / 0.12 | Error plumbing + the OnceCell runtime/client caches |
either / http | 1 / 1 | Exec stream multiplexing + raw apiserver request types |
Release profile: opt-level = 3, lto = "thin", codegen-units = 1, strip = true, panic = "abort".
@PERSISTENT STATE
The v1 helper rebuilt the client (full TLS+auth handshake) on every fork. The cdylib holds two process-lifetime caches instead:
| Cell | Contents |
|---|---|
RUNTIME | One shared tokio multi-thread runtime driving every async call — no per-call runtime spin-up |
CLIENTS | kube::Client cache keyed by kubeconfig context; reuses the same client + underlying HTTP connection pool across calls |
Both are held in OnceCell for the life of the process. The first use K8s dlopens the library; subsequent calls hit the warm caches.
$WHY OPT-IN (NOT BUILTIN)
Built on the kube crate (kube-client + kube-runtime). Drop-in replacement for kubectl one-liners that pipe through jq / yq / awk.
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 K8s::* wrapper serializes its args to a JSON dict and calls the matching k8s__* symbol on the dlopen'd cdylib; the cdylib returns a JSON CString the wrapper parses. catch_unwind on every call converts panics to JSON errors. The returned CString is freed via the cdylib-exported stryke_free_cstring, wired automatically by rust_ffi::load_cdylib.
# request shape (built by the .stk wrapper)
{"verb": "<op>", "...": ...}
# response shape
{"result": ...} # success — per-fn shape
{"error": "<msg>"} # failure — wrapper die()s with the message
/SCOPE
74 public K8s::* functions. The package is intentionally narrower than the full Kubernetes API — the goal is "useful from a shell pipeline", not "complete API coverage". The surface groups into:
| Group | Functions |
|---|---|
| Read paths | get, get_one, get_yaml, exists, namespaces, nodes, api_resources, watch (deferred) |
| Write paths | apply, create, replace, patch, delete_resource, delete_collection, scale, get_scale |
| Rollouts + workload | set_image, rollout_restart, rollout_status, rollout_history, autoscale, label, annotate |
| Nodes + scheduling | cordon, uncordon, taint, untaint, evict |
| Events / metrics / wait | events, top_pods, top_nodes, wait |
| Logs + exec | logs; logs_follow + exec (deferred) |
| Connection + plumbing | version, ping, contexts, current_context, healthz, raw, pkg_version |
| Pure helpers (no cluster) | valid_name / valid_label_value / valid_label_key; parse/build selector + field_selector + resource_ref + gvk + api_version + image_ref; selector_matches, field_selector_matches; parse/format/normalize/compare/sum/sub/scale quantity; resource_ratio, pod_status, container_images, condition, age_seconds, owner_refs, diff_merge_patch, drain_filter |
Full signatures live in the Docs API reference. The README's project page carries the same authoritative scope.
!DEFERRED OPS
Streaming-only operations — watch, logs_follow, and exec — are defined on the surface but die with a clear message. They need a callback FFI shape that the current FfiSig::StrToStr JSON-in/JSON-out envelope does not model: each emits an unbounded sequence of events rather than a single response. Buffered logs (K8s::logs) ship today. The callback FFI is the gate; once it lands, these light up without surface changes.
#PROJECT METADATA
| Item | Value |
|---|---|
| License | MIT |
| Author | MenkeTechnologies |
| Repository | github.com/MenkeTechnologies/stryke-k8s |
| Parent language | strykelang |
| Meta umbrella | MenkeTechnologiesMeta |
| Issues | github.com/MenkeTechnologies/stryke-k8s/issues |