Skip to content

kreuzberg-dev/alef

Repository files navigation

Alef

Generate fully-typed, lint-clean language bindings for Rust libraries across 11 languages. Alef handles the entire pipeline -- API extraction, code generation, type stubs, package scaffolding, build orchestration, version sync, and e2e test generation -- from a single TOML config file.

Key Features

  • API extraction -- Parses your Rust crate's public API via syn into a language-agnostic intermediate representation. Handles pub use re-exports across workspace crates, #[cfg(feature)] gating, serde rename_all metadata, doc comments, Default detection, and transparent newtype resolution.
  • 11 language backends -- Each backend generates idiomatic, lint-clean binding code using the target language's native framework. See the supported languages table below.
  • Configurable DTO styles -- Choose how types are represented in each language: Python dataclass vs TypedDict vs pydantic vs msgspec, TypeScript interface vs zod, Ruby Struct vs dry-struct vs Data, and more. Input and output types can use different styles.
  • Type stubs -- Generates .pyi (Python), .rbs (Ruby), and .d.ts (TypeScript) type definition files for editor support and static analysis in consuming projects.
  • Package scaffolding -- Generates complete package manifests for each language: pyproject.toml, package.json, .gemspec, composer.json, mix.exs, go.mod, pom.xml, .csproj, DESCRIPTION (R), and Cargo.toml for binding crates.
  • E2E test generation -- Write test fixtures as JSON, get complete runnable test suites for all configured languages. Supports 40+ assertion types, field path aliases, per-language overrides, and skip conditions.
  • Adapter patterns -- Define custom FFI bridging patterns in config: sync_function, async_method, callback_bridge, streaming, and server_lifecycle. Alef generates the glue code for each backend.
  • Version sync -- Propagates the version from Cargo.toml to all package manifests, C headers, pkg-config files, and any custom file via regex text replacements.
  • Build orchestration -- Wraps maturin, napi, wasm-pack, and cargo+cbindgen with post-processing steps (e.g., patching .d.ts files for verbatimModuleSyntax compatibility).
  • Visitor FFI -- Generates a 40-method visitor callback interface via C FFI, enabling the visitor pattern in Go, Java, C#, and other FFI-based languages.
  • Caching -- blake3-based content hashing skips regeneration when source and config haven't changed. alef verify checks staleness in CI.

Supported Languages

Language Framework Package Format Test Framework DTO Styles
Python PyO3 PyPI (.whl) pytest dataclass, typed-dict, pydantic, msgspec
TypeScript/Node.js NAPI-RS npm vitest interface, zod
WebAssembly wasm-bindgen npm vitest --
Ruby Magnus RubyGems (.gem) RSpec struct, dry-struct, data
PHP ext-php-rs Composer PHPUnit readonly-class, array
Go cgo + C FFI Go modules go test struct
Java Panama FFM Maven (.jar) JUnit record
C# P/Invoke NuGet (.nupkg) xUnit record
Elixir Rustler Hex ExUnit struct, typed-struct
R extendr CRAN testthat list, r6
C cbindgen Header (.h) -- --

Quick Start

Install

# Pre-built binary (fastest)
cargo binstall alef-cli

# From crates.io
cargo install alef-cli

# Via Homebrew
brew install kreuzberg-dev/tap/alef

# From source
git clone https://github.com/kreuzberg-dev/alef.git
cd alef && cargo install --path crates/alef-cli

Initialize

cd your-rust-crate
alef init --lang python,node,ruby,go

This creates alef.toml with your crate's configuration.

Generate Bindings

alef generate              # Generate all configured languages
alef generate --lang node  # Generate for specific language
alef generate --clean      # Regenerate everything (ignore cache)

Build

alef build                 # Build all languages
alef build --lang node     # Build Node.js (runs napi build + patches .d.ts)
alef build --release       # Release profile

Test

alef test                  # Run all language tests
alef test --e2e            # Include e2e tests
alef test --lang python,go # Specific languages

Commands

Command Description
alef init Initialize alef.toml for your crate
alef extract Extract API surface from Rust source into IR JSON
alef generate Generate language bindings from IR
alef stubs Generate type stubs (.pyi, .rbs, .d.ts)
alef scaffold Generate package manifests (pyproject.toml, package.json, etc.)
alef readme Generate per-language README files
alef build Build bindings with native tools (maturin, napi, wasm-pack, etc.)
alef test Run per-language test suites
alef lint Run configured linters on generated output
alef sync-versions Sync version from Cargo.toml to all manifests
alef verify Check if bindings are up-to-date (CI mode with --exit-code)
alef diff Show what would change without writing
alef all Run full pipeline: generate + stubs + scaffold + readme + sync
alef e2e Generate e2e test projects from JSON fixtures
alef cache Manage build cache

Configuration Reference

Alef is configured via alef.toml in your project root. Run alef init to generate a starter config.

Minimal Example

[crate]
name = "my-library"
sources = ["src/lib.rs", "src/types.rs"]

languages = ["python", "node", "go", "java"]

[output]
python = "crates/my-library-py/src/"
node = "crates/my-library-node/src/"
ffi = "crates/my-library-ffi/src/"

