{"owner":"halide","repo":"Halide","hasSkills":true,"totalSkillsCount":1,"totalTokensCount":2850,"categories":["claude-rule"],"hasMcp":false,"mcpConfig":null,"found":[".claude/CLAUDE.md"],"skills":{".claude/CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with\ncode in this repository. Personal overrides (e.g. always preferring the\nMakefile) belong in a git-ignored `CLAUDE.local.md` in the repo root, not here.\n\n## What this is\n\nHalide is a compiler embedded in C++ (with Python bindings) for writing\nhigh-performance image/array processing pipelines. Users describe pipelines as\n`Func`/`Var`/`Expr` algebra (front-end), which Halide lowers to an internal\n`Stmt`/`Expr` IR, applies dozens of scheduling/optimization passes to, then\ncodegens via LLVM for CPU targets (x86, ARM, Hexagon, PowerPC, RISC-V, Wasm) or\nemits device-C/shading code for GPU backends (CUDA, OpenCL, Metal, D3D12,\nVulkan, WebGPU).\n\n## Building\n\nCMake (3.28+) is the supported build system; the top-level `Makefile` also works\nand is preferred by some contributors, but is unsupported for third parties\n(\"use at your own risk\", can't build Python bindings or packages). If instructed\nto use the Makefile, don't forget to verify that any new tests are added to the\nCMake build too before pushing.\n\nHalide needs LLVM 21, 22, or 23 (trunk also works). Easiest way to get one is\nvia a `uv`-managed Python virtual env; activate it before building so CMake can\nautodetect the LLVM install:\n\n```shell\n$ uv sync --frozen --group ci-llvm-22 --no-install-workspace\n$ source .venv/bin/activate\n```\n\nBasic build:\n\n```shell\n$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release\n$ cmake --build build\n```\n\nIf CMake can't find LLVM (e.g. the venv isn't active in the current shell), pass\nit explicitly: `-DHalide_LLVM_ROOT=$(halide-llvm --prefix)` (run `halide-llvm`\nfrom inside the venv to get the right absolute path).\n\nOn macOS with Homebrew LLVM, `cmake --preset=macOS -S . -B build` finds it\nautomatically. Other useful presets (see `CMakePresets.json`): `debug`,\n`release`, `release-vcpkg`, `macOS-fuzz`, `macOS-coverage`, `linux-x64-asan`,\n`linux-x64-fuzzer`, `valgrind`, `sde`.\n\nKey build options (`Halide_feature(...)` in `CMakeLists.txt`): `WITH_TESTS`,\n`WITH_AUTOSCHEDULERS`, `WITH_PYTHON_BINDINGS`, `WITH_SERIALIZATION`,\n`WITH_TUTORIALS`, `WITH_UTILS`, `WITH_DOCS`. `Halide_ENABLE_MEMCHECK` enables\n`ctest -T memcheck` (valgrind) runs.\n\nDetails: `doc/BuildingHalideWithCMake.md`. Package-consumer docs:\n`doc/HalideCMakePackage.md`.\n\n## Testing\n\nTests use CTest and live under `test/`, one CTest label per subdirectory\n(`correctness`, `error`, `warning`, `generator`, `performance`, `runtime`,\n`fuzz`, `integration`, `autoschedulers/$AS`). See `doc/Testing.md` for the full\nbreakdown of conventions (e.g. `error` tests expect an uncaught non-Halide\nexception, `warning` tests look for a `Warning:` line, tests print `[SKIP]` when\ninapplicable to the current target).\n\n```shell\n$ ctest --test-dir build --output-on-failure          # everything\n$ ctest --test-dir build -L correctness               # one label\n$ ctest --test-dir build -R correctness_bounds         # one test by name\n```\n\nTest binaries are named `<label>_<basename>`, e.g. `test/correctness/bounds.cpp`\nbuilds `correctness_bounds`; running it directly (e.g. under `lldb`) works too.\nTests print `Success!` on success.\n\n`make run_tests` and `make test_apps` are the make-based equivalents (JIT tests\nand app compile/run checks, respectively).\n\nUseful runtime env vars (see README \"Some useful environment variables\"):\n`HL_JIT_TARGET`, `HL_TARGET` (AOT target for make-based test builds),\n`HL_DEBUG_CODEGEN=1` (+ higher for more detail), `HL_NUM_THREADS`,\n`HL_TRACE_FILE`.\n\n## Linting / formatting\n\nThis repo uses `pre-commit`; run it locally before sending a PR:\n\n```shell\n$ pre-commit run --all-files\n```\n\nIt runs `clang-format` (C++, sorted includes), `clang-tidy` (via\n`run-clang-tidy.sh`), `ruff` (Python), `codespell`, `shellcheck`/`shfmt`,\n`mdformat`, `taplo`, and CMake style/file-list checks\n(`tools/check_cmake_style.py`, `tools/check_cmake_file_lists.py` — CMake test\n`CMakeLists.txt` file lists are checked for being sorted/complete).\n\n## Contribution norms (from CONTRIBUTING.md)\n\n- Non-trivial changes should have a GitHub Issue/Discussion first to align on\n  design before large effort is invested.\n- Bug fixes need a regression test; new features need tests (fuzz tests\n  requested where applicable).\n- Public API changes (anything in `Halide::`) need doc updates and corresponding\n  Python binding updates.\n- Performance-affecting changes should describe expected impact / include\n  benchmarks in the PR description.\n- Keep unrelated fixes out of feature/bugfix PRs, even tempting drive-by CI\n  fixes — open a separate PR.\n- AI-assisted commits require a `Co-authored-by:` trailer identifying the tool\n  (see `CONTRIBUTING.md` for the exact format Halide expects).\n- Any AI-assisted github comments or PR descriptions require a 'Generated with'\n  footer that names the tool used.\n- Documentation, comments, and tutorials should match the existing style and\n  prose — keep explanations simple and concise. If a change makes any of these\n  out of date, identify and update them to match the implementation.\n\n## Common mistakes to avoid\n\n- Comments should describe the code as it is now, not the history of how it got\n  there — don't reference past bugs, prior implementations, or the current\n  task/PR in comments.\n- Prefer existing compiler machinery (`IRVisitor`/`IRMutator`/`IRMatch` helpers,\n  existing `Simplify` rules, etc.) over hand-rolling a new mechanism that\n  duplicates something already in the codebase.\n- Only amend or force-push commits that haven't been pushed yet; once a commit\n  is pushed, add new commits on top instead (PRs are squash-merged, so in-branch\n  history doesn't need to be pristine).\n- When benchmarking multiple things, run them sequentially, not in parallel —\n  concurrent runs contend for CPU/cache resources and produce misleading\n  numbers.\n- `For` loop IR nodes store an inclusive `min`/`max` pair (the loop runs for `i`\n  in `[min, max]`), not `min`/`extent` — mixing the two up is a common source of\n  apparent off-by-one errors.\n\n## Architecture\n\n### Front end (embedded DSL)\n\nThe user-facing API — `Func`, `Var`, `Expr`, `Buffer`, `Param`, `RDom`,\n`Pipeline`, scheduling directives (`.split`, `.vectorize`, `.compute_at`, etc.)\n— lives in top-level `src/*.h`/`.cpp` files named after the concept (`Func.h`,\n`Var.h`, `Schedule.h`, `RDom.h`, ...). This is the layer most user code and\ntutorials interact with directly.\n\n### IR core\n\n`Expr`/`Stmt` (defined in `IR.h`/`Expr.h`) are the internal AST nodes lowered\npipelines are built from. Almost every pass in the compiler is one of:\n\n- an `IRVisitor`/`IRGraphVisitor` (`IRVisitor.h`) — read-only traversal,\n- an `IRMutator` (`IRMutator.h`) — traversal producing a rewritten IR, or\n- pattern-matching via `IRMatch.h` (`Halide::IR::match`-style wildcard matching,\n  heavily used in `Simplify*.cpp` and `FindIntrinsics.cpp`) built on\n  `IROperator.h` helpers.\n\n`IRMatch.h` and `Type.h` are code-size- and perf-sensitive (they're inlined into\nevery simplifier pass), so changes there need to be weighed for both\ncompile-time throughput and generated-binary size, not just correctness.\n\nFor a short, single-use traversal (no other caller needs the visitor/mutator\nclass), prefer the lambda-based `visit_with`/`mutate_with` helpers\n(`IRVisitor.h`/`IRMutator.h`) over defining a full `IRVisitor`/`IRMutator`\nsubclass — pass one lambda per node type you care about\n(`(auto *self, const T *op) { ... }`); unhandled node types fall through to the\ndefault recursive behavior. Reach for a real subclass instead once the logic\nneeds to be reused from multiple call sites or carries enough per-pass state\nthat a named class is clearer.\n\n### Lowering pipeline\n\n`Lower.cpp` (`lower_main_stmt`/`lower`) is the orchestrator: it runs Funcs\nthrough ~50-100 named passes in a fixed order — bounds inference (`Bounds.cpp`,\n`BoundsInference.cpp`), inlining, storage flattening, loop partitioning,\nvectorization/simplification, GPU loop handling (`FuseGPUThreadLoops.cpp`,\n`CanonicalizeGPUVars.cpp`), async producer insertion, atomic mutex insertion,\nand more — each implemented as its own `PassName.cpp`/`.h` pair at the top of\n`src/`. When debugging an unexpected lowering result, `HL_DEBUG_CODEGEN=1`+\nprints the IR after key passes, and `Lower.cpp`'s pass list is the map of \"what\nruns when.\"\n\n### Code generation\n\n`CodeGen_LLVM.cpp`/`.h` is the shared LLVM IR emission base class.\nArchitecture-specific specializations (`CodeGen_ARM.cpp`, `CodeGen_Hexagon.cpp`,\n`CodeGen_RISCV.cpp`, `CodeGen_PowerPC.cpp`, `CodeGen_WebAssembly.cpp`, x86 via\n`CodeGen_CPU.cpp`) override intrinsic lowering and target-specific codegen.\nGPU/device backends are separate \"Dev\" codegen classes (`CodeGen_PTX_Dev.cpp`\nfor CUDA, `CodeGen_OpenCL_Dev.cpp`, `CodeGen_Metal_Dev.cpp`,\n`CodeGen_D3D12Compute_Dev.cpp`, `CodeGen_Vulkan_Dev.cpp`,\n`CodeGen_WebGPU_Dev.cpp`) that emit device kernels, while host-side glue for\noffloading is handled by passes like `InjectHostDevBufferCopies.cpp` and\n`OffloadGPULoops.cpp`. `CodeGen_C.cpp` is a separate C source backend (not\nLLVM-based).\n\n### Runtime\n\n`src/runtime/` is a minimal, freestanding-ish C/C++ runtime (allocation,\nthreading, device API glue, tracing) compiled to LLVM bitcode and linked into\n*every* compiled Halide pipeline. It must stay compilable without a full libc in\nsome configurations — notably, standalone Hexagon builds have no libc++, so\nruntime headers must avoid pulling in heavy STL headers like `<iostream>` (use\n`<ostream>`/`<iosfwd>` instead).\n\n### Generators and AOT compilation\n\n`Generator.h`/`AbstractGenerator.h` define the `Generator<T>` mechanism users\nsubclass to package a pipeline (`generate()`/`schedule()`) for ahead-of-time\ncompilation. `tools/GenGen.cpp` is the generic generator-executable `main()`\nthat CMake's `add_halide_generator`/`add_halide_library` (in\n`cmake/HalideGeneratorHelpers.cmake`) build and invoke to emit object\nfiles/headers. `Callable.h` covers a lighter-weight JIT-callable path that skips\nthe Generator plumbing.\n\n### Autoschedulers\n\n`src/autoschedulers/` contains pluggable autoscheduling algorithms\n(`mullapudi2016`, `adams2019`, `li2018`, `anderson2021`), each built as its own\nshared library that can be loaded at schedule time\n(`Pipeline::apply_autoscheduler`) rather than linked into core Halide.\n`src/autoschedulers/common` holds shared infrastructure.\n\n### Python bindings\n\n`python_bindings/` mirrors the C++ API via pybind11 (`src/`), with its own\n`test/`, `tutorial/`, and `apps/` mirroring the top-level layout. Public API\nchanges in `Halide::` should come with a matching binding update here.\n\n### apps/ and tutorial/\n\n`apps/` holds larger, realistic example pipelines (camera_pipe, hannk,\nresnet_50, local_laplacian, etc.) used as both examples and\nperformance/integration tests. `tutorial/` holds the numbered lessons behind\nhttps://halide-lang.org/tutorials, each with corresponding code Halide expects\nto keep in sync with the docs.\n"},"files":{".claude/CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with\ncode in this repository. Personal overrides (e.g. always preferring the\nMakefile) belong in a git-ignored `CLAUDE.local.md` in the repo root, not here.\n\n## What this is\n\nHalide is a compiler embedded in C++ (with Python bindings) for writing\nhigh-performance image/array processing pipelines. Users describe pipelines as\n`Func`/`Var`/`Expr` algebra (front-end), which Halide lowers to an internal\n`Stmt`/`Expr` IR, applies dozens of scheduling/optimization passes to, then\ncodegens via LLVM for CPU targets (x86, ARM, Hexagon, PowerPC, RISC-V, Wasm) or\nemits device-C/shading code for GPU backends (CUDA, OpenCL, Metal, D3D12,\nVulkan, WebGPU).\n\n## Building\n\nCMake (3.28+) is the supported build system; the top-level `Makefile` also works\nand is preferred by some contributors, but is unsupported for third parties\n(\"use at your own risk\", can't build Python bindings or packages). If instructed\nto use the Makefile, don't forget to verify that any new tests are added to the\nCMake build too before pushing.\n\nHalide needs LLVM 21, 22, or 23 (trunk also works). Easiest way to get one is\nvia a `uv`-managed Python virtual env; activate it before building so CMake can\nautodetect the LLVM install:\n\n```shell\n$ uv sync --frozen --group ci-llvm-22 --no-install-workspace\n$ source .venv/bin/activate\n```\n\nBasic build:\n\n```shell\n$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release\n$ cmake --build build\n```\n\nIf CMake can't find LLVM (e.g. the venv isn't active in the current shell), pass\nit explicitly: `-DHalide_LLVM_ROOT=$(halide-llvm --prefix)` (run `halide-llvm`\nfrom inside the venv to get the right absolute path).\n\nOn macOS with Homebrew LLVM, `cmake --preset=macOS -S . -B build` finds it\nautomatically. Other useful presets (see `CMakePresets.json`): `debug`,\n`release`, `release-vcpkg`, `macOS-fuzz`, `macOS-coverage`, `linux-x64-asan`,\n`linux-x64-fuzzer`, `valgrind`, `sde`.\n\nKey build options (`Halide_feature(...)` in `CMakeLists.txt`): `WITH_TESTS`,\n`WITH_AUTOSCHEDULERS`, `WITH_PYTHON_BINDINGS`, `WITH_SERIALIZATION`,\n`WITH_TUTORIALS`, `WITH_UTILS`, `WITH_DOCS`. `Halide_ENABLE_MEMCHECK` enables\n`ctest -T memcheck` (valgrind) runs.\n\nDetails: `doc/BuildingHalideWithCMake.md`. Package-consumer docs:\n`doc/HalideCMakePackage.md`.\n\n## Testing\n\nTests use CTest and live under `test/`, one CTest label per subdirectory\n(`correctness`, `error`, `warning`, `generator`, `performance`, `runtime`,\n`fuzz`, `integration`, `autoschedulers/$AS`). See `doc/Testing.md` for the full\nbreakdown of conventions (e.g. `error` tests expect an uncaught non-Halide\nexception, `warning` tests look for a `Warning:` line, tests print `[SKIP]` when\ninapplicable to the current target).\n\n```shell\n$ ctest --test-dir build --output-on-failure          # everything\n$ ctest --test-dir build -L correctness               # one label\n$ ctest --test-dir build -R correctness_bounds         # one test by name\n```\n\nTest binaries are named `<label>_<basename>`, e.g. `test/correctness/bounds.cpp`\nbuilds `correctness_bounds`; running it directly (e.g. under `lldb`) works too.\nTests print `Success!` on success.\n\n`make run_tests` and `make test_apps` are the make-based equivalents (JIT tests\nand app compile/run checks, respectively).\n\nUseful runtime env vars (see README \"Some useful environment variables\"):\n`HL_JIT_TARGET`, `HL_TARGET` (AOT target for make-based test builds),\n`HL_DEBUG_CODEGEN=1` (+ higher for more detail), `HL_NUM_THREADS`,\n`HL_TRACE_FILE`.\n\n## Linting / formatting\n\nThis repo uses `pre-commit`; run it locally before sending a PR:\n\n```shell\n$ pre-commit run --all-files\n```\n\nIt runs `clang-format` (C++, sorted includes), `clang-tidy` (via\n`run-clang-tidy.sh`), `ruff` (Python), `codespell`, `shellcheck`/`shfmt`,\n`mdformat`, `taplo`, and CMake style/file-list checks\n(`tools/check_cmake_style.py`, `tools/check_cmake_file_lists.py` — CMake test\n`CMakeLists.txt` file lists are checked for being sorted/complete).\n\n## Contribution norms (from CONTRIBUTING.md)\n\n- Non-trivial changes should have a GitHub Issue/Discussion first to align on\n  design before large effort is invested.\n- Bug fixes need a regression test; new features need tests (fuzz tests\n  requested where applicable).\n- Public API changes (anything in `Halide::`) need doc updates and corresponding\n  Python binding updates.\n- Performance-affecting changes should describe expected impact / include\n  benchmarks in the PR description.\n- Keep unrelated fixes out of feature/bugfix PRs, even tempting drive-by CI\n  fixes — open a separate PR.\n- AI-assisted commits require a `Co-authored-by:` trailer identifying the tool\n  (see `CONTRIBUTING.md` for the exact format Halide expects).\n- Any AI-assisted github comments or PR descriptions require a 'Generated with'\n  footer that names the tool used.\n- Documentation, comments, and tutorials should match the existing style and\n  prose — keep explanations simple and concise. If a change makes any of these\n  out of date, identify and update them to match the implementation.\n\n## Common mistakes to avoid\n\n- Comments should describe the code as it is now, not the history of how it got\n  there — don't reference past bugs, prior implementations, or the current\n  task/PR in comments.\n- Prefer existing compiler machinery (`IRVisitor`/`IRMutator`/`IRMatch` helpers,\n  existing `Simplify` rules, etc.) over hand-rolling a new mechanism that\n  duplicates something already in the codebase.\n- Only amend or force-push commits that haven't been pushed yet; once a commit\n  is pushed, add new commits on top instead (PRs are squash-merged, so in-branch\n  history doesn't need to be pristine).\n- When benchmarking multiple things, run them sequentially, not in parallel —\n  concurrent runs contend for CPU/cache resources and produce misleading\n  numbers.\n- `For` loop IR nodes store an inclusive `min`/`max` pair (the loop runs for `i`\n  in `[min, max]`), not `min`/`extent` — mixing the two up is a common source of\n  apparent off-by-one errors.\n\n## Architecture\n\n### Front end (embedded DSL)\n\nThe user-facing API — `Func`, `Var`, `Expr`, `Buffer`, `Param`, `RDom`,\n`Pipeline`, scheduling directives (`.split`, `.vectorize`, `.compute_at`, etc.)\n— lives in top-level `src/*.h`/`.cpp` files named after the concept (`Func.h`,\n`Var.h`, `Schedule.h`, `RDom.h`, ...). This is the layer most user code and\ntutorials interact with directly.\n\n### IR core\n\n`Expr`/`Stmt` (defined in `IR.h`/`Expr.h`) are the internal AST nodes lowered\npipelines are built from. Almost every pass in the compiler is one of:\n\n- an `IRVisitor`/`IRGraphVisitor` (`IRVisitor.h`) — read-only traversal,\n- an `IRMutator` (`IRMutator.h`) — traversal producing a rewritten IR, or\n- pattern-matching via `IRMatch.h` (`Halide::IR::match`-style wildcard matching,\n  heavily used in `Simplify*.cpp` and `FindIntrinsics.cpp`) built on\n  `IROperator.h` helpers.\n\n`IRMatch.h` and `Type.h` are code-size- and perf-sensitive (they're inlined into\nevery simplifier pass), so changes there need to be weighed for both\ncompile-time throughput and generated-binary size, not just correctness.\n\nFor a short, single-use traversal (no other caller needs the visitor/mutator\nclass), prefer the lambda-based `visit_with`/`mutate_with` helpers\n(`IRVisitor.h`/`IRMutator.h`) over defining a full `IRVisitor`/`IRMutator`\nsubclass — pass one lambda per node type you care about\n(`(auto *self, const T *op) { ... }`); unhandled node types fall through to the\ndefault recursive behavior. Reach for a real subclass instead once the logic\nneeds to be reused from multiple call sites or carries enough per-pass state\nthat a named class is clearer.\n\n### Lowering pipeline\n\n`Lower.cpp` (`lower_main_stmt`/`lower`) is the orchestrator: it runs Funcs\nthrough ~50-100 named passes in a fixed order — bounds inference (`Bounds.cpp`,\n`BoundsInference.cpp`), inlining, storage flattening, loop partitioning,\nvectorization/simplification, GPU loop handling (`FuseGPUThreadLoops.cpp`,\n`CanonicalizeGPUVars.cpp`), async producer insertion, atomic mutex insertion,\nand more — each implemented as its own `PassName.cpp`/`.h` pair at the top of\n`src/`. When debugging an unexpected lowering result, `HL_DEBUG_CODEGEN=1`+\nprints the IR after key passes, and `Lower.cpp`'s pass list is the map of \"what\nruns when.\"\n\n### Code generation\n\n`CodeGen_LLVM.cpp`/`.h` is the shared LLVM IR emission base class.\nArchitecture-specific specializations (`CodeGen_ARM.cpp`, `CodeGen_Hexagon.cpp`,\n`CodeGen_RISCV.cpp`, `CodeGen_PowerPC.cpp`, `CodeGen_WebAssembly.cpp`, x86 via\n`CodeGen_CPU.cpp`) override intrinsic lowering and target-specific codegen.\nGPU/device backends are separate \"Dev\" codegen classes (`CodeGen_PTX_Dev.cpp`\nfor CUDA, `CodeGen_OpenCL_Dev.cpp`, `CodeGen_Metal_Dev.cpp`,\n`CodeGen_D3D12Compute_Dev.cpp`, `CodeGen_Vulkan_Dev.cpp`,\n`CodeGen_WebGPU_Dev.cpp`) that emit device kernels, while host-side glue for\noffloading is handled by passes like `InjectHostDevBufferCopies.cpp` and\n`OffloadGPULoops.cpp`. `CodeGen_C.cpp` is a separate C source backend (not\nLLVM-based).\n\n### Runtime\n\n`src/runtime/` is a minimal, freestanding-ish C/C++ runtime (allocation,\nthreading, device API glue, tracing) compiled to LLVM bitcode and linked into\n*every* compiled Halide pipeline. It must stay compilable without a full libc in\nsome configurations — notably, standalone Hexagon builds have no libc++, so\nruntime headers must avoid pulling in heavy STL headers like `<iostream>` (use\n`<ostream>`/`<iosfwd>` instead).\n\n### Generators and AOT compilation\n\n`Generator.h`/`AbstractGenerator.h` define the `Generator<T>` mechanism users\nsubclass to package a pipeline (`generate()`/`schedule()`) for ahead-of-time\ncompilation. `tools/GenGen.cpp` is the generic generator-executable `main()`\nthat CMake's `add_halide_generator`/`add_halide_library` (in\n`cmake/HalideGeneratorHelpers.cmake`) build and invoke to emit object\nfiles/headers. `Callable.h` covers a lighter-weight JIT-callable path that skips\nthe Generator plumbing.\n\n### Autoschedulers\n\n`src/autoschedulers/` contains pluggable autoscheduling algorithms\n(`mullapudi2016`, `adams2019`, `li2018`, `anderson2021`), each built as its own\nshared library that can be loaded at schedule time\n(`Pipeline::apply_autoscheduler`) rather than linked into core Halide.\n`src/autoschedulers/common` holds shared infrastructure.\n\n### Python bindings\n\n`python_bindings/` mirrors the C++ API via pybind11 (`src/`), with its own\n`test/`, `tutorial/`, and `apps/` mirroring the top-level layout. Public API\nchanges in `Halide::` should come with a matching binding update here.\n\n### apps/ and tutorial/\n\n`apps/` holds larger, realistic example pipelines (camera_pipe, hannk,\nresnet_50, local_laplacian, etc.) used as both examples and\nperformance/integration tests. `tutorial/` holds the numbered lessons behind\nhttps://halide-lang.org/tutorials, each with corresponding code Halide expects\nto keep in sync with the docs.\n"},"items":[{"name":"CLAUDE.md","path":".claude/CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/halide/Halide/HEAD/.claude/CLAUDE.md","title":".claude - Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with\ncode in this repository. Personal overrides (e.g. always preferring the\nMakefile) belong in a git-ignored `CLAUDE.local.md` in the repo root, not here.\n\n## What this is\n\nHalide is a compiler embedded in C++ (with Python bindings) for writing\nhigh-performance image/array processing pipelines. Users describe pipelines as\n`Func`/`Var`/`Expr` algebra (front-end), which Halide lowers to an internal\n`Stmt`/`Expr` IR, applies dozens of scheduling/optimization passes to, then\ncodegens via LLVM for CPU targets (x86, ARM, Hexagon, PowerPC, RISC-V, Wasm) or\nemits device-C/shading code for GPU backends (CUDA, OpenCL, Metal, D3D12,\nVulkan, WebGPU).\n\n## Building\n\nCMake (3.28+) is the supported build system; the top-level `Makefile` also works\nand is preferred by some contributors, but is unsupported for third parties\n(\"use at your own risk\", can't build Python bindings or packages). If instructed\nto use the Makefile, don't forget to verify that any new tests are added to the\nCMake build too before pushing.\n\nHalide needs LLVM 21, 22, or 23 (trunk also works). Easiest way to get one is\nvia a `uv`-managed Python virtual env; activate it before building so CMake can\nautodetect the LLVM install:\n\n```shell\n$ uv sync --frozen --group ci-llvm-22 --no-install-workspace\n$ source .venv/bin/activate\n```\n\nBasic build:\n\n```shell\n$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release\n$ cmake --build build\n```\n\nIf CMake can't find LLVM (e.g. the venv isn't active in the current shell), pass\nit explicitly: `-DHalide_LLVM_ROOT=$(halide-llvm --prefix)` (run `halide-llvm`\nfrom inside the venv to get the right absolute path).\n\nOn macOS with Homebrew LLVM, `cmake --preset=macOS -S . -B build` finds it\nautomatically. Other useful presets (see `CMakePresets.json`): `debug`,\n`release`, `release-vcpkg`, `macOS-fuzz`, `macOS-coverage`, `linux-x64-asan`,\n`linux-x64-fuzzer`, `valgrind`, `sde`.\n\nKey build options (`Halide_feature(...)` in `CMakeLists.txt`): `WITH_TESTS`,\n`WITH_AUTOSCHEDULERS`, `WITH_PYTHON_BINDINGS`, `WITH_SERIALIZATION`,\n`WITH_TUTORIALS`, `WITH_UTILS`, `WITH_DOCS`. `Halide_ENABLE_MEMCHECK` enables\n`ctest -T memcheck` (valgrind) runs.\n\nDetails: `doc/BuildingHalideWithCMake.md`. Package-consumer docs:\n`doc/HalideCMakePackage.md`.\n\n## Testing\n\nTests use CTest and live under `test/`, one CTest label per subdirectory\n(`correctness`, `error`, `warning`, `generator`, `performance`, `runtime`,\n`fuzz`, `integration`, `autoschedulers/$AS`). See `doc/Testing.md` for the full\nbreakdown of conventions (e.g. `error` tests expect an uncaught non-Halide\nexception, `warning` tests look for a `Warning:` line, tests print `[SKIP]` when\ninapplicable to the current target).\n\n```shell\n$ ctest --test-dir build --output-on-failure          # everything\n$ ctest --test-dir build -L correctness               # one label\n$ ctest --test-dir build -R correctness_bounds         # one test by name\n```\n\nTest binaries are named `<label>_<basename>`, e.g. `test/correctness/bounds.cpp`\nbuilds `correctness_bounds`; running it directly (e.g. under `lldb`) works too.\nTests print `Success!` on success.\n\n`make run_tests` and `make test_apps` are the make-based equivalents (JIT tests\nand app compile/run checks, respectively).\n\nUseful runtime env vars (see README \"Some useful environment variables\"):\n`HL_JIT_TARGET`, `HL_TARGET` (AOT target for make-based test builds),\n`HL_DEBUG_CODEGEN=1` (+ higher for more detail), `HL_NUM_THREADS`,\n`HL_TRACE_FILE`.\n\n## Linting / formatting\n\nThis repo uses `pre-commit`; run it locally before sending a PR:\n\n```shell\n$ pre-commit run --all-files\n```\n\nIt runs `clang-format` (C++, sorted includes), `clang-tidy` (via\n`run-clang-tidy.sh`), `ruff` (Python), `codespell`, `shellcheck`/`shfmt`,\n`mdformat`, `taplo`, and CMake style/file-list checks\n(`tools/check_cmake_style.py`, `tools/check_cmake_file_lists.py` — CMake test\n`CMakeLists.txt` file lists are checked for being sorted/complete).\n\n## Contribution norms (from CONTRIBUTING.md)\n\n- Non-trivial changes should have a GitHub Issue/Discussion first to align on\n  design before large effort is invested.\n- Bug fixes need a regression test; new features need tests (fuzz tests\n  requested where applicable).\n- Public API changes (anything in `Halide::`) need doc updates and corresponding\n  Python binding updates.\n- Performance-affecting changes should describe expected impact / include\n  benchmarks in the PR description.\n- Keep unrelated fixes out of feature/bugfix PRs, even tempting drive-by CI\n  fixes — open a separate PR.\n- AI-assisted commits require a `Co-authored-by:` trailer identifying the tool\n  (see `CONTRIBUTING.md` for the exact format Halide expects).\n- Any AI-assisted github comments or PR descriptions require a 'Generated with'\n  footer that names the tool used.\n- Documentation, comments, and tutorials should match the existing style and\n  prose — keep explanations simple and concise. If a change makes any of these\n  out of date, identify and update them to match the implementation.\n\n## Common mistakes to avoid\n\n- Comments should describe the code as it is now, not the history of how it got\n  there — don't reference past bugs, prior implementations, or the current\n  task/PR in comments.\n- Prefer existing compiler machinery (`IRVisitor`/`IRMutator`/`IRMatch` helpers,\n  existing `Simplify` rules, etc.) over hand-rolling a new mechanism that\n  duplicates something already in the codebase.\n- Only amend or force-push commits that haven't been pushed yet; once a commit\n  is pushed, add new commits on top instead (PRs are squash-merged, so in-branch\n  history doesn't need to be pristine).\n- When benchmarking multiple things, run them sequentially, not in parallel —\n  concurrent runs contend for CPU/cache resources and produce misleading\n  numbers.\n- `For` loop IR nodes store an inclusive `min`/`max` pair (the loop runs for `i`\n  in `[min, max]`), not `min`/`extent` — mixing the two up is a common source of\n  apparent off-by-one errors.\n\n## Architecture\n\n### Front end (embedded DSL)\n\nThe user-facing API — `Func`, `Var`, `Expr`, `Buffer`, `Param`, `RDom`,\n`Pipeline`, scheduling directives (`.split`, `.vectorize`, `.compute_at`, etc.)\n— lives in top-level `src/*.h`/`.cpp` files named after the concept (`Func.h`,\n`Var.h`, `Schedule.h`, `RDom.h`, ...). This is the layer most user code and\ntutorials interact with directly.\n\n### IR core\n\n`Expr`/`Stmt` (defined in `IR.h`/`Expr.h`) are the internal AST nodes lowered\npipelines are built from. Almost every pass in the compiler is one of:\n\n- an `IRVisitor`/`IRGraphVisitor` (`IRVisitor.h`) — read-only traversal,\n- an `IRMutator` (`IRMutator.h`) — traversal producing a rewritten IR, or\n- pattern-matching via `IRMatch.h` (`Halide::IR::match`-style wildcard matching,\n  heavily used in `Simplify*.cpp` and `FindIntrinsics.cpp`) built on\n  `IROperator.h` helpers.\n\n`IRMatch.h` and `Type.h` are code-size- and perf-sensitive (they're inlined into\nevery simplifier pass), so changes there need to be weighed for both\ncompile-time throughput and generated-binary size, not just correctness.\n\nFor a short, single-use traversal (no other caller needs the visitor/mutator\nclass), prefer the lambda-based `visit_with`/`mutate_with` helpers\n(`IRVisitor.h`/`IRMutator.h`) over defining a full `IRVisitor`/`IRMutator`\nsubclass — pass one lambda per node type you care about\n(`(auto *self, const T *op) { ... }`); unhandled node types fall through to the\ndefault recursive behavior. Reach for a real subclass instead once the logic\nneeds to be reused from multiple call sites or carries enough per-pass state\nthat a named class is clearer.\n\n### Lowering pipeline\n\n`Lower.cpp` (`lower_main_stmt`/`lower`) is the orchestrator: it runs Funcs\nthrough ~50-100 named passes in a fixed order — bounds inference (`Bounds.cpp`,\n`BoundsInference.cpp`), inlining, storage flattening, loop partitioning,\nvectorization/simplification, GPU loop handling (`FuseGPUThreadLoops.cpp`,\n`CanonicalizeGPUVars.cpp`), async producer insertion, atomic mutex insertion,\nand more — each implemented as its own `PassName.cpp`/`.h` pair at the top of\n`src/`. When debugging an unexpected lowering result, `HL_DEBUG_CODEGEN=1`+\nprints the IR after key passes, and `Lower.cpp`'s pass list is the map of \"what\nruns when.\"\n\n### Code generation\n\n`CodeGen_LLVM.cpp`/`.h` is the shared LLVM IR emission base class.\nArchitecture-specific specializations (`CodeGen_ARM.cpp`, `CodeGen_Hexagon.cpp`,\n`CodeGen_RISCV.cpp`, `CodeGen_PowerPC.cpp`, `CodeGen_WebAssembly.cpp`, x86 via\n`CodeGen_CPU.cpp`) override intrinsic lowering and target-specific codegen.\nGPU/device backends are separate \"Dev\" codegen classes (`CodeGen_PTX_Dev.cpp`\nfor CUDA, `CodeGen_OpenCL_Dev.cpp`, `CodeGen_Metal_Dev.cpp`,\n`CodeGen_D3D12Compute_Dev.cpp`, `CodeGen_Vulkan_Dev.cpp`,\n`CodeGen_WebGPU_Dev.cpp`) that emit device kernels, while host-side glue for\noffloading is handled by passes like `InjectHostDevBufferCopies.cpp` and\n`OffloadGPULoops.cpp`. `CodeGen_C.cpp` is a separate C source backend (not\nLLVM-based).\n\n### Runtime\n\n`src/runtime/` is a minimal, freestanding-ish C/C++ runtime (allocation,\nthreading, device API glue, tracing) compiled to LLVM bitcode and linked into\n*every* compiled Halide pipeline. It must stay compilable without a full libc in\nsome configurations — notably, standalone Hexagon builds have no libc++, so\nruntime headers must avoid pulling in heavy STL headers like `<iostream>` (use\n`<ostream>`/`<iosfwd>` instead).\n\n### Generators and AOT compilation\n\n`Generator.h`/`AbstractGenerator.h` define the `Generator<T>` mechanism users\nsubclass to package a pipeline (`generate()`/`schedule()`) for ahead-of-time\ncompilation. `tools/GenGen.cpp` is the generic generator-executable `main()`\nthat CMake's `add_halide_generator`/`add_halide_library` (in\n`cmake/HalideGeneratorHelpers.cmake`) build and invoke to emit object\nfiles/headers. `Callable.h` covers a lighter-weight JIT-callable path that skips\nthe Generator plumbing.\n\n### Autoschedulers\n\n`src/autoschedulers/` contains pluggable autoscheduling algorithms\n(`mullapudi2016`, `adams2019`, `li2018`, `anderson2021`), each built as its own\nshared library that can be loaded at schedule time\n(`Pipeline::apply_autoscheduler`) rather than linked into core Halide.\n`src/autoschedulers/common` holds shared infrastructure.\n\n### Python bindings\n\n`python_bindings/` mirrors the C++ API via pybind11 (`src/`), with its own\n`test/`, `tutorial/`, and `apps/` mirroring the top-level layout. Public API\nchanges in `Halide::` should come with a matching binding update here.\n\n### apps/ and tutorial/\n\n`apps/` holds larger, realistic example pipelines (camera_pipe, hannk,\nresnet_50, local_laplacian, etc.) used as both examples and\nperformance/integration tests. `tutorial/` holds the numbered lessons behind\nhttps://halide-lang.org/tutorials, each with corresponding code Halide expects\nto keep in sync with the docs.\n","isInternal":false,"tokens":2850,"sizeBytes":11010}],"systemPromptSnippet":"<yakaai_skills repo=\"halide/Halide\">\n<!-- File: .claude/CLAUDE.md (Tokens: ~2850 | Category: claude-rule) -->\n# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with\ncode in this repository. Personal overrides (e.g. always preferring the\nMakefile) belong in a git-ignored `CLAUDE.local.md` in the repo root, not here.\n\n## What this is\n\nHalide is a compiler embedded in C++ (with Python bindings) for writing\nhigh-performance image/array processing pipelines. Users describe pipelines as\n`Func`/`Var`/`Expr` algebra (front-end), which Halide lowers to an internal\n`Stmt`/`Expr` IR, applies dozens of scheduling/optimization passes to, then\ncodegens via LLVM for CPU targets (x86, ARM, Hexagon, PowerPC, RISC-V, Wasm) or\nemits device-C/shading code for GPU backends (CUDA, OpenCL, Metal, D3D12,\nVulkan, WebGPU).\n\n## Building\n\nCMake (3.28+) is the supported build system; the top-level `Makefile` also works\nand is preferred by some contributors, but is unsupported for third parties\n(\"use at your own risk\", can't build Python bindings or packages). If instructed\nto use the Makefile, don't forget to verify that any new tests are added to the\nCMake build too before pushing.\n\nHalide needs LLVM 21, 22, or 23 (trunk also works). Easiest way to get one is\nvia a `uv`-managed Python virtual env; activate it before building so CMake can\nautodetect the LLVM install:\n\n```shell\n$ uv sync --frozen --group ci-llvm-22 --no-install-workspace\n$ source .venv/bin/activate\n```\n\nBasic build:\n\n```shell\n$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release\n$ cmake --build build\n```\n\nIf CMake can't find LLVM (e.g. the venv isn't active in the current shell), pass\nit explicitly: `-DHalide_LLVM_ROOT=$(halide-llvm --prefix)` (run `halide-llvm`\nfrom inside the venv to get the right absolute path).\n\nOn macOS with Homebrew LLVM, `cmake --preset=macOS -S . -B build` finds it\nautomatically. Other useful presets (see `CMakePresets.json`): `debug`,\n`release`, `release-vcpkg`, `macOS-fuzz`, `macOS-coverage`, `linux-x64-asan`,\n`linux-x64-fuzzer`, `valgrind`, `sde`.\n\nKey build options (`Halide_feature(...)` in `CMakeLists.txt`): `WITH_TESTS`,\n`WITH_AUTOSCHEDULERS`, `WITH_PYTHON_BINDINGS`, `WITH_SERIALIZATION`,\n`WITH_TUTORIALS`, `WITH_UTILS`, `WITH_DOCS`. `Halide_ENABLE_MEMCHECK` enables\n`ctest -T memcheck` (valgrind) runs.\n\nDetails: `doc/BuildingHalideWithCMake.md`. Package-consumer docs:\n`doc/HalideCMakePackage.md`.\n\n## Testing\n\nTests use CTest and live under `test/`, one CTest label per subdirectory\n(`correctness`, `error`, `warning`, `generator`, `performance`, `runtime`,\n`fuzz`, `integration`, `autoschedulers/$AS`). See `doc/Testing.md` for the full\nbreakdown of conventions (e.g. `error` tests expect an uncaught non-Halide\nexception, `warning` tests look for a `Warning:` line, tests print `[SKIP]` when\ninapplicable to the current target).\n\n```shell\n$ ctest --test-dir build --output-on-failure          # everything\n$ ctest --test-dir build -L correctness               # one label\n$ ctest --test-dir build -R correctness_bounds         # one test by name\n```\n\nTest binaries are named `<label>_<basename>`, e.g. `test/correctness/bounds.cpp`\nbuilds `correctness_bounds`; running it directly (e.g. under `lldb`) works too.\nTests print `Success!` on success.\n\n`make run_tests` and `make test_apps` are the make-based equivalents (JIT tests\nand app compile/run checks, respectively).\n\nUseful runtime env vars (see README \"Some useful environment variables\"):\n`HL_JIT_TARGET`, `HL_TARGET` (AOT target for make-based test builds),\n`HL_DEBUG_CODEGEN=1` (+ higher for more detail), `HL_NUM_THREADS`,\n`HL_TRACE_FILE`.\n\n## Linting / formatting\n\nThis repo uses `pre-commit`; run it locally before sending a PR:\n\n```shell\n$ pre-commit run --all-files\n```\n\nIt runs `clang-format` (C++, sorted includes), `clang-tidy` (via\n`run-clang-tidy.sh`), `ruff` (Python), `codespell`, `shellcheck`/`shfmt`,\n`mdformat`, `taplo`, and CMake style/file-list checks\n(`tools/check_cmake_style.py`, `tools/check_cmake_file_lists.py` — CMake test\n`CMakeLists.txt` file lists are checked for being sorted/complete).\n\n## Contribution norms (from CONTRIBUTING.md)\n\n- Non-trivial changes should have a GitHub Issue/Discussion first to align on\n  design before large effort is invested.\n- Bug fixes need a regression test; new features need tests (fuzz tests\n  requested where applicable).\n- Public API changes (anything in `Halide::`) need doc updates and corresponding\n  Python binding updates.\n- Performance-affecting changes should describe expected impact / include\n  benchmarks in the PR description.\n- Keep unrelated fixes out of feature/bugfix PRs, even tempting drive-by CI\n  fixes — open a separate PR.\n- AI-assisted commits require a `Co-authored-by:` trailer identifying the tool\n  (see `CONTRIBUTING.md` for the exact format Halide expects).\n- Any AI-assisted github comments or PR descriptions require a 'Generated with'\n  footer that names the tool used.\n- Documentation, comments, and tutorials should match the existing style and\n  prose — keep explanations simple and concise. If a change makes any of these\n  out of date, identify and update them to match the implementation.\n\n## Common mistakes to avoid\n\n- Comments should describe the code as it is now, not the history of how it got\n  there — don't reference past bugs, prior implementations, or the current\n  task/PR in comments.\n- Prefer existing compiler machinery (`IRVisitor`/`IRMutator`/`IRMatch` helpers,\n  existing `Simplify` rules, etc.) over hand-rolling a new mechanism that\n  duplicates something already in the codebase.\n- Only amend or force-push commits that haven't been pushed yet; once a commit\n  is pushed, add new commits on top instead (PRs are squash-merged, so in-branch\n  history doesn't need to be pristine).\n- When benchmarking multiple things, run them sequentially, not in parallel —\n  concurrent runs contend for CPU/cache resources and produce misleading\n  numbers.\n- `For` loop IR nodes store an inclusive `min`/`max` pair (the loop runs for `i`\n  in `[min, max]`), not `min`/`extent` — mixing the two up is a common source of\n  apparent off-by-one errors.\n\n## Architecture\n\n### Front end (embedded DSL)\n\nThe user-facing API — `Func`, `Var`, `Expr`, `Buffer`, `Param`, `RDom`,\n`Pipeline`, scheduling directives (`.split`, `.vectorize`, `.compute_at`, etc.)\n— lives in top-level `src/*.h`/`.cpp` files named after the concept (`Func.h`,\n`Var.h`, `Schedule.h`, `RDom.h`, ...). This is the layer most user code and\ntutorials interact with directly.\n\n### IR core\n\n`Expr`/`Stmt` (defined in `IR.h`/`Expr.h`) are the internal AST nodes lowered\npipelines are built from. Almost every pass in the compiler is one of:\n\n- an `IRVisitor`/`IRGraphVisitor` (`IRVisitor.h`) — read-only traversal,\n- an `IRMutator` (`IRMutator.h`) — traversal producing a rewritten IR, or\n- pattern-matching via `IRMatch.h` (`Halide::IR::match`-style wildcard matching,\n  heavily used in `Simplify*.cpp` and `FindIntrinsics.cpp`) built on\n  `IROperator.h` helpers.\n\n`IRMatch.h` and `Type.h` are code-size- and perf-sensitive (they're inlined into\nevery simplifier pass), so changes there need to be weighed for both\ncompile-time throughput and generated-binary size, not just correctness.\n\nFor a short, single-use traversal (no other caller needs the visitor/mutator\nclass), prefer the lambda-based `visit_with`/`mutate_with` helpers\n(`IRVisitor.h`/`IRMutator.h`) over defining a full `IRVisitor`/`IRMutator`\nsubclass — pass one lambda per node type you care about\n(`(auto *self, const T *op) { ... }`); unhandled node types fall through to the\ndefault recursive behavior. Reach for a real subclass instead once the logic\nneeds to be reused from multiple call sites or carries enough per-pass state\nthat a named class is clearer.\n\n### Lowering pipeline\n\n`Lower.cpp` (`lower_main_stmt`/`lower`) is the orchestrator: it runs Funcs\nthrough ~50-100 named passes in a fixed order — bounds inference (`Bounds.cpp`,\n`BoundsInference.cpp`), inlining, storage flattening, loop partitioning,\nvectorization/simplification, GPU loop handling (`FuseGPUThreadLoops.cpp`,\n`CanonicalizeGPUVars.cpp`), async producer insertion, atomic mutex insertion,\nand more — each implemented as its own `PassName.cpp`/`.h` pair at the top of\n`src/`. When debugging an unexpected lowering result, `HL_DEBUG_CODEGEN=1`+\nprints the IR after key passes, and `Lower.cpp`'s pass list is the map of \"what\nruns when.\"\n\n### Code generation\n\n`CodeGen_LLVM.cpp`/`.h` is the shared LLVM IR emission base class.\nArchitecture-specific specializations (`CodeGen_ARM.cpp`, `CodeGen_Hexagon.cpp`,\n`CodeGen_RISCV.cpp`, `CodeGen_PowerPC.cpp`, `CodeGen_WebAssembly.cpp`, x86 via\n`CodeGen_CPU.cpp`) override intrinsic lowering and target-specific codegen.\nGPU/device backends are separate \"Dev\" codegen classes (`CodeGen_PTX_Dev.cpp`\nfor CUDA, `CodeGen_OpenCL_Dev.cpp`, `CodeGen_Metal_Dev.cpp`,\n`CodeGen_D3D12Compute_Dev.cpp`, `CodeGen_Vulkan_Dev.cpp`,\n`CodeGen_WebGPU_Dev.cpp`) that emit device kernels, while host-side glue for\noffloading is handled by passes like `InjectHostDevBufferCopies.cpp` and\n`OffloadGPULoops.cpp`. `CodeGen_C.cpp` is a separate C source backend (not\nLLVM-based).\n\n### Runtime\n\n`src/runtime/` is a minimal, freestanding-ish C/C++ runtime (allocation,\nthreading, device API glue, tracing) compiled to LLVM bitcode and linked into\n*every* compiled Halide pipeline. It must stay compilable without a full libc in\nsome configurations — notably, standalone Hexagon builds have no libc++, so\nruntime headers must avoid pulling in heavy STL headers like `<iostream>` (use\n`<ostream>`/`<iosfwd>` instead).\n\n### Generators and AOT compilation\n\n`Generator.h`/`AbstractGenerator.h` define the `Generator<T>` mechanism users\nsubclass to package a pipeline (`generate()`/`schedule()`) for ahead-of-time\ncompilation. `tools/GenGen.cpp` is the generic generator-executable `main()`\nthat CMake's `add_halide_generator`/`add_halide_library` (in\n`cmake/HalideGeneratorHelpers.cmake`) build and invoke to emit object\nfiles/headers. `Callable.h` covers a lighter-weight JIT-callable path that skips\nthe Generator plumbing.\n\n### Autoschedulers\n\n`src/autoschedulers/` contains pluggable autoscheduling algorithms\n(`mullapudi2016`, `adams2019`, `li2018`, `anderson2021`), each built as its own\nshared library that can be loaded at schedule time\n(`Pipeline::apply_autoscheduler`) rather than linked into core Halide.\n`src/autoschedulers/common` holds shared infrastructure.\n\n### Python bindings\n\n`python_bindings/` mirrors the C++ API via pybind11 (`src/`), with its own\n`test/`, `tutorial/`, and `apps/` mirroring the top-level layout. Public API\nchanges in `Halide::` should come with a matching binding update here.\n\n### apps/ and tutorial/\n\n`apps/` holds larger, realistic example pipelines (camera_pipe, hannk,\nresnet_50, local_laplacian, etc.) used as both examples and\nperformance/integration tests. `tutorial/` holds the numbered lessons behind\nhttps://halide-lang.org/tutorials, each with corresponding code Halide expects\nto keep in sync with the docs.\n</yakaai_skills>"}