RepoPilotOpen in app →

pybind/pybind11

Seamless operability between C++11 and Python

Healthy

Healthy across the board

worst of 4 axes
Use as dependencyConcerns

non-standard license (Other)

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 5d ago
  • 32+ active contributors
  • Distributed ownership (top contributor 28% of recent commits)
Show 4 more →
  • Other licensed
  • CI configured
  • Tests present
  • Non-standard license (Other) — review terms
What would change the summary?
  • Use as dependency ConcernsMixed if: clarify license terms

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.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/pybind/pybind11)](https://repopilot.app/r/pybind/pybind11)

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/pybind/pybind11 on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: pybind/pybind11

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:

  1. 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.
  2. 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.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/pybind/pybind11 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 5d ago
  • 32+ active contributors
  • Distributed ownership (top contributor 28% of recent commits)
  • Other licensed
  • CI configured
  • Tests present
  • ⚠ Non-standard license (Other) — review terms

<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 pybind/pybind11 repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/pybind/pybind11.

What it runs against: a local clone of pybind/pybind11 — 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 pybind/pybind11 | Confirms the artifact applies here, not a fork | | 2 | License is still Other | 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 ≤ 35 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>pybind/pybind11</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of pybind/pybind11. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/pybind/pybind11.git
#   cd pybind11
#
# 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 pybind/pybind11 and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "pybind/pybind11(\\.git)?\\b" \\
  && ok "origin remote is pybind/pybind11" \\
  || miss "origin remote is not pybind/pybind11 (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
  && ok "license is Other" \\
  || miss "license drift — was Other 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 "include/pybind11/attr.h" \\
  && ok "include/pybind11/attr.h" \\
  || miss "missing critical file: include/pybind11/attr.h"
test -f "include/pybind11/cast.h" \\
  && ok "include/pybind11/cast.h" \\
  || miss "missing critical file: include/pybind11/cast.h"
test -f "include/pybind11/detail/class.h" \\
  && ok "include/pybind11/detail/class.h" \\
  || miss "missing critical file: include/pybind11/detail/class.h"
test -f "include/pybind11/common.h" \\
  && ok "include/pybind11/common.h" \\
  || miss "missing critical file: include/pybind11/common.h"
test -f "include/pybind11/detail/type_caster_base.h" \\
  && ok "include/pybind11/detail/type_caster_base.h" \\
  || miss "missing critical file: include/pybind11/detail/type_caster_base.h"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 35 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~5d)"
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/pybind/pybind11"
  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).

</details>

TL;DR

pybind11 is a lightweight, header-only C++ library that creates seamless Python bindings for C++11 code without requiring Boost. It uses compile-time introspection and template metaprogramming to automatically infer type information, allowing developers to expose C++ functions, classes, operators, and STL containers to Python with minimal boilerplate (~4K lines of core code). Header-only library organized around include/pybind11/ with modular type casting in include/pybind11/cast/ (chrono.h, eigen.h, functional.h, stl.h, strings.h), core binding machinery in include/pybind11/ (class definitions, operators, exceptions), and comprehensive examples in examples/ and external repos (python_example, scikit_build_example, cmake_example). CMake-based build system with presets (CMakePresets.json) for standard configurations.

👥Who it's for

C++ library authors who need to expose their code to Python users, and Python developers who need high-performance C++ acceleration without writing complex extension modules. Also used by scientific computing projects (NumPy, SciPy ecosystem) and those building performance-critical bindings.

🌱Maturity & risk

Production-ready and actively maintained. The project is at v3, has extensive CI/CD across multiple platforms (.github/workflows/ci.yml, cibw tests), comprehensive test coverage, and supports CPython 3.8+, PyPy, and GraalPy. Regular commits and active GitHub Discussions indicate ongoing development and community engagement.

Low risk: header-only library reduces dependency issues, but requires C++11-compatible compiler and Python dev headers at compile time. Documentation is thorough but the codebase is complex (1.8M lines of C++); contributors need solid C++ template knowledge. Single-project focus means no broad ecosystem risk, but binding-specific issues could affect users.

Active areas of work

Active development visible in .github/workflows/ with nightly wheel builds (.github/workflows/nightlies.yml), dependency management via Dependabot, and CI standardization through reusable workflows (.github/workflows/reusable-standard.yml). Documentation updates ongoing with Sphinx + MyST parser (docs/requirements.txt). Code formatting enforced via .clang-format and .clang-tidy.

🚀Get running

git clone https://github.com/pybind/pybind11.git
cd pybind11
cmake -B build --preset=default
cmake --build build
ctest --test-dir build

For development: Python 3.8+ required, uses CMake 3.15+. See docs/ for detailed build instructions and examples/ for starter code.

Daily commands:

