smithery.ai

pyzig

How the Zig↔Python binding layer works (pyzig), including build-on-import, wrapper generation patterns, ownership rules, and where to add new exported APIs. Use when adding Zig-Python bindings, modifying native extensions, or debugging C-API interactions.

First seen Mar 28, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 4,137 B
  • docs SUMMARY.md 171 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Pyzig Module

pyzig is the Zig↔Python interoperability layer used by Faebryk’s native modules (graph, sexp, faebryk typegraph, …).

There are three distinct layers to keep straight:

  • Python loader/glue: src/faebryk/core/zig/init.py (build-on-import + .pyi syncing)
  • Zig build: src/faebryk/core/zig/build.zig (builds pyzig.so + pyzig_sexp.so, generates stubs)
  • Zig binding utilities: src/faebryk/core/zig/src/pyzig/* (wrapper generation + minimal C-API surface)

Quick Start

ato dev compile
python -c "import faebryk.core.zig; import faebryk.core.graph"

Relevant Files

  • Python-side loader/build glue:

- src/faebryk/core/zig/init.py (ZIGNORECOMPILE, ZIGRELEASEMODE, lock, stub syncing)

  • Zig build + stub generation:

- src/faebryk/core/zig/build.zig (builds extensions + runs .pyi generator)

  • Core pyzig utilities:

- src/faebryk/core/zig/src/pyzig/pybindings.zig (minimal CPython C-API declarations) - src/faebryk/core/zig/src/pyzig/pyzig.zig (wrapper generation helpers) - src/faebryk/core/zig/src/pyzig/type_registry.zig (global type-object registry) - src/faebryk/core/zig/src/pyzig/pyi.zig (stub generation helpers)

  • Example consumers:

- src/faebryk/core/zig/src/python/graph/graphpy.zig - src/faebryk/core/zig/src/python/sexp/sexppy.zig

Dependants (Call Sites)

  • Graph bindings: src/faebryk/core/zig/src/python/graph/*
  • Sexp bindings: src/faebryk/core/zig/src/python/sexp/*
  • TypeGraph bindings: src/faebryk/core/zig/src/python/faebryk/* (and friends)

How to Work With / Develop / Test

Core Concepts

  • Direct binding: pyzig calls the CPython C-API directly (no cffi/ctypes).
  • Wrapper types: most exposed Zig structs become Python heap types via wrapinpython(...) / wrapinpython_simple(...).
  • Global type registry: prevents re-creating Python PyTypeObjects for the same Zig type (type_registry).
  • No direct init (by default): many “reference” types are not meant to be user-constructed; pyzig often installs an init that raises.
  • Debug handle: generated wrappers include __zig_address__() to help debug pointer identity.

Development Workflow

  1. Edit Zig:

- binding helpers: src/faebryk/core/zig/src/pyzig/* - module wrappers: src/faebryk/core/zig/src/python/**

  1. Rebuild native modules:

- ato dev compile (imports faebryk.core.zig; editable installs compile-on-import) - set ZIG_RELEASEMODE=ReleaseFast|ReleaseSafe|Debug as needed

  1. If you changed stubs/output:

- ensure src/faebryk/core/zig/gen/** gets updated (this is driven by src/faebryk/core/zig/init.py)

Testing

  • Smoke tests are usually through downstream modules:

- python -m faebryk.core.graph (GraphView allocation/cleanup stress) - ato dev test --llm test/core/solver (heavy user of graph + bindings via many subsystems)

Best Practices

  • Assume mistakes segfault: treat changes here like unsafe systems programming.
  • Be explicit about ownership:

- if a wrapper allocates Zig memory, define how it is freed (explicit .destroy() vs tp_dealloc calling .deinit()). - if you duplicate input buffers (sexp does), expose a free(...) path and document it.

  • Don’t rely on Python GC for Zig arenas unless you intentionally installed a tp_dealloc that calls deinit.
  • Stub hygiene matters: keep the .pyi surface accurate; many callers rely on types for navigation.

Build-on-import behavior (important)

src/faebryk/core/zig/init.py is responsible for:

  • compiling extensions in editable installs (unless ZIG_NORECOMPILE=1)
  • loading pyzig.so and pyzig_sexp.so from src/faebryk/core/zig/zig-out/lib/
  • copying + formatting generated .pyi files into src/faebryk/core/zig/gen/** (black + ruff)