[python]
module_name = "_my_library"

[node]
package_name = "@myorg/my-library"

[dto]
python = "dataclass"
node = "interface"

[crate] -- Source Configuration

Field Type Default Description
name string required Rust crate name
sources string[] required Rust source files to extract
version_from string "Cargo.toml" File to read version from (supports workspace Cargo.toml)
core_import string {name} with - replaced by _ Import path for the core crate in generated bindings
workspace_root string -- Workspace root for resolving pub use re-exports from sibling crates
skip_core_import bool false Skip adding use {core_import}; to generated bindings
features string[] [] Cargo features treated as always-present (#[cfg(feature)] fields are included)
path_mappings map {} Rewrite extracted Rust path prefixes (e.g., { "spikard" = "spikard_http" })

languages -- Target Languages

Top-level array of languages to generate bindings for:

languages = ["python", "node", "ruby", "php", "elixir", "wasm", "ffi", "go", "java", "csharp", "r"]

The ffi language generates the C FFI layer required by go, java, and csharp. If you enable any of those three, ffi is implicitly included.

[exclude] / [include] -- Filtering

[exclude]
types = ["InternalHelper"]
functions = ["deprecated_fn"]
methods = ["MyType.internal_method"]   # dot-notation: "TypeName.method_name"

[include]
types = ["PublicApi", "Config"]        # whitelist only these types
functions = ["extract", "parse"]       # whitelist only these functions

[output] -- Output Directories

Per-language output directories for generated Rust binding code:

[output]
python = "crates/{name}-py/src/"
node = "crates/{name}-node/src/"
ruby = "crates/{name}-rb/src/"
php = "crates/{name}-php/src/"
elixir = "crates/{name}-rustler/src/"
wasm = "crates/{name}-wasm/src/"
ffi = "crates/{name}-ffi/src/"
go = "packages/go/"
java = "packages/java/src/main/java/"
csharp = "packages/csharp/"
r = "crates/{name}-extendr/src/"

The {name} placeholder is replaced with the crate name.

Language-Specific Sections

[python]
Field Type Default Description
module_name string _{name} Python module name (the native extension name)
async_runtime string -- Async runtime spec for pyo3_async_runtimes
stubs.output string -- Output directory for .pyi stub files
features string[] inherits [crate] features Per-language Cargo feature override
[node]
Field Type Default Description
package_name string {name} npm package name
features string[] inherits [crate] features Per-language Cargo feature override
[ruby]
Field Type Default Description
gem_name string {name} with _ Ruby gem name
stubs.output string -- Output directory for .rbs type stubs
features string[] inherits [crate] features Per-language Cargo feature override
[php]
Field Type Default Description
extension_name string {name} with _ PHP extension name
feature_gate string "extension-module" Feature gate wrapping all generated code
stubs.output string -- Output directory for PHP facades/stubs
features string[] inherits [crate] features Per-language Cargo feature override
[elixir]
Field Type Default Description
app_name string {name} with _ Elixir application name
features string[] inherits [crate] features Per-language Cargo feature override
[wasm]
Field Type Default Description
exclude_functions string[] [] Functions to exclude from WASM bindings
exclude_types string[] [] Types to exclude from WASM bindings
type_overrides map {} Override types (e.g., { "DOMNode" = "JsValue" })
features string[] inherits [crate] features Per-language Cargo feature override
[ffi]
Field Type Default Description
prefix string {name} with _ C symbol prefix for all exported functions
error_style string "last_error" Error reporting convention
header_name string {prefix}.h Generated C header filename
lib_name string {prefix}_ffi Native library name (for Go/Java/C# linking)
visitor_callbacks bool false Generate visitor/callback FFI support
features string[] inherits [crate] features Per-language Cargo feature override
[go]
Field Type Default Description
module string github.com/kreuzberg-dev/{name} Go module path
package_name string derived from module path Go package name
features string[] inherits [crate] features Per-language Cargo feature override
[java]
Field Type Default Description
package string dev.kreuzberg Java package name
ffi_style string "panama" FFI binding style (Panama Foreign Function & Memory API)
features string[] inherits [crate] features Per-language Cargo feature override
[csharp]
Field Type Default Description
namespace string PascalCase of {name} C# namespace
target_framework string -- Target framework version
features string[] inherits [crate] features Per-language Cargo feature override
[r]
Field Type Default Description
package_name string {name} R package name
features string[] inherits [crate] features Per-language Cargo feature override

[dto] -- Type Generation Styles

Controls how Rust structs are represented in each language's public API:

[dto]
python = "dataclass"         # dataclass | typed-dict | pydantic | msgspec
python_output = "typed-dict"  # separate style for return types (optional)
node = "interface"           # interface | zod
ruby = "struct"              # struct | dry-struct | data
php = "readonly-class"       # readonly-class | array
elixir = "struct"            # struct | typed-struct
go = "struct"                # struct
java = "record"              # record
csharp = "record"            # record
r = "list"                   # list | r6

[scaffold] -- Package Metadata

Metadata used when generating package manifests:

[scaffold]
description = "My library for doing things"
license = "MIT"
repository = "https://github.com/org/repo"
homepage = "https://docs.example.com"
authors = ["Your Name"]
keywords = ["parsing", "extraction"]

[[adapters]] -- Custom FFI Adapters

Define custom binding patterns that alef can't extract automatically:

[[adapters]]
name = "convert"
pattern = "sync_function"
core_path = "my_crate::convert"
params = [
  { name = "input", type = "String" },
  { name = "options", type = "Options", optional = true },
]
returns = "Result"
error_type = "ConvertError"
gil_release = true    # Python: release GIL during call

Supported patterns: sync_function, async_method, callback_bridge, streaming, server_lifecycle.

[generate] / [generate_overrides.<lang>] -- Generation Control

Toggle individual generation passes (all default to true):

[generate]
bindings = true          # struct wrappers, From impls, module init
errors = true            # error type hierarchies from thiserror enums
configs = true           # config builder constructors from Default types
async_wrappers = true    # async/sync function pairs with runtime management
type_conversions = true  # recursive type marshaling helpers
package_metadata = true  # package manifests (pyproject.toml, package.json, etc.)
public_api = true        # idiomatic public API wrappers

# Override per language:
[generate_overrides.wasm]
async_wrappers = false

[sync] -- Version Synchronization

Configure the alef sync-versions command:

[sync]
extra_paths = ["packages/go/go.mod"]

[[sync.text_replacements]]
path = "crates/*/cbindgen.toml"
search = 'header = ".*"'
replace = 'header = "/* v{version} */"'

[test.<lang>] / [lint.<lang>] -- Test and Lint Commands

[test.python]
command = "pytest packages/python/tests/"
e2e = "cd e2e/python && pytest"

[test.node]
command = "npx vitest run"

[lint.python]
format = "ruff format packages/python/"
check = "ruff check packages/python/"
typecheck = "mypy packages/python/"

[e2e] -- E2E Test Generation

Configure fixture-driven test generation:

[e2e]
fixtures = "fixtures"
output = "e2e"
languages = ["python", "node", "rust", "go"]

[e2e.call]
function = "extract"
module = "my_library"
async = true
args = [
  { name = "path", field = "input.path", type = "string" },
]

[opaque_types] -- External Type Declarations

Declare types from external crates that alef can't extract:

[opaque_types]
Tree = "tree_sitter_language_pack::Tree"

These get opaque wrapper structs in all backends with handle-based FFI access.

[custom_modules] / [custom_registrations] -- Hand-Written Code

Declare hand-written modules that alef should include in mod declarations and module init:

[custom_modules]
python = ["custom_handler"]

[custom_registrations.python]
classes = ["CustomHandler"]
functions = ["custom_extract"]
init_calls = ["register_custom_types(m)?;"]

Architecture

Rust Source Files
       |
  [alef extract]
       |
  Intermediate Representation (IR)
  ApiSurface { types, functions, enums, errors }
       |
  [alef generate]
       |
  +----+----+----+----+----+----+----+----+----+----+----+
  |    |    |    |    |    |    |    |    |    |    |    |
 PyO3 NAPI WASM FFI  Magnus PHP Rustler extendr Go Java C#
  |    |    |    |
  |    |    |    +-- cbindgen --> C header
  |    |    +-- wasm-pack --> npm
  |    +-- napi build --> npm + .d.ts
  +-- maturin --> PyPI wheel + .pyi

Crate Structure

Crate Role
alef-core IR types, config schema, Backend trait
alef-extract Rust source to IR extraction via syn
alef-codegen Shared code generation (type mappers, converters, builders)
alef-adapters Adapter pattern code generators
alef-cli CLI binary with all commands
alef-docs API reference documentation generator
alef-e2e Fixture-driven e2e test generator
alef-readme Per-language README generator
alef-scaffold Package manifest generator
alef-backend-pyo3 Python backend
alef-backend-napi TypeScript/Node.js backend
alef-backend-wasm WebAssembly backend
alef-backend-ffi C FFI backend (used by Go, Java, C#)
alef-backend-magnus Ruby backend
alef-backend-php PHP backend
alef-backend-rustler Elixir backend
alef-backend-extendr R backend
alef-backend-go Go backend
alef-backend-java Java backend
alef-backend-csharp C# backend

Pre-commit Hooks

Alef ships pre-commit hooks that consumer projects can use to keep generated output up to date.

Verify mode (CI-friendly, check-only)

Fails if any generated file is stale -- does not modify files:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/kreuzberg-dev/alef
    rev: v0.3.0
    hooks:
      - id: alef-verify

Generate mode (auto-regenerate)

Regenerates all output (bindings, stubs, docs, readme, scaffold) when source files change:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/kreuzberg-dev/alef
    rev: v0.3.0
    hooks:
      - id: alef-generate

Both hooks trigger on .rs and .toml file changes. They require alef to be installed and available on PATH.

Contributing

Contributions welcome! Please open an issue or PR on GitHub.

License

MIT -- Copyright (c) 2025-2026 Kreuzberg, Inc.