cmake -B build --preset=default
cmake --build build
ctest --test-dir build  # Run test suite

No runtime server; library is header-only. Binding generation happens at compile time. See examples/ subdirectory for compiled executable examples using pybind11.

🗺️Map of the codebase

  • include/pybind11/attr.h — Core attribute binding interface that defines how C++ members and methods are exposed to Python—fundamental to the binding DSL.
  • include/pybind11/cast.h — Type casting and conversion engine between C++ and Python objects; handles all serialization logic that makes operability work.
  • include/pybind11/detail/class.h — Class binding implementation that drives how C++ classes are wrapped into Python types—core abstraction for OOP interop.
  • include/pybind11/common.h — Shared utilities, macros, and platform abstractions used throughout the library; must be understood for any contribution.
  • include/pybind11/detail/type_caster_base.h — Base type caster that defines the protocol for custom type conversions between C++ and Python.
  • CMakeLists.txt — Build configuration and header-only library installation logic; defines how the library is distributed.
  • .github/workflows/ci.yml — Primary CI/CD pipeline orchestrating tests across Python versions and platforms; signals what must pass.

🛠️How to make changes

Add a custom type caster for a new C++ type

  1. Inherit from pybind11::detail::type_caster_base in include/pybind11/detail/type_caster_base.h to understand the protocol (load, cast methods) (include/pybind11/detail/type_caster_base.h)
  2. Create a new header in include/pybind11/ (e.g., include/pybind11/my_type.h) implementing your caster specialization (include/pybind11/)
  3. Define PYBIND11_TYPE_CASTER macro with load() and cast() implementations, matching patterns in include/pybind11/chrono.h (include/pybind11/chrono.h)
  4. Add test cases in tests/ directory following existing patterns (e.g., test_chrono.cpp for chrono types) (tests/)
  5. Document usage in docs/advanced/cast/custom.rst with example binding code (docs/advanced/cast/custom.rst)

Expose a new C++ class to Python

  1. In your binding module, include include/pybind11/pybind11.h and review class binding patterns in docs/classes.rst (docs/classes.rst)
  2. Use py::class_<YourClass> DSL to define constructors, methods, properties via py::init and .def calls as shown in include/pybind11/attr.h (include/pybind11/attr.h)
  3. For smart pointers, configure holder_type in py::class_ using struct_smart_holder patterns from include/pybind11/detail/struct_smart_holder.h (include/pybind11/detail/struct_smart_holder.h)
  4. Register exception translation for custom exceptions using PYBIND11_EXCEPTION macro as shown in include/pybind11/detail/exception_translation.h (include/pybind11/detail/exception_translation.h)

Build and test a pybind11 extension

  1. Create CMakeLists.txt calling find_package(pybind11 CONFIG REQUIRED) and pybind11_add_module(your_module src/module.cpp) as per CMakeLists.txt patterns (CMakeLists.txt)
  2. Run pytest on tests directory; CI invokes tests via .github/workflows/ci.yml which tests multiple Python versions (.github/workflows/ci.yml)
  3. Check code style with clang-format using .clang-format config rules (.clang-format)

🔧Why these technologies

  • C++11 with template metaprogramming — Compile-time type introspection enables zero-overhead abstractions; infers conversion logic without runtime overhead.
  • Header-only library — Users include pybind11 headers directly; no separate binary distribution needed; simplifies deployment and ABI isolation.
  • Python C API (CPython stable ABI via conduit) — Direct access to Python internals for seamless object wrapping; conduit layer isolates ABI details.
  • CMake for build configuration — Integrates with user projects' CMake workflows; portable across platforms (Windows, macOS, Linux).
  • Sphinx + Breathe for documentation — Sphinx generates HTML docs; Breathe bridges C++ Doxygen comments into reStructuredText narratives.

⚖️Trade-offs already made

  • Header-only vs. precompiled library

    • Why: Header-only maximizes ease of use and avoids ABI mismatch issues across compiler/version combinations.
    • Consequence: Compilation time increases for users (longer rebuild cycles); no shared .so/.dll reduces disk footprint trade-off.
  • Minimal boilerplate DSL (attr.h) vs. explicit code generation

    • Why: DSL (py::class_, .def, .init) is more readable and maintainable than generated glue code.
    • Consequence: Heavy template instantiation; build times and binary size grow with binding complexity; requires C++11 compiler support.
  • GIL management in critical_section.h vs. fine-grained locking

    • Why: Scoped GIL guards prevent deadlocks and simplify concurrent C++/Python code.
    • Consequence: GIL contention may limit parallelism; users must understand GIL semantics for performance tuning.
  • Stable ABI conduit layer vs. direct CPython API usage

    • Why: Conduit (include/pybind11/conduit/) isolates version-specific CPython implementation details.
    • Consequence: Extra layer of indirection; enables forward compatibility but adds maintenance burden for platform/version-specific code paths.

