
rust-uniffi-building
Build, generate, test, package, and troubleshoot shared Rust components and cross-platform bindings with Mozilla UniFFI. Use automatically when users want to write business logic once in Rust and call or reuse it from Swift, iOS, macOS, Kotlin, Android, JVM, Python, Ruby, JavaScript, browsers, desktop apps, or multiple platforms—even when they do not mention UniFFI; when they ask to bridge, expose, connect, or share Rust with Swift/Kotlin/Android/iOS; or when they need procedural-macro versus UDL selection, records, enums, errors, objects, traits, callbacks, custom types, uniffi.toml, uniffi-bindgen, async exports, generated-binding diagnostics, native-library loading, packaging, ABI, or upgrades. Verify that the locked UniFFI release supports each requested target; route hand-written C ABI work to rust-unsafe-ffi.
- Installs
- 89
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/full-stack-skills/rust-skills --skill rust-uniffi-building- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads rust-uniffi-building automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Rust UniFFI Building
Build a narrow, versioned foreign-language API around a shared Rust library. Recognize requests such as “write the core once in Rust for Swift and Android,” “call Rust from Kotlin and iOS,” or “reuse Rust business logic across mobile and browser clients” as UniFFI evaluation/building tasks even if the user does not name UniFFI. Treat generated bindings, the compiled native library, and host-language packaging as one contract: a successful Rust build alone does not prove that Kotlin, Swift, Python, Ruby, JavaScript, or WASM consumers work.
Scope and Routing
Use this skill for Mozilla UniFFI interface design, scaffolding, binding generation, language integration, lifecycle behavior, and end-to-end validation.
Route these adjacent tasks deliberately:
- Hand-written
extern "C", raw pointers, allocator ownership, or manual headers →rust-unsafe-ffi. - General procedural-macro implementation or diagnostics →
rust-macros. - Workspace manifests, build scripts, features, cross-compilation, and artifact profiles →
rust-cargo-build. - Rust task supervision and runtime architecture beyond exported async calls →
rust-concurrency. - General test strategy, coverage, or fuzz infrastructure →
rust-testing.
Workflow
1. Pin the actual contract
Before editing, record:
rustc --version --verbose, target triples, MSRV, and host platforms;- locked
uniffi, backend, and language-tooling versions plus enabled features; - intended languages and minimum Kotlin/JVM, Android, Swift, Xcode, Python, Ruby, or WASM versions;
- library artifact type, package name, namespace/module name, and loading path;
- exported functions, objects, records, enums, errors, traits, callbacks, async calls, and custom types;
- threading, cancellation, ownership, destruction, and backward-compatibility expectations;
- generation owner: Cargo build, a checked-in tool, Gradle/Xcode task, CI job, or release pipeline.
Inspect Cargo.lock and the current official UniFFI guide. Do not copy syntax from a different UniFFI release line. The repository's golden example is evidence for its locked version, not a timeless dependency recommendation.
2. Choose one interface-definition strategy
| Strategy | Prefer when | Required discipline |
|---|---|---|
| Procedural macros | Rust is the API source of truth and supported constructs cover the contract | Use library mode and uniffi::setup_scaffolding!() exactly once |
| UDL | An explicit language-neutral schema is desired or existing UDL must remain authoritative | Generate in build.rs and include the generated scaffolding |
| Mixed UDL + macros | Migration or a real unsupported construct requires both | Keep UDL valid alone; make crate name match the UDL namespace |
Never call both uniffi::setup_scaffolding!() and uniffi::include_scaffolding!() in one crate. Do not mix strategies merely for convenience; it increases duplicate-definition and drift risk.
Read Interface Model before designing public types or choosing UDL versus macros.
3. Establish scaffolding and artifact boundaries
For a procedural-macro-only crate, start with the smallest viable pattern:
uniffi::setup_scaffolding!();
#[derive(uniffi::Record)]
pub struct Greeting {
pub message: String,
}
#[uniffi::export]
pub fn greet(name: String) -> Greeting {
Greeting {
message: format!("Hello, {name}!"),
}
}
Build an ordinary Rust library for Rust callers and the platform artifacts required by hosts:
[lib]
crate-type = ["lib", "cdylib", "staticlib"]
Do not enable every crate type or UniFFI feature automatically. Select artifacts from the host packaging contract, isolate bindgen/CLI dependencies when practical, and keep runtime-facing dependencies minimal.
For UDL build scripts, generated bindings, configuration precedence, and library-mode commands, read Scaffolding and Generation.
4. Design an FFI-shaped public API
- Export only UniFFI-supported types or explicit custom/external conversions.
- Prefer records for immutable value transfer and objects for identity or shared state.
- Return
Arc<Self>from exported object constructors when required by the selected UniFFI version. - Model expected failures as exported error enums; never encode routine failures as panics.
- Keep internal Rust types private and convert at the UniFFI boundary.
- Treat names, field presence, enum variants, defaults, and error variants as host-language compatibility commitments.
- Bound strings, byte buffers, collections, recursive structures, callback frequency, and response sizes.
- Avoid exposing a Rust-centric API that becomes awkward or unsafe in every target language.
Read Async, Lifetimes, and Callbacks before exporting futures, callbacks, traits, or stateful objects.
5. Generate and integrate per language
Generate bindings from the exact library/configuration combination that will ship. Keep generated sources and native artifacts version-aligned.
Validate language-specific integration rather than stopping at generated files:
- Kotlin/Android: package/JNA or platform bridge, Gradle task inputs, ABI splits, coroutine behavior, and native library loading;
- Swift/Apple: Swift sources, headers/module maps, static or dynamic library linkage, module naming, Xcode build phases, and XCFramework packaging;
- Python: extension/library discovery, generated module import, supported Python versions, and wheel/platform tagging;
- Ruby: generated wrapper loading and the feature gaps documented for the selected release;
- WASM: unstable support constraints, single-thread assumptions, JavaScript tooling, and supported UniFFI features.
Read Language Bindings only for the requested target languages.
6. Verify at three boundaries
Run the Rust gates first:
cargo fmt --all --check
cargo check --workspace --all-targets --all-features
cargo test --workspace --all-targets --all-features
cargo clippy --workspace --all-targets --all-features -- -D warnings
Then verify:
- Generation boundary — bindings regenerate deterministically from a clean checkout and fail clearly on metadata, namespace, configuration, or library mismatches.
- Host-language boundary — compile and run real Kotlin, Swift, Python, Ruby, or WASM tests against the produced native artifact.
- Distribution boundary — install the package into a minimal consumer project and exercise loading, calls, errors, callbacks, async cancellation, and cleanup on supported platforms.
Rust tests, generated-source snapshots, and host compilation are different evidence levels. Do not claim a platform works without executing it.
Read Testing, Packaging, and Upgrades before release, CI design, or version migration.
7. Diagnose from the correct layer
Classify failures before changing code:
| Symptom | Inspect first |
|---|---|
| Missing exported symbol or metadata | scaffolding macro/include mode, crate features, final library artifact |
| Duplicate symbols or definitions | mixed UDL/macros, duplicate scaffolding setup, multiple generated sources |
| Bindgen cannot find crate/config | cargo-metadata, global [crate-roots], working directory, config precedence |
| Generated code compiles but library will not load | filename, architecture, ABI, search path, signing, package contents |
| Values corrupt or fail to decode | type model, custom converter, version skew, lowering/lifting contract |
| Object disappears, leaks, or races | reference counting, host lifetime, callback registration, thread policy |
| Async hangs or cancellation leaks work | runtime feature, foreign executor/poller, cancellation and completion contract |
| Only release builds fail | dead stripping, LTO, symbol retention, feature/profile differences |
Read Internals and Diagnostics only when surface-level checks cannot explain the failure.
Gotchas
- UniFFI generates bindings; it does not ship, sign, publish, or load the native library for every platform.
- Generated bindings and the Rust artifact must come from compatible UniFFI metadata and configuration.
latestdocumentation can move. Pin crate versions and record the guide snapshot used for a release decision.- A UDL file remains a complete schema even when macros add supported items.
- Put
#[cfg]on separate exported impl blocks when needed; conditional items inside an exported block can still generate incompatible scaffolding. - Host-language naming, exceptions, nullability, collections, and lifecycle semantics are not identical to Rust semantics.
- Miri cannot validate the real foreign runtime. Use it for Rust-side unsafe code, then run platform integration tests.
When Not to Use
Do not activate this skill for:
- ordinary Rust library APIs with no foreign-language consumer;
wasm-bindgen, CXX, PyO3, JNI, cbindgen, Diplomat, or raw C bindings unless the task explicitly adopts or compares UniFFI;- writing a general derive or attribute macro unrelated to UniFFI;
- packaging an already-generated binding when no UniFFI contract, code, or artifact changes are involved.
Completion Criteria
- Pin versions, targets, languages, generation owner, and artifact/package contract.
- Choose procedural macros, UDL, or a justified mixed strategy without duplicate scaffolding.
- Keep the exported type, error, ownership, callback, async, and compatibility model explicit.
- Generate bindings from the exact shipping library and configuration.
- Run Rust gates plus real host-language and minimal-consumer tests for every claimed platform.
- Verify packaging, architecture, loading, symbol retention, cancellation, and cleanup.
- Record unsupported platforms, unexecuted tests, and version-sensitive assumptions.
Resources
- Interface Model
- Scaffolding and Generation
- Language Bindings
- Async, Lifetimes, and Callbacks
- Testing, Packaging, and Upgrades
- Internals and Diagnostics
- Official Documentation Map
- Execution Scenarios
examples/golden-uniffi/: a compiled procedural-macro library with records, enums, objects, tests, and a version-locked local bindgen CLI.
Data Privacy
Do not upload proprietary UDL, generated bindings, native libraries, symbols, crash dumps, or host application logs to external services without authorization.
FAQ
What does the rust-uniffi-building skill do?
Build, generate, test, package, and troubleshoot shared Rust components and cross-platform bindings with Mozilla UniFFI. Use automatically when users want to write business logic once in Rust and call or reuse it from Swift, iOS, macOS, Kotlin, Android, JVM, Python, Ruby, JavaScript, browsers, desktop apps, or multiple platforms—even when they do not mention UniFFI; when they ask to bridge, expose, connect, or share Rust with Swift/Kotlin/Android/iOS; or when they need procedural-macro versus UDL selection, records, enums, errors, objects, traits, callbacks, custom types, uniffi.toml, uniffi-bindgen, async exports, generated-binding diagnostics, native-library loading, packaging, ABI, or upgrades. Verify that the locked UniFFI release supports each requested target; route hand-written C ABI work to rust-unsafe-ffi.
How do I install rust-uniffi-building?
Run npx skills add https://github.com/full-stack-skills/rust-skills --skill rust-uniffi-building in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/rust-uniffi-building/ (personal) or .claude/skills/rust-uniffi-building/ (project).
Which AI agents can use rust-uniffi-building?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is rust-uniffi-building safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains rust-uniffi-building?
It is published by full-stack-skills in full-stack-skills/rust-skills. It has 89 recorded installs.
More from full-stack-skills/rust-skills
rust-testing
full-stack-skills/rust-skills
Design, implement, and validate Rust tests, including unit, integration, doctest, compile-fail, property, fuzz, benchmark, coverage, async, concurrency, process, daemon, IPC, terminal, platform, and hardware-facing test strategies. Use when users ask for Rust test architecture, flaky-test diagnosis, coverage gates, benchmarks, trybuild, cargo-nextest, real-process tests, or failure-path verification.
rust-style-clippy
full-stack-skills/rust-skills
Apply and diagnose Rust style, rustfmt, Clippy, compiler diagnostics, Edition migrations, lint policy, idiomatic control flow, error handling, allocation behavior, production Rust conventions, and the Rust API Guidelines ↔ Clippy lint mapping. Use when users ask to format or lint Rust, fix warning or error codes, migrate editions, review unwrap or clone usage, improve idioms, map a C- API guideline rule to the enforcing Clippy lint, or establish CI quality gates. Route API shape decisions (naming conventions, type/trait design, module layout, full C- guideline review) to the rust-api-design skill.
rust-concurrency
full-stack-skills/rust-skills
Design, implement, diagnose, and test Rust concurrency and parallelism with threads, Send and Sync, locks, atomics, channels, Tokio, Rayon, Crossbeam, bounded backpressure, actor ownership, task supervision, graceful shutdown, runtime diagnostics, and Loom model tests. Use when users ask about shared state, deadlocks, async tasks, CPU parallelism, high concurrency, daemon resource budgets, slow consumers, worker pools, lock-free structures, or concurrent correctness.
rust-performance
full-stack-skills/rust-skills
Measure, profile, optimize, and regression-test Rust performance across latency, throughput, CPU, allocations, memory, binary size, and compile time using representative workloads, Criterion, iai-callgrind, cargo-flamegraph, samply, DHAT, heap or pprof tools, cargo-bloat, cargo-llvm-lines, and build timings. Use when users report slow Rust code, high memory or CPU, large binaries, noisy benchmarks, tail-latency regressions, or need performance budgets and evidence-backed optimization.
rust-code-review
full-stack-skills/rust-skills
Review Rust changes for correctness, memory and thread safety, error semantics, unnecessary allocation or cloning, lock scope, API compatibility, test gaps, documentation, and dependency risk, applying the Rust API Guidelines checklist (C-PANIC, C-UNWRAP, C-TRANSMUTE, C-BOOL, C-NEWTYPE, C-COMMON-TRAITS, C-CONVERT, C-SEALED, C-NON-EXHAUSTIVE). Use when reviewing Rust diffs, pull requests, libraries, unsafe boundaries, or production incidents; report actionable findings by severity before summaries, route automated formatting or lint policy to rust-style-clippy, and route API shape decisions (trait sealing, error taxonomy, newtype design, builder patterns) to rust-api-design.
rust-cargo-build
full-stack-skills/rust-skills
Configure, operate, diagnose, and automate Cargo for Rust packages and workspaces. Cover manifests and targets, commands, dependency resolution and features, profiles, build scripts, configuration and environment variables, caches and build diagnostics, cross-compilation, registries, packaging, publishing, metadata, CI reproducibility, and stable-versus-nightly feature gates. Use for Cargo.toml, Cargo.lock, .cargo/config.toml, cargo build/check/run/tree/metadata/package/publish, resolver or feature problems, build output and performance, private registries, and beginner Cargo workflows. Route crate selection and supply-chain audits to rust-dependencies, workspace topology to rust-workspace, test design to rust-testing, documentation design to rust-documentation, lint policy to rust-style-clippy, and API compatibility decisions to rust-semver.
Popular backend & apis skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
entra-app-registration
microsoft/azure-skills
Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.
google-agents-cli-adk-code
google/agents-cli
This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).
embedded-captions
heygen-com/hyperframes
Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.
entra-agent-id
microsoft/azure-skills
Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).
neon
neondatabase/agent-skills
Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.