This file is the shared operating manual for AI contributors working in irx.
Use it to keep implementation style, review standards, and delivery quality
consistent across different agents.
Use this guidance for any change inside the IRx repository:
- LLVM lowering or codegen behavior
- ASTx node support in visitors/builders
- build/link/run behavior
- tests, typing, lint, and coverage work
- docs/examples updates
- CI/release-related maintenance
- Preserve existing IR semantics unless the task explicitly changes behavior.
- Keep lowering code, tests, and docs aligned.
- Keep quality gates green (tests, mypy, ruff, pre-commit, coverage).
- Make minimal, targeted edits with clear intent.
- Package:
pyirx - Runtime: Python
>=3.10,<4 - Main architecture:
ASTx -> LLVMLiteIRVisitor -> LLVM IR -> object -> clang link - Key dependencies:
astxfor AST nodesllvmlitefor IR and object emissionplum-dispatchfor visitor dispatchxhellfor invokingclang
- Docs stack: MkDocs + Material + mkdocstrings
src/irx/builders/base.py: generic builder interfaces and command runnersrc/irx/builders/llvmliteir.py: main LLVM visitor/builder implementationsrc/irx/system.py: IRx-specific ASTx expression helpers (PrintExpr,Cast)src/irx/symbol_table.py: register/symbol table helperssrc/irx/tools/typing.py: typing/typeguard helperstests/: unit/integration tests (translate and build/run flows)docs/: project documentation and notebook tutorials.makim.yaml: local task runner definitions.github/workflows/main.yaml: CI pipeline
- Defines
BuilderVisitorandBuilderabstractions. Builder.module()creates ASTx modules.Builder.translate()delegates to visitor translation.Builder.run()executes generated binaries viarun_command().
VariablesLLVM: canonical LLVM types and module/builder state.LLVMLiteIRVisitor: ASTx -> LLVM lowering via@dispatchmethods.LLVMLiteIR: public builder API (translate,build,run).- Handles:
- literals, identifiers, assignments, unary/binary ops
- functions/prototypes/calls/returns
- control flow (
if, loops) - system expressions (
PrintExpr,Cast)
- Defines IRx expression helpers used by lowering:
PrintExprCast
- These are ASTx expressions and should remain structurally serializable.
result_stackdiscipline:- push only real produced values
- never assume a value exists after statement-only or terminating branches
- Terminator safety:
- never emit instructions after a block terminator (
ret,br, etc.) - when temporarily moving insertion point (entry allocas), restore the previous block
- never emit instructions after a block terminator (
- If/merge behavior:
- build PHI only when both incoming paths fall through and value types match
- allow branch-terminating paths without forced stack pops
safe_pop()behavior is optional (Noneon empty stack); callers must guard appropriately- Keep generated IR parseable by LLVM (
llvm.parse_assembly).
translate()only returns LLVM IR text.build()parses IR, emits object, and links withclang.run()executes the compiled output file.- Build-path tests require
clangavailable onPATH.
- Python style:
- 4-space indentation (
.editorconfig) - keep lines shorter than 80 characters (
ruffuses 79)
- 4-space indentation (
- Ruff:
ruff check src testsruff format src tests
- Typing:
mypystrict mode (check_untyped_defs = true,strict = true)
- Pre-commit also runs:
bandit,vulture,mccabe, and project hooks
- Design:
- follow SOLID principles
- prefer the Never Nest philosophy as much as possible
- do not reuse the same variable for different types
- avoid unnecessary or obvious comments in code
- Docstrings are written in Douki format:
- Keep existing docstring style (
title: ..., optional metadata fields). - Preserve docstrings for public-facing symbols when adding/updating code.
- Keep errors explicit and local to failure context.
- Avoid introducing broad catch-all behavior that hides IR-generation faults.
Environment setup:
mamba env create --file conda/dev.yaml
conda activate irx
poetry installHigh-value commands:
# tests
pytest tests -q
# strict typing
mypy src tests
# lint/format
ruff check src tests
ruff format src tests
# project lint stack
makim tests.linter
# CI-like local run
makim tests.ci
# coverage-gated unit run (fails under 80%)
makim tests.unit
# docs
mkdocs build --config-file mkdocs.yamlIR/build debug helpers:
# generate temporary C test binary
makim tests.build
# emit LLVM IR from C for comparison experiments
makim tests.emit-ir
# build binary from .ll
makim tests.build-from-ir --file <path-without-extension>GitHub Actions (.github/workflows/main.yaml) runs:
- tests on Python 3.10, 3.11, 3.12, 3.13, 3.14
- operating systems: ubuntu + windows (windows/3.13 excluded)
- linter job on ubuntu (Python 3.13) with pre-commit stack
Do not merge feature work that assumes only one interpreter/OS path.
- Prefer targeted tests near changed behavior (
tests/test_*.py). - For lowering/control-flow work:
- add at least one
translate-path assertion (IR validity/shape) - add
build/runtime assertions when behavior depends on execution
- add at least one
- Keep/extend regressions for previously fixed edge cases (e.g., terminator-sensitive branches).
When behavior changes, update docs in the same PR:
README.mdusage/examplesdocs/installation.md/docs/contributing.mdwhen setup changes- tutorial notebooks when user-facing behavior changes
- Add/adjust a
@dispatchvisitor inllvmliteir.py. - Ensure type handling and stack behavior are explicit.
- Add tests for both happy path and at least one invalid/edge path.
- Validate generated IR is parseable.
- Update README/docs if feature is user-visible.
- Validate block terminator states before branching/merging.
- Avoid unconditional pops from
result_stack. - Add branch-termination regressions (both terminate, one terminates, neither).
- Verify IR parse + runtime behavior.
- Keep
translateandbuildresponsibilities separate. - Preserve
clanginvocation behavior across platforms where possible. - Add tests that fail clearly when toolchain assumptions are not met.
- Make minimal focused changes.
- Add/update tests for behavior changes.
- Run local checks before finalizing (
ruff,mypy, targetedpytest). - Keep AGENTS/docs consistent with any workflow or architecture changes.