TheDan64/inkwell
It's a New Kind of Wrapper for Exposing LLVM (Safely)
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit today
- ✓40+ active contributors
- ✓Distributed ownership (top contributor 14% of recent commits)
Show all 6 evidence items →Show less
- ✓Apache-2.0 licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/thedan64/inkwell)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/thedan64/inkwell on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: TheDan64/inkwell
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/TheDan64/inkwell shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit today
- 40+ active contributors
- Distributed ownership (top contributor 14% of recent commits)
- Apache-2.0 licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live TheDan64/inkwell
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/TheDan64/inkwell.
What it runs against: a local clone of TheDan64/inkwell — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in TheDan64/inkwell | Confirms the artifact applies here, not a fork |
| 2 | License is still Apache-2.0 | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 30 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of TheDan64/inkwell. If you don't
# have one yet, run these first:
#
# git clone https://github.com/TheDan64/inkwell.git
# cd inkwell
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of TheDan64/inkwell and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "TheDan64/inkwell(\\.git)?\\b" \\
&& ok "origin remote is TheDan64/inkwell" \\
|| miss "origin remote is not TheDan64/inkwell (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is Apache-2.0" \\
|| miss "license drift — was Apache-2.0 at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "src/lib.rs" \\
&& ok "src/lib.rs" \\
|| miss "missing critical file: src/lib.rs"
test -f "src/context.rs" \\
&& ok "src/context.rs" \\
|| miss "missing critical file: src/context.rs"
test -f "src/module.rs" \\
&& ok "src/module.rs" \\
|| miss "missing critical file: src/module.rs"
test -f "src/builder.rs" \\
&& ok "src/builder.rs" \\
|| miss "missing critical file: src/builder.rs"
test -f "src/types/mod.rs" \\
&& ok "src/types/mod.rs" \\
|| miss "missing critical file: src/types/mod.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 30 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~0d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/TheDan64/inkwell"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Inkwell is a memory-safe Rust wrapper around LLVM (the Low-Level Virtual Machine) that lets you build compilers and JIT interpreters without touching unsafe C code directly. It provides strongly-typed bindings to LLVM 11–22 that catch type errors at compile-time rather than runtime, making it possible to safely generate, optimize, and execute machine code from Rust. Single crate with modular organization: src/ contains core abstractions (context.rs, module.rs, builder.rs, execution_engine.rs) that mirror LLVM's API structure; src/types/ (int_type.rs, fn_type.rs, array_type.rs) provides strongly-typed wrappers; src/support/ handles cross-platform error handling; internal_macros/ is a separate proc-macro crate for generating version-aware code. Examples in examples/ (jit.rs, kaleidoscope/) show real usage patterns. Build.rs manages LLVM library discovery.
👥Who it's for
Language designers and compiler engineers who want to implement their own programming languages or runtime systems in Rust without wrestling with raw LLVM C bindings. Developers building JIT compilers, optimization frameworks, or code generation tools who value type safety and Rust's memory guarantees.
🌱Maturity & risk
Pre-1.0 but actively maintained and production-capable. The codebase has 1.34M lines of Rust, comprehensive CI via GitHub Actions (test.yml workflow), codecov integration, and supports 12 concurrent LLVM versions (11–22). Minimum Rust requirement is 1.85+. The project has clear governance (CONTRIBUTING.md, CODE_OF_CONDUCT.md) and documented examples like the Kaleidoscope tutorial, though the maintainer notes breaking changes may occur before v1.0.
Single primary maintainer (TheDan64) creates sustainability risk. The project explicitly maintains compatibility with 12 LLVM versions simultaneously (llvm11-0 through llvm22-1), which increases testing surface area and maintenance burden—cfg macros in internal_macros/src handle version-specific code. LLVM itself is a complex, fast-moving dependency, and users must select exactly one feature flag or builds will fail. No visible issue backlog or recent commit dates in the provided data, so momentum is unclear.
Active areas of work
The repo tracks against LLVM's active releases: the Cargo.toml shows recent additions of llvm20-1, llvm21-1, and llvm22-1 features, indicating ongoing tracking of LLVM's major versions. Internal_macros/src/cfg.rs and enum.rs suggest active work on macro infrastructure to reduce boilerplate across versions. The Dependabot.yml indicates automated dependency updates are enabled.
🚀Get running
git clone https://github.com/TheDan64/inkwell.git
cd inkwell
rustup update # Ensure Rust 1.85+
cargo build --features llvm22-1 # Build against LLVM 22
cargo test --features llvm22-1 # Run tests
cargo run --example jit --features llvm22-1 # Run JIT example
Daily commands:
cargo build --features llvm22-1
cargo test --features llvm22-1
cargo doc --features llvm22-1 --open # View generated docs
cargo run --example jit --features llvm22-1
cargo run --example kaleidoscope --features llvm22-1
🗺️Map of the codebase
src/lib.rs— Entry point and public API surface—defines the core Context, Module, and builder abstractions that all users interact with.src/context.rs— Manages LLVM Context lifecycle and thread safety; every other major component depends on having a valid context.src/module.rs— Wraps LLVM Module; central container for functions, globals, and IR generation—used in nearly all compilation workflows.src/builder.rs— IRBuilder abstraction for generating LLVM IR instructions; most IR-generation code flows through this module.src/types/mod.rs— Type system abstraction layer; defines the trait-based type safety model that differentiates Inkwell from raw llvm-sys.src/values/mod.rs— Value system mirroring LLVM's value hierarchy; coupled tightly with types to enforce compile-time safety.internal_macros/src/lib.rs— Procedural macros for reducing boilerplate across type and value enums; breaking changes here ripple across the entire codebase.
🛠️How to make changes
Add a new type wrapper (e.g., CustomType)
- Create new file
src/types/custom_type.rswith a struct wrappingLLVMTypeRefand implementAnyTypetrait fromsrc/types/mod.rs. (src/types/custom_type.rs) - Add the new type to the
AnyTypeEnumenum insrc/types/enums.rsand implement conversion methods. (src/types/enums.rs) - Export the type from
src/types/mod.rsand add tosrc/lib.rspublic exports. (src/types/mod.rs) - Add feature-gated variant in
internal_macros/src/cfg.rsif type availability differs across LLVM versions. (internal_macros/src/cfg.rs) - Write comprehensive tests in
tests/all/test_types.rscovering construction, operations, and edge cases. (tests/all/test_types.rs)
Add a new instruction builder method (e.g., build_custom_op)
- Add method to
impl Builder<'ctx>insrc/builder.rs, calling the underlyingllvm_sysfunction and wrapping result in an appropriate value type. (src/builder.rs) - If the instruction returns a new value type, ensure the result is wrapped in the corresponding type from
src/values/mod.rs. (src/values/mod.rs) - Add tests in
tests/all/test_builder.rsortests/all/test_instruction_values.rsto verify the instruction is generated correctly. (tests/all/test_builder.rs) - Update documentation with examples of expected IR output and parameter constraints. (
src/builder.rs)
Support a new LLVM version (e.g., LLVM 17)
- Add feature flag
llvm17-0toCargo.tomlfollowing the pattern of existing versions and update internal_macros FEATURE_VERSIONS. (Cargo.toml) - Update
internal_macros/src/cfg.rsto add conditional compilation logic for version-specific APIs. (internal_macros/src/cfg.rs) - Wrap any new or deprecated LLVM APIs with
#[cfg(feature = "llvm17-0")]guards in affected modules (e.g.,src/builder.rs,src/context.rs). (src/builder.rs) - Run full test suite with
cargo test --features llvm17-0and update CI in.github/workflows/test.ymlif needed. (.github/workflows/test.yml)
Add a new optimization pass integration
- Add pass struct and methods to
src/passes.rswrapping the correspondingllvm_sys::transformsfunction. (src/passes.rs) - Ensure the pass can be applied to modules and/or functions via
PassManagerandFunctionPassManageras appropriate. (src/passes.rs) - Write integration tests in
tests/all/test_passes.rsortests/all/test_passes_on_function.rsverifying the pass correctly transforms IR. (tests/all/test_passes.rs)
🪤Traps & gotchas
- Feature flag is mandatory: You must select exactly one llvm*-* feature in Cargo.toml; omitting it or selecting multiple will cause build errors because llvm-sys versions conflict. 2. Lifetime binding is strict: All types (Value, IntType, etc.) are generic over &'ctx, and the borrow checker enforces that you cannot use them after the Context is dropped; this is intentional for safety but requires careful lifetime management. 3. LLVM installation required: build.rs expects LLVM headers and libraries on the system; if missing, build will fail with cryptic linker errors—install LLVM (matching your feature flag version) or set LLVM_SYS_*_PREFIX env var. 4. Edition is 2024: The Cargo.toml specifies edition = "2024", which is the upcoming Rust edition; ensure your rustc is recent enough (1.85+). 5. Typed pointers vs opaque: llvm11-0 through llvm14-0 auto-enable typed-pointers feature (older LLVM behavior); llvm15+ default to opaque pointers, affecting type representation in generated IR.
🏗️Architecture
💡Concepts to learn
- LLVM Intermediate Representation (IR) — Inkwell's entire type system and builder API are designed to safely emit LLVM IR; you must understand IR's structure (values, instructions, basic blocks) to use Inkwell effectively.
- Lifetime-bound generics and phantom data — Inkwell uses Rust's lifetime system ('ctx) to prevent use-after-free when the underlying LLVM Context is destroyed; this is the core safety mechanism.
- Just-In-Time (JIT) compilation — The execution_engine.rs module enables compiling IR to machine code at runtime without writing to disk; essential for REPLs, dynamic compilation, and interactive environments.
- Strong typing in code generation — Inkwell replicates LLVM IR's type system in Rust (IntType vs FloatType are distinct types), preventing accidental type mismatches that the C API would silently allow; this is Inkwell's core value proposition.
- Builder pattern for IR emission — The Builder<'ctx> type accumulates instructions at a specific insertion point in a basic block, mirroring LLVM's IRBuilder; understanding how append_* methods maintain insertion state is key to generating correct IR.
- Procedural macros for multi-version support — Inkwell's internal_macros crate (cfg.rs, enum.rs) uses proc-macros to generate version-aware code; this pattern is unusual and worth understanding if you modify or extend LLVM version support.
- Basic blocks and control flow graphs — IR code is organized into basic blocks (sequential instruction runs with a single entry/exit); builder.rs and basic_block.rs expose this structure for branching and control flow.
🔗Related repos
llvm/llvm-project— The upstream LLVM project itself; Inkwell wraps this via llvm-sys, so understanding LLVM's IR semantics and API is essential.tari/llvm-sys— The low-level unsafe FFI bindings that Inkwell wraps; if you hit a limitation in Inkwell, this is the layer below that provides raw LLVM access.gluon-lang/gluon— A statically-typed functional language compiler that uses Inkwell for code generation, showing a real-world production use case.bytecodealliance/wasmtime— WebAssembly runtime that uses LLVM for JIT compilation; relevant if building a language that targets Wasm or needs similar code generation patterns.rust-lang/rust— The Rust compiler itself uses LLVM as its code generation backend; understanding Rust's own rustc architecture informs how to structure a language using Inkwell.
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive unit tests for src/types/traits.rs and src/values/traits.rs
The traits modules are foundational abstractions for the type and value systems in Inkwell, but there are no dedicated test files visible in the repository structure. Given that this is a safety-critical FFI wrapper around LLVM, comprehensive trait tests would ensure that type conversions, implementations, and bounds checking work correctly across different LLVM versions (11-22). This would catch regressions early and provide examples for contributors.
- [ ] Create src/types/traits_test.rs with tests for BasicType, FloatMathType, and other core traits
- [ ] Create src/values/traits_test.rs with tests for BasicValue, AggregateValue, and related traits
- [ ] Test trait implementations across multiple LLVM versions using feature gates (llvm11-0, llvm15-0, llvm22-1)
- [ ] Add trait downcasting and type checking edge cases
- [ ] Document test patterns in a comment block for future contributors
Add integration tests for LLVM version compatibility in .github/workflows/
The Cargo.toml shows support for 12 LLVM versions (11.0 through 22.1) but the test.yml workflow is not shown in detail. Inkwell should have explicit CI tests that verify each supported LLVM version compiles and passes tests. This prevents subtle version-specific regressions and makes version support claims testable. A matrix-based GitHub Actions workflow would efficiently test all versions.
- [ ] Expand .github/workflows/test.yml with a Cargo matrix strategy testing features: llvm11-0, llvm15-0, llvm18-1, llvm22-1 (representative versions)
- [ ] Add a job that tests the no-llvm-linking variants for at least one LLVM version
- [ ] Add a job testing the typed-pointers feature with llvm14-0 (last version requiring it)
- [ ] Document in the workflow why these specific versions were chosen
- [ ] Test that examples/jit.rs and examples/kaleidoscope run successfully
Add missing documentation comments and examples to src/values/mod.rs and src/types/mod.rs module exports
These are the primary entry points for the public API (exporting array_value, float_value, int_value, etc., and array_type, float_type, int_type, etc.). The exported items appear to lack documentation comments and examples in the module-level docs. This makes it harder for new users to understand the type/value hierarchy. Adding comprehensive module-level documentation with examples would improve discoverability and reduce the learning curve.
- [ ] Add doc comments to src/types/mod.rs explaining the type hierarchy (BasicType → IntType, FloatType, etc.) with a diagram in docs
- [ ] Add doc comments to src/values/mod.rs explaining the value hierarchy and common patterns
- [ ] Add at least 2 runnable examples per module using /// example blocks (e.g., creating an i32 type, constructing an array type)
- [ ] Reference src/types/traits.rs and src/values/traits.rs from module docs to guide users to trait implementations
- [ ] Cross-reference these docs from README.md's getting-started section
🌿Good first issues
- Add integration tests for src/comdat.rs: The file exists but no corresponding test coverage is visible; writing tests for COMDAT (Common Object Model Data) section support would exercise the builder and module APIs and help maintain reliability across LLVM versions.
- Expand src/debug_info.rs documentation with examples: The debug_info.rs module exists but has minimal visibility in the examples/; adding a small example showing how to generate dwarf debug info (like the jit.rs or kaleidoscope examples) would help users emit debuggable code.
- Add version-specific feature tests in internal_macros: The internal_macros crate generates version-aware code but has minimal test coverage (only src/cfg.rs and src/enum.rs); adding proc-macro tests that verify cfg! and enum! macros expand correctly for each LLVM version would prevent subtle breakages as new versions are added.
⭐Top contributors
Click to expand
Top contributors
- @TheDan64 — 14 commits
- @ErisianArchitect — 12 commits
- @my4ng — 12 commits
- @marxin — 7 commits
- @airwoodix — 7 commits
📝Recent commits
Click to expand
Recent commits
5756ac0— Swaps raw pointer types with NonNull for better safety and niches (#687) (ErisianArchitect)ad3eecc— Fixes bug in write_bitcode_to_file in #6. (#685) (ErisianArchitect)317feaf— Fixes get_current_debug_location error. (#683) (ErisianArchitect)6c76540— Inkwell 0.9.0 + Internals 0.14.0 (TheDan64)4f4d09a— fix missing LinkIn* calls (#681) (foxidokun)832a448— Fix docs.rs build (#673) (AdamGS)adf6094— Feature/llvm run passes on function (#671) (GoncaloBranquinho)07fa9f2— Deprecate legacy PassManager in favor of PassBuilderOptions and run_passes (#670) (GoncaloBranquinho)7f5895f— chore: replace once_cell with std LazyLock/LazyCell (#669) (DaniPopes)159cddd— chore: bump llvm-sys-221 dependency version (#668) (marxin)
🔒Security observations
The Inkwell codebase shows a well-structured Rust FFI wrapper project with generally good security practices. However, there are critical configuration issues (invalid edition), incomplete dependency definitions, and inherent risks from wrapping unsafe C libraries. The project would benefit from fixing the Cargo.toml edition field, completing feature configurations, enforcing minimum Rust versions, and maintaining rigorous testing of FFI boundaries. No obvious hardcoded secrets, injection vulnerabilities, or Docker-related issues were identified in the provided files.
- High · Invalid Rust Edition in Cargo.toml —
Cargo.toml. The Cargo.toml specifies edition = "2024", which does not exist. Valid Rust editions are 2015, 2018, and 2021. This will cause build failures and indicates a configuration error that could affect dependency resolution and security tooling. Fix: Change edition to "2021" (or "2018" if supporting older Rust versions). This is blocking and must be corrected before the package can compile. - Medium · Incomplete Cargo.toml Feature Configuration —
Cargo.toml (llvm20-1-no-llvm-linking feature). The Cargo.toml file appears truncated with an incomplete feature definition: 'llvm20-1-no-llvm-linking = ' is cut off without a value. This suggests either a malformed configuration file or incomplete documentation provided. Fix: Complete all feature definitions following the pattern used for other versions, e.g., 'llvm20-1-no-llvm-linking = ["llvm20-1", "llvm-sys-201/no-llvm-linking"]'. - Medium · Unsafe FFI Wrapper Without Clear Safety Boundaries —
src/lib.rs and all FFI-related modules. Inkwell is a wrapper around llvm-sys, which is a raw FFI binding to LLVM. While the project aims for safety, wrapping unsafe C bindings requires careful attention to null pointer checks, bounds verification, and proper cleanup of LLVM resources. The safety guarantees depend on correct usage of the underlying LLVM library. Fix: Ensure comprehensive documentation of unsafe invariants, maintain strict code review for unsafe blocks, consider adding static analysis tools (miri, clippy) to CI/CD, and add extensive tests for FFI boundary conditions. - Low · Minimum Rust Version Constraint Clarity —
Cargo.toml (missing rust-version field). The README specifies 'Minimum rustc 1.85+', but the Cargo.toml does not include a 'rust-version' field to enforce this constraint. This could lead to users attempting compilation with incompatible Rust versions. Fix: Add 'rust-version = "1.85"' to the Cargo.toml [package] section to enforce the minimum version requirement. - Low · Multiple LLVM Versions and Feature Complexity —
Cargo.toml (features section). The project supports 12 different LLVM versions with optional no-llvm-linking features, creating a large feature matrix. This complexity increases the risk of version-specific bugs or security issues not being caught across all supported versions. Fix: Consider regular testing across all feature combinations in CI/CD, maintain clear documentation of feature interactions, and consider deprecating very old LLVM versions to reduce maintenance burden.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.