// STRYKE-ARROW — ENGINEERING REPORT

Opt-in stryke connector package · cdylib libstryke_arrow.{dylib,so} (crate-type = cdylib) · dlopen'd in-process on use Arrow · JSON-over-FFI envelope

>_EXECUTIVE SUMMARY

stryke-arrow is one of the opt-in connector packages in the stryke ecosystem. Apache Arrow + Parquet + Arrow IPC + Feather + arrow-CSV + arrow-JSON for stryke. Opt-in package, kept out of the stryke core binary so the daily-driver install stays slim. The heavy arrow-rs / parquet code ships as a Rust cdylib that stryke dlopens in-process on first use Arrow.

Core stays small on purpose — most one-liner / awk-replacement work doesn't need 200 transitive crates of columnar data infrastructure. arrow-rs + parquet hit a different scale, so they ship as an opt-in package.

v0.19.0
Version
52
FFI exports
58
Arrow:: fns
cdylib
Crate type
opt-in
Tier
dlopen
Load model
JSON-over-FFI
Envelope
5
Formats

~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.

LayerImplementation
stryke wrappers (lib/*.stk)Thin .stk wrappers (Arrow, Arrow::Parquet, Arrow::IPC, Arrow::Feather, Arrow::CSV, Arrow::JSON, Arrow::DataFrame); each exposes typed helpers that serialize args to JSON and parse the response
cdylib (libstryke_arrow.{dylib,so})Single Rust cdylib crate; every public surface fn is an extern "C" fn arrow__<verb>(*const c_char) -> *mut c_char
Process modelLibrary is dlopen'd once per stryke session on first use Arrow; stateless — arrow operations are pure file transforms with no process-level cache; lives until the runtime exits
BuildCargo with [lib] crate-type = ["cdylib"]; publish = false; the package itself ships via s pkg install -g .
Install path~/.stryke/store/arrow@<version>/ after make install; use Arrow from any stryke script resolves it
Testszunit-style under t/ with live-service variants when applicable
CIGitHub Actions .github/workflows/ci.yml — cargo fmt + clippy + test, plus stryke pkg install verification

$WHY OPT-IN (NOT BUILTIN)

Core stays small on purpose — most one-liner / awk-replacement work doesn't need 200 transitive crates of columnar data infrastructure. arrow-rs + parquet hit a different scale, so they ship as an opt-in package.

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 Arrow::* wrapper serializes its args to a JSON dict and calls the matching arrow__* symbol resolved out of libstryke_arrow.{dylib,so}; the cdylib returns a JSON CString the wrapper parses. The cdylib exposes 52 arrow__* entry points (the [ffi].exports list in stryke.toml) across four roles — read (version, read, read_columnar, schema, stats), write (write), conversion (convert), and compute / aggregation / numeric transforms (filter, filter_in, filter_not_in, filter_str, select, drop, distinct, drop_nulls, keep_nulls, fill_null, sort, reverse, gather, top_k, value_counts, slice, head, tail, with_row_index, count, null_counts, shape, concat, hstack, rename, cast, sum, mean, min_max, std, median, quantile, corr, describe, aggregate, unique, clip, scale, add_const, abs, round, add_column, sample, fold_case, metadata). Each is an extern "C" fn arrow__<verb>(*const c_char) -> *mut c_char; 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)
{"path": "<file>", "format": ..., "...": ...}

# success — per-verb shape:
#   read            → {"columns": [...], "rows": [{col: val, ...}, ...]}
#   read_columnar   → {"columns": [...], "num_rows": N, "data": {col: [...]}}
#   schema          → {"fields": [{name, type, nullable}, ...]}
#   stats (parquet) → {"num_rows", "num_row_groups", "columns": [{name, null_count, min, max}, ...]}
#   write / convert → {"path": ..., "rows": N}
#   compute (filter/sort/select/…) → {"dst": ..., "rows": N}
#   count           → {"src": ..., "rows": N}

# failure
{"error": "<msg>"}        # wrapper die()s with the message

/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". The 58-function Arrow::* surface breaks down as follows:

RoleFunctions
Read & inspectread, read_stream, read_columnar, schema, stats, row_count, column_names, column_count, is_empty, null_counts, shape, metadata, count, version
Write & convertwrite, write_iter, convert
Compute (file → file)filter, filter_in, filter_not_in, filter_str, select, drop, distinct, drop_nulls, keep_nulls, fill_null, sort, reverse, gather, top_k, value_counts, head, tail, slice, sample, with_row_index, concat, hstack, rename, cast, unique, add_column, fold_case
Aggregation & numericsum, mean, min_max, std, median, quantile, corr, describe, aggregate, clip, scale, add_const, abs, round
FormatsParquet, Arrow IPC, Feather (IPC v2 alias), CSV, NDJSON — each with an explicit Arrow::<Format> sublibrary plus extension auto-detection; Arrow::DataFrame bridges into stryke's columnar value

Read the full per-signature reference in the Docs page or the README. Every function above is either an arrow__* cdylib export or a pure-stryke helper layered over one; none round-trips bulk data through the stryke process except the row-returning readers.


#PROJECT METADATA

ItemValue
Version0.19.0
LicenseMIT
Core depsarrow 58, arrow-csv/ipc/json/schema 58, parquet 58 (snap/brotli/flate2/lz4/zstd), serde, serde_json, anyhow, once_cell
AuthorMenkeTechnologies
Repositorygithub.com/MenkeTechnologies/stryke-arrow
Parent languagestrykelang
Meta umbrellaMenkeTechnologiesMeta
Issuesgithub.com/MenkeTechnologies/stryke-arrow/issues