Skill Store 33

Alef Generated Bindings

Alef-managed generated bindings in packages/* and binding crates — the regeneration workflow (tas…

by xberg-io · MIT

The skill

Alef-managed generated bindings in packages/* and binding crates — the regeneration workflow (task alef:generate / alef:verify), the alef.toml section layout, the core-side edits that break a regen, and the FFI bridge's JSON marshalling requirement. Load before editing anything under packages/* or a binding crate, before adding a trait method or extractor, or when regenerating or verifying Alef output.

Alef-Generated Bindings

Files under packages/*/ and in the binding crates are generated by Alef — do not hand-edit.

Workflow

  1. Check alef.toml before touching anything in packages/*/ or a binding crate
  2. Modify the Rust source or alef.toml itself
  3. task alef:generate → alef all --clean. This formats via poly as part of the run; there is no task alef:format
  4. task alef:verify → alef verify --exit-code
  5. task e2e:generate then task e2e:test (or task e2e:all) to verify behaviour
  6. Commit Rust source + alef.toml + regenerated output atomically

The alef:* namespace is exactly: generate, verify, build, sync, docs, verify:readme-paths, verify:ffi-formats. Formatting is poly fmt / poly lint.

Freshness check

task alef:verify. A hand-rolled git diff over packages/ is under-scoped — generated output also lands in crates/xberg-py/, crates/xberg-php/, crates/xberg-jni/, crates/xberg-node/, crates/xberg-wasm/, crates/xberg-ffi/, packages/dart/rust/, packages/swift/rust/, and e2e/.

Alef tracks both sides under .alef/: sources_hash.cache (input hashes over the parsed Rust sources) and .alef/hashes/xberg.<lang>.output_hashes (per-file output content hashes). Neither makes a generated file safe to hand-fix — a regen restores it. Fix alef.toml or the Rust source, then regenerate and re-verify.

Key alef.toml sections

  • [workspace], [workspace.sync] (version-sync extra_paths), [workspace.docs], [workspace.poly], [workspace.generate]
  • [[crates]] — the Rust source crate parsed for type/function extraction, plus [[crates.source_crates]]
  • [crates.<lang>] — one table per binding: python, node, ruby, php, elixir, wasm, ffi, go, java, dart, kotlin_android, jni, swift, csharp, zig (each carrying exclude_functions, target_dep_overrides, stubs, …)
  • [crates.e2e] — e2e generation (output = "e2e", [crates.e2e.call.overrides.<lang>])
  • [crates.readme] — README generation (template_dir = "templates/readme", [crates.readme.languages.<lang>])
  • [crates.exclude], [crates.output], [crates.custom_modules], [crates.publish]

There are no [crate], [languages.*], [e2e] or [readme] top-level tables, and alef.toml declares no rename mappings — the generated Go trait type is DocumentExtractor, unchanged.

Canonical e2e tasks: task e2e:generate, e2e:build, e2e:test, e2e:all, plus e2e:verify, e2e:lint, e2e:quick, e2e:lang. Do not add legacy aliases.

Core-side edits that break a regen

  • New extractor struct — needs #[cfg_attr(alef, alef(skip))] on the struct declaration, not the impl block. Without it the regen aborts globally and nothing regenerates, leaving the tree silently stale. Check this first when a regen dies. (36 of the 42 modules in crates/xberg/src/extractors/ carry the attribute.)
  • Binding-facing types must not be #[non_exhaustive] — alef generates impl From<Mirror> for xberg::TheType with a struct literal in ~10 binding crates, and #[non_exhaustive] forbids that (E0639). Derive Default for forward-compat instead. Keep #[non_exhaustive] only on types listed in [crates.exclude].
  • A new enum variant on a binding-facing type breaks exhaustive matches across the generated binding crates.

Trait return types crossing the generated FFI bridge

The generated XbergOcrBackendBridge in crates/xberg-ffi/src/lib.rs marshals every trait method's return value through JSON (218 serde_json::from_str::<xberg::…> call sites today) and falls back to Default::default() on an uninitialised vtable slot, a failing host callback, or a null result. Whether a variant carries a payload is irrelevant.

Adding a method to a trait with a generated bridge means its return type needs Default + Serialize + Deserialize. Unit-only enums included.

crates/xberg-ffi is built by no ci-rust.yaml leg — only publish-path jobs — so cargo check --workspace cannot fail on it. Verify with the scoped cargo check -p xberg-ffi. That check rewrites crates/xberg-ffi/include/xberg.h and packages/go/include/xberg.h to match whatever feature set you invoked it with, which is usually not the committed one. Revert that churn rather than committing it.

Which alef answered

task alef:generate shells out to the globally installed ~/.cargo/bin/alef, not a cargo run against a sibling checkout. A source fix there has zero effect until cargo install --path . --force. Generator fixes ship in order: land upstream → release alef → bump the pinned version → regen. Regenerating against a locally modified alef produces a tree the pinned version cannot reproduce.

Use this skill

Connect your agent to the Skill Store MCP server and ask for it by ref: xberg-io/alef-generated-bindings-18365249546.

Download SKILL.md · Markdown version

Details

Publisher
xberg-io
Category
Software Development › Developer docs & tooling
License
MIT
Updated
2026-10-19

References

More from xberg-io