# Embody + Envoy — AI Instructions This project uses **[Embody](https://github.com/dylanroscover/Embody)** (TouchDesigner externalization) and **Envoy** (MCP server for AI coding tools). - Embody externalizes TouchDesigner operators to version-controlled files (`.py`, `.tox`, `.tdn`, `.json`, etc.) - Envoy provides MCP tools for AI assistants to inspect and modify the live TD network - Use the `Aiclient` parameter on the Embody COMP to regenerate these files for your AI tool > **Note:** For Claude Code users, a `CLAUDE.md` with modular `.claude/rules/` and `.claude/skills/` is also generated. This `AGENTS.md` is the universal fallback read by Cursor, GitHub Copilot, Windsurf, Gemini, and others. --- ## Critical Rules 1. **Prefer `.tdn` files for reading TDN-externalized COMPs** — `.tdn` files are JSON on disk with complete network structure (operators, parameters, connections, positions, flags, DAT content, annotations). Reading them directly is faster than MCP round-trips. Check `externalizations.tsv` (strategy column) to identify TDN-strategy COMPs. To edit: modify the `.tdn` file on disk, then call `import_network` via MCP with the COMP path, the parsed JSON, and `clear_first=True` to reload it in TD. Use MCP when you need live runtime state (evaluated expressions, cook errors) or for non-TDN operators. 2. **Use Envoy MCP tools for live TD state and non-TDN operators** — never say "I can't access that binary file." For operators not externalized as TDN, use MCP tools to inspect and modify them. 3. **Do NOT assume network paths** — use `query_network` on `/` to discover the actual root structure. 4. **Default to the current network** — use `execute_python` with `result = ui.panes.current.owner.path` to find the active pane. 5. **Never edit `externalizations.tsv` directly** — managed exclusively by Embody's tracking system. 6. **Always use forward slashes** in file paths. 7. **Check for errors and warnings after creating operators** — `get_op_errors` with `recurse=true` immediately after creation. 8. **Thread boundary**: MCP server worker thread must never import TD modules. All TD access goes through `_execute_in_td()`. --- ## TD Python Rules - **Always use `.eval()`** to get a parameter's current runtime value. `.val` only returns the constant-mode value. - **Setting `.val` silently switches mode to CONSTANT** — destroys any active expression. - **Toggle parameters** use `0`/`1` (not `"True"`/`"False"`). - **Use `opex()`** when the operator must exist — raises immediately with a clear error. `op()` returns `None` silently. - **Never call `op()`, `parent()`, or access TD objects at module level** — defer to methods. - **NEVER access TD objects from a worker thread** — all TD operations must go through main-thread hooks. - **`fetch()` searches UP the parent hierarchy** by default — pass `search=False` for local-only lookup. - **`tdu.Dependency`**: Assign to `.val` (`dep.val = 5`), NOT the object itself. Call `.modified()` after mutating contents. ## Network Layout Rules - **200-unit grid**: All positions snap to multiples of 200. Never place at arbitrary coordinates. - **300 units horizontal** between connected operators in a chain. - **Left to right** signal flow: inputs on the left, outputs on the right. - **NEVER place an operator on top of another** — scan with `query_network` and `get_op_position` before placing. - **Every logical group gets an annotation** — use `create_annotation` around each cluster of related operators. - **Annotations must enclose their operators**: `nodeX`/`nodeY` is the bottom-left corner — `nodeY` must be below (less than) the lowest operator's Y. - **TD Y-axis increases upward** — new rows go downward (decreasing Y). ## MCP Server Safety Rules - Envoy must bind to `127.0.0.1`, NEVER `0.0.0.0`. - `_execute_in_td()` times out at 30 seconds. - The MCP server runs as a `standalone=True` TDTask (long-lived, outside the worker pool). - Uses `threading.Event` + `Queue` rather than locks because TD's cook cycle is frame-based. --- ## Project Structure ``` Embody/ ├── AGENTS.md # This file — universal AI instructions ├── CLAUDE.md # Claude Code specific instructions (if using Claude) ├── dev/ │ ├── embody/ │ │ ├── externalizations.tsv # Tracking table (NEVER edit directly) │ │ └── Embody/ # Main extension source │ │ ├── EmbodyExt.py # Core externalization engine │ │ ├── EnvoyExt.py # MCP server extension │ │ └── TDNExt.py # TDN network format export/import └── release/ └── Embody-v*.tox # Latest release build ``` ## Extension Referencing ```python # Promoted methods (uppercase) — called directly on the component: op.Embody.Update() op.Embody.Save() # Non-promoted (lowercase) — through ext: op.Embody.ext.Embody.getExternalizedOps() op.Embody.ext.Envoy.Start() ``` **NEVER cache extension references in variables** — always call inline.