🚫Non-goals (don't propose these)

  • Does not provide automatic C++ code generation from Python type hints; binding must be written explicitly.
  • Does not handle network I/O, async/await, or coroutines natively; integration with asyncio is user-responsibility.
  • Does not provide a package manager or dependency resolution; relies on CMake/pip ecosystem.
  • Does not support Python 2; Python 3.6+ only.
  • Not a real-time or embedded database; purely a binding library.
  • Does not replace the Python C API entirely; advanced use cases may require direct API calls.

🪤Traps & gotchas

Compile-time type information: all binding decisions made at template instantiation; runtime type changes won't be reflected. GIL interaction: must explicitly release GIL for thread-safe C++ code using py::gil_scoped_release. Memory ownership: mixing pybind11-managed and manual memory can cause double-frees; understand holder_type carefully. Binary compatibility: CPython ABI differs by version; wheels must be built per-version (cibw handles this). Header-only library size: compilation can be slow for large binding projects; consider precompiled modules.

🏗️Architecture

💡Concepts to learn

  • Type casting and specialization (type_caster<T>) — Core mechanism pybind11 uses to convert between C++ and Python types at binding boundaries; understanding template specialization is essential for extending the library
  • CRTP (Curiously Recurring Template Pattern) — pybind11 uses CRTP extensively in class_<> and type_caster<> to provide static polymorphism without virtual function overhead, critical for header-only performance
  • GIL (Global Interpreter Lock) management — pybind11 provides py::gil_scoped_release and gil_scoped_acquire for managing thread safety in C++ code; mishandling leads to deadlocks or race conditions
  • Holder types and smart pointer management — pybind11's holder_type mechanism (default std::unique_ptr) controls memory ownership; understanding this prevents dangling pointers and double-frees with custom deleters
  • Python descriptor protocol (for properties) — pybind11 leverages Python's descriptor protocol to implement property() and class attributes; essential for exposing getters/setters naturally to Python
  • C++ name mangling and symbol visibility — pybind11 bindings require careful control of symbol visibility via hidden visibility (-fvisibility=hidden) to avoid ABI conflicts; affects cross-platform binary compatibility
  • CPython stable ABI vs. limited API — pybind11 currently uses CPython's full ABI for performance; understanding the stable ABI trade-offs matters for long-term binary compatibility across Python versions
  • pybind/python_example — Official minimal CMake + setuptools example showing how to package a pybind11 binding module for PyPI distribution
  • pybind/scikit_build_example — Modern example using scikit-build-core instead of plain setuptools, demonstrating current packaging best practices for pybind11 projects
  • boostorg/python — Boost.Python is pybind11's spiritual predecessor and alternative; has more features but heavier dependencies (used to compare design trade-offs)
  • nanopb/nanopb — Similar philosophy of minimalist, header-only C library design with strong emphasis on code generation over runtime magic
  • pytorch/pytorch — Major production user of pybind11 for exposing libtorch C++ tensors to Python; reference implementation of complex binding patterns

🪄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 CI workflow for testing pybind11 with upstream C++ standard library versions

The repo has a .github/workflows/upstream.yml file listed but no visibility into its current coverage. Given pybind11's core mission of C++11/Python interoperability, there's high value in systematically testing against development versions of libstdc++ and libc++ to catch breaking changes early. This prevents silent failures for downstream users relying on cutting-edge C++ features.

  • [ ] Review current .github/workflows/upstream.yml to understand existing coverage gaps
  • [ ] Add matrix strategy testing multiple libstdc++ versions (GCC 12, 13, 14 development versions)
  • [ ] Add matrix strategy testing multiple libc++ versions (Clang 16, 17, 18 development versions)
  • [ ] Configure tests to run on Ubuntu and macOS runners with appropriate toolchain setup
  • [ ] Document expectations and known failures in .github/workflows/upstream.yml comments
  • [ ] Add step to report results to GitHub Discussions for visibility

Create missing integration tests for smart pointer edge cases in tests/ directory

The docs have extensive coverage of smart pointers (docs/advanced/smart_ptrs.rst) but the PR suggests this is a complex feature area. New contributors can add specific regression tests for: holder types with custom deleters, cyclic reference handling, and exception safety during smart pointer lifecycle transitions. This directly supports the documented feature set.

  • [ ] Review docs/advanced/smart_ptrs.rst to identify documented smart pointer behavior
  • [ ] Create new test file tests/test_smart_ptr_edge_cases.cpp with holder type tests
  • [ ] Add tests for std::shared_ptr with custom deleters and weak_ptr cycles
  • [ ] Add exception safety tests during construction/destruction in holder context
  • [ ] Add tests for smart pointer holder with move-only types
  • [ ] Update tests/CMakeLists.txt to register new test module

Expand cross-language deadlock documentation and add detection guidance in docs/advanced/deadlock.md

There's a docs/advanced/deadlock.md file indicating this is a known challenge area for C++/Python interop. This document likely needs: concrete reproduction examples, debugging strategies, detection patterns, and links to related test cases. This helps new users avoid a subtle pitfall and reduces support burden.

  • [ ] Review current docs/advanced/deadlock.md to identify gaps vs. similar Boost.Python documentation
  • [ ] Add section: 'Common Deadlock Scenarios' with GIL acquisition ordering examples
  • [ ] Add section: 'Detection Techniques' covering GDB/lldb inspection and timeout-based testing
  • [ ] Add section: 'Best Practices' with code examples for release_guard() and scoped_acquire patterns
  • [ ] Reference related test cases from the test suite (create cross-links)
  • [ ] Add warning box about recursive C++→Python→C++ calls with GIL management
  • [ ] Include link from docs/advanced/functions.rst to deadlock.md for callback functions

🌿Good first issues

  • Add docs/advanced/cast/numpy.rst documenting NumPy array type casting patterns (similar structure to docs/advanced/cast/eigen.rst) with working examples for array_t<> and buffer_info
  • Expand tests/test_smart_ptr.rst coverage for std::make_shared reference counting edge cases and circular reference cleanup, currently underspecified in include/pybind11/smart_holder.h
  • Create examples/auto_cpp_binding/ demonstrating automatic type deduction in class_ definitions vs explicit type specs, filling gap between basic examples/ and advanced docs/

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 81817ae — ci: remove the deadsnakes job (#6052) (rwgk)
  • 9cc298a — ci: pass explicit ARM64 Python artifacts on windows-11-arm (#6051) (rwgk)
  • c5b3ae8 — ci: pin PyPy 3.11 to 7.3.21 on macOS and Windows (#6050) (rwgk)
  • ee1d83f — chore(deps): bump the actions group with 2 updates (#6047) (dependabot[bot])
  • 0f8396e — [skip ci] ci: schedule recurring CI and CIBW runs (#6048) (rwgk)
  • d433610 — [ci] Drop GitHub Action seanmiddleditch/gha-setup-ninja (#6044) (gruenich)
  • 678b673 — build: support Eigen 5 (#6036) (e-kwsm)
  • ae05b15 — [skip ci] docs: add v3.0.4 changelog updates. (#6041) (rwgk)
  • 7029f99 — fix: segfault when moving scoped_ostream_redirect (#6033) (kounelisagis)
  • 2889136 — ci: bump setup-uv to maintained tag scheme (#6035) (henryiii)

🔒Security observations

The pybind11 repository demonstrates good security practices with a dedicated SECURITY.md policy, Dependabot integration for automated dependency monitoring, and clean code structure. The main security considerations are related to documentation build dependencies and dependency management. No hardcoded secrets, SQL injection risks, XSS vulnerabilities, or infrastructure misconfigurations were detected. The codebase appears to be a well-maintained header-only C++ library with minimal external runtime dependencies, which is inherently more secure than large dependency-heavy projects. Recommend implementing automated security scanning (SAST), maintaining regular dependency updates, and considering a more granular vulnerability disclosure timeline for critical issues.

  • Medium · Outdated Sphinx Dependencies — docs/requirements.txt - Sphinx and sphinx-* packages. Sphinx 7.2.6 and related documentation dependencies are pinned to versions from 2024. While not critically outdated, regular updates are recommended to patch potential vulnerabilities in the documentation build chain. Fix: Implement automated dependency scanning with tools like Dependabot (already present in .github/dependabot.yml) and establish a regular update schedule for documentation dependencies.
  • Low · Multiple Third-party Dependencies in Documentation Build — docs/requirements.txt. The documentation build chain includes numerous third-party packages (breathe, furo, myst-parser, sphinxcontrib-*) that expand the attack surface for the documentation generation process. Each dependency could potentially introduce vulnerabilities. Fix: Regularly audit documentation dependencies using pip-audit or similar tools. Consider using dependency pinning with hash verification in CI/CD pipelines to ensure integrity.
  • Low · Long Vulnerability Disclosure Timeline — SECURITY.md. The SECURITY.md policy requests 90 days before public disclosure of vulnerabilities. While reasonable for some projects, this extended timeline could leave users vulnerable if a critical issue is discovered. Fix: Consider implementing a tiered disclosure timeline: critical vulnerabilities (0-30 days), high severity (30-60 days), medium/low (60-90 days). Provide security patches more frequently than the full release cycle.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.