# TouchDesigner Project (powered by Embody + Envoy) ## Project Overview This is a TouchDesigner project using **Embody** for version-controlled externalization and **Envoy** as an MCP server for programmatic operator access. - **Embody** externalizes COMP and DAT operators to text files (.tox, .py, .json, .xml, etc.) so they can be diffed and merged in git - **Envoy** lets you create, modify, connect, and query TouchDesigner operators via MCP tools — plus manage externalizations ## 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) or call `get_externalizations` 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 edit that because it's in a .tox" or "these are binary files I can't access." For operators not externalized as TDN, use MCP tools to inspect and modify them. The filesystem holds externalized files (`.py`, `.tox`, `.tdn`, `.json`, `.xml`, etc.); MCP is for interacting with live operator state inside TD. 3. **Do NOT assume network paths** — never guess `/project1`. 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 for cross-platform compatibility. 7. **Always consult the TD wiki** before writing TD Python code OR claiming TD behavior — confirm API behavior, file formats, and application features against official Derivative documentation even if you're confident. Never assume a TD feature, file type, or convention exists without a verified source. 8. **Binary files** (`.toe`, `.tox`) — use MCP tools to inspect contents, not the filesystem. 9. **Always check for errors and warnings after creating operators** — `get_op_errors` with `recurse=true` immediately after creating and connecting. 10. **Favor annotations over OP comments** — use `create_annotation` for documenting operators and groups. 11. **Always analyze log files after MCP operations** — read `dev/logs/` for the complete picture. Ring buffer only holds 200 entries. 12. **Load the relevant skill BEFORE acting** — skills are prerequisites, not optional reference: - Before `create_op`: load `/create-operator` - Before `create_annotation` or `set_annotation`: load `/manage-annotations` - Before `create_extension`: load `/create-extension` - Before `externalize_op` or `save_externalization`: load `/externalize-operator` - Before writing TD Python (`execute_python`, `set_dat_content`): load `/td-api-reference` - When diagnosing operator errors: load `/debug-operator` - Before first MCP call in a new session: load `/mcp-tools-reference` ## Approach Guidelines - Before editing a file, verify it is the ACTUAL file responsible. Grep and trace the render path before making changes. - Avoid over-engineering. Prefer minimal, targeted changes. - When debugging, state your hypothesis, verify with evidence, then fix. ## Envoy MCP Server The MCP server runs inside TouchDesigner on the configured port (default: 9870). It auto-creates `.mcp.json` in the project root on startup. Manual configuration if needed: ```json { "mcpServers": { "envoy": { "type": "http", "url": "http://localhost:9870/mcp" } } } ``` ## Recommended Permissions To reduce tool-approval prompts, consider auto-allowing read-only Envoy tools in your Claude Code settings (`.claude/settings.local.json` → `alwaysAllow`). These tools only inspect — they never create, modify, or delete: `get_op`, `get_parameter`, `get_connections`, `get_annotations`, `get_enclosed_ops`, `get_op_position`, `get_op_flags`, `get_op_performance`, `get_op_errors`, `get_dat_content`, `get_td_info`, `get_td_classes`, `get_td_class_details`, `get_logs`, `get_externalizations`, `get_externalization_status`, `get_module_help`, `query_network`, `find_children` ## Extension Conventions ```python # Promoted methods (uppercase) — called directly on the component: op.MyExtension.DoSomething() # Non-promoted (lowercase) — through ext: op.MyExtension.ext.MyExtension.helperMethod() ``` **NEVER cache extension references in variables** — always call inline. Cached refs go stale on reinit. ## Creating Python Files When creating Python files for TouchDesigner (scripts, extensions, callbacks): 1. Create the textDAT in TouchDesigner first (via MCP `create_op` or in TD UI) 2. Write code into the DAT (via MCP `set_dat_content`) 3. Externalize the DAT (`externalize_op`) — Embody writes the file to disk **Never** manually set `file`/`syncfile` parameters — Embody handles all file management. ## Key References - **TD Wiki**: https://docs.derivative.ca/Main_Page - **TD Python API**: MUST load `/td-api-reference` before writing TD Python code - **MCP Tools**: MUST load `/mcp-tools-reference` before first MCP tool call in session - **Network Layout**: See `.claude/rules/network-layout.md` for placement conventions - **TD Python Rules**: See `.claude/rules/td-python.md` for critical gotchas