# Binding Architecture

> Architecture rules for the polyglot binding layer and the C FFI boundary — crate naming, distribution paths, ownership and null-safety invariants, error-context propagation, and async patterns. Load when designing or editing language bindings, the C ABI, cbindgen headers, or FFI type/error conversions.

- Skill: `kreuzberg-dev/binding-architecture` (Agent Skill)
- Install (CLI): `npx skillmds@latest add kreuzberg-dev/binding-architecture`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kreuzberg-dev/binding-architecture/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: kreuzberg-dev (https://skillmd.com/u/kreuzberg-dev)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kreuzberg-dev/binding-architecture

---


# Binding Architecture

## Bindings

- Bindings are minimal glue: call Rust core, convert types, convert errors — no business logic
- Canonical surface: Rust core API first, C FFI ABI second, language bindings third;
  integrations/adapters sit outside bindings
- Crate naming: {lib}-py (PyO3), {lib}-node (NAPI-RS), {lib}-rb (Magnus), {lib}-php (ext-php-rs),
  {lib}-wasm (wasm-bindgen), {lib}-ffi (C FFI), {lib}-jni (JNI)
- Distribution paths: packages/python/ (PyPI), typescript/ (npm), ruby/ (RubyGems), php/ (Composer),
  go/ (Go module), java/ (Maven), csharp/ (NuGet), dart/ (pub.dev), swift/ (SwiftPM),
  kotlin-android/ (Maven/Gradle), r/ (CRAN/GitHub), zig/ (Zig package)
- Each binding has its own language-native test suite — 80%+ coverage
- Generated e2e code lives under e2e/{language}/ and is not hand-edited
- Error conversion must preserve context (message + numeric code) at every FFI boundary
- Async: pyo3_asyncio (Python), native #[napi] async (TS), Fiber (Ruby), block on Tokio via FFI only at
  sync host boundaries

## FFI and language interop

- Every pointer has one owner, documented with SAFETY comments
- Opaque handles only — never expose Rust types directly, use #[repr(transparent)] wrappers
- Null safety: check ALL pointers before use, return null + error code on failure
- Allocate/free pairs: every \_new() has a matching \_free(), caller owns \*mut
- Every unsafe block has a SAFETY comment: what invariant, why it holds, what breaks if violated
- Generate C headers with cbindgen — CI verifies generated headers match committed
- C ABI is the stable native contract for Go, Java/JNI, C#, Dart, Swift, Kotlin Android, Zig, and R wrappers
- Semantic versioning for C headers, struct layouts frozen at MAJOR.MINOR boundaries
- All exported functions use #[no_mangle] extern "C"
- Rust Result\<T, E> → host exceptions via dedicated conversion functions at every boundary
- Preserve error context across boundaries: message, numeric code (1000+), source location, cause chain

