# 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/<extension_id>/`: 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/<extension_id>/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/<extension_id>
./build-all.sh
blender --factory-startup --command extension validate dist/<id>-<version>.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`.

