# Contributor and Agent Guide This repository contains Blender extensions and standalone asset-pipeline tools. For Blender work, start with [the extension authoring guide](docs/blender-extension-guide.md), then use [the API notes](docs/blender-api-notes.md) and [the testing and release guide](docs/testing-and-releasing.md) as needed. ## Repository map - `blender//`: one installable Blender extension per directory. Each extension root contains `blender_manifest.toml` and `__init__.py`. - `blender/tests/`: headless Blender smoke tests. These run inside Blender's bundled Python, not ordinary system Python. - `blender/scripts/`: focused helpers for the current extension. - `tools/`: standalone tools that do not need to run inside Blender. - `dist/`: generated extension ZIP packages. Do not hand-edit them. - `build-all.sh`: discover and package every manifest under `blender/`. - `install-all.sh` / `install-all.bat`: build, install, and enable every extension for the current Blender user. ## Rules for Blender extensions 1. Use the Blender Extensions format introduced in Blender 4.2. Do not add a legacy `bl_info` dictionary. Metadata belongs in `blender_manifest.toml`. 2. Keep each extension self-contained. Use relative imports inside its package. Bundle third-party dependencies as wheels and list them in the manifest; never run `pip` from an enabled extension. 3. Treat the installed extension directory as read-only. Persistent extension data belongs under `bpy.utils.extension_path_user(__package__, ...)`. 4. Declare `files`, `network`, `clipboard`, `camera`, or `microphone` permissions in the manifest whenever the extension uses them. Network code must also respect `bpy.app.online_access`. 5. Register Blender classes in dependency order and unregister them in reverse. Delete properties added to `bpy.types` during `unregister()` and remove every handler, timer, menu callback, preview collection, and keymap item created by `register()`. 6. Operators must have a useful `poll()`, use their passed `context`, report actionable failures, and return `{'FINISHED'}` or `{'CANCELLED'}` correctly. 7. Prefer Blender's data API over `bpy.ops`. When an operator is necessary, make its context, selection, active object, object mode, and render engine requirements explicit. 8. Preserve user state. Snapshot and restore temporary selection, active object, mode, render settings, material assignments, and temporary data in `finally`. Do not rely on Undo to reverse file writes or external side effects. 9. Never mutate shared mesh or material data merely to simplify processing. Copy it, operate on the copy, and clean it up unless a persistent result is an explicit feature. 10. Avoid hard-coded repository namespaces such as `bl_ext.user_default`. An extension may be installed from another repository; use `__package__` and relative imports. ## Adding an extension 1. Create `blender//blender_manifest.toml` and `__init__.py`. 2. Use a lowercase snake-case manifest `id`; keep operator IDs and registered class names uniquely prefixed. 3. Set a truthful `blender_version_min`, semantic `version`, SPDX license, and only the permissions actually required. 4. Add a deterministic smoke test under `blender/tests/`. It must create its own scene data, exercise the public operator or API, assert the result, and check that temporary data and global state are restored. 5. Add the test to `blender/scripts/test.sh` or replace that helper with a test dispatcher when a second extension needs its own Blender process. 6. Document the user workflow in `README.md` or a focused file under `docs/`. 7. Run the completion checks below. ## Required completion checks For any changed Blender extension, run checks proportional to the change. The minimum for code changes is: ```bash ./blender/scripts/test.sh blender --factory-startup --command extension validate blender/ ./build-all.sh blender --factory-startup --command extension validate dist/-.zip ``` For registration, packaging, dependency, or manifest changes, also test the built package in an isolated Blender user profile and confirm the enabled extension is loaded. See [Testing and releasing](docs/testing-and-releasing.md). Before declaring success: - Test both the successful path and at least one important validation/failure path. - Confirm the original scene state is preserved unless the feature documents a persistent change. - Confirm no temporary objects, meshes, materials, images, handlers, or files survive unexpectedly. - Rebuild the ZIP after the final source edit; a previously built package is not evidence for the current source. - Bump the manifest version for a user-visible release. ## Standalone tools Code under `tools/` runs in ordinary Python. Keep its dependencies in `tools/requirements.txt`, provide a helpful error when a dependency is absent, and test with `./tools/test.sh`. Standalone tools must not import `bpy`.