LLMSkillHub
mirroredCopied from dylanroscover/Embody under MIT. dylanroscover has not claimed this page, and is not affiliated with LLM SkillHub.

dylanroscover / externalize-operator

MUST READ before calling externalize_op or save_externalization. Required workflow steps.

0
SKILL.md
7.8 KB

<!-- Generated by Embody/Envoy - Do not remove this comment - sha:6d75ab685950501e -->

Externalize Operator Workflow

Tagging (includes save)

externalize_op tags the operator AND writes it to disk in one step (it calls Update() internally). No separate save is needed.

  1. Tag and externalize: externalize_op on the operator (auto-detects type if omitted)
  2. Verify: get_externalization_status to confirm dirty state and file path
  3. Inspect: Verify file exists in embody/ via file inspection

Re-exporting After Changes

save_externalization force re-exports an already-externalized operator. Use it after modifying an operator in TD when you need to update its file on disk.

Excluding Runtime State from TDXN Exports (tdxn_exclude:<par> tags)

When a parameter holds runtime state (a session file path, a negotiated port, a live readout) rather than configuration, keep its value out of committed .tdxn files by tagging the operator itself - one tag per parameter, using the colon-suffixed form of the exclude tag:

op('deck_a').tags.add('tdxn_exclude:file')

The operator and its other parameters export normally; the named parameter's constant value is omitted (expressions/binds still export - references are configuration). The bare tdxn_exclude tag on a COMP is different: it makes the whole COMP invisible to TDXN. The suffixed tag round-trips in the .tdxn, so the omission is visible and survives reconstruction; it takes effect at the COMP's next export (Save tdxn, Update, or project save). A tag naming a nonexistent parameter logs a WARNING at export. Users can manage these visually: the tagger's Actions menu on a TDXN COMP has Exclude from tdxn, a drop-zone panel that toggles tdxn_exclude:<par> for dragged parameters and whole-COMP tdxn_exclude for dragged COMPs, listing every exclusion in the subtree with a per-row x to remove it.

A third form targets a DAT's live contents instead of a parameter: tdxn_exclude:dat_content (a reserved name, so it never trips the unknown-parameter warning). Use it for DATs whose rows are runtime state with no authored value -- a log ring buffer, a status readout. Those are normally force-captured even when Embed DATs is OFF, because Embody refuses to drop content that exists nowhere else on disk; this tag is the only sanctioned way past that net, so apply it only where losing the content is the intent. The operator itself still exports in full (parameters, position, wiring, tags) and returns empty on reconstruction, and the save-time content check reads the same rule, so it never flags the DAT or files it as its own file.

Creating Python Files for TouchDesigner

When creating Python files (scripts, extensions, test files, callbacks):

  1. Create the textDAT in TouchDesigner first (via MCP create_op or in TD UI)
  2. Write the Python code into the DAT (via MCP set_dat_content)
  3. Tag the DAT for externalization (externalize_op) - Embody writes the .py file to disk

NEVER manually set the file and syncfile parameters - Embody handles all file path management.

Exporting a Portable Tox

Export any COMP as a self-contained .tox with all Embody metadata stripped:

  • Via MCP: execute_python with op.Embody.ExportPortableTox(target=op('/path/to/comp'), save_path='/output/path.tox')
  • Via UI: Manager UI > Actions popup > "Export portable tox"

The exported .tox works in any TD project with no missing file errors.

Release hooks: a TEXT DAT named pre_release that is a DIRECT child of the target runs on a STAGED COPY in /sys/quiet - the live comp is never touched, file-sync is disabled on the copy (no write-through to source files), extensions are NOT initialized there and par callbacks don't fire (shape via direct par/DAT/op edits, or use hook_mode='live' for extension logic). A raise aborts the export and keeps the copy as <name>_release_failed for same-session inspection (/sys is not saved; post_release skipped). A direct-child Text DAT named post_release runs on the ORIGINAL after the save whenever pre_release completed - even when the save failed. Both hook DATs are deleted from the copy, so hook code never ships in the artifact. args[0] = resolved save path; post_release also gets args[1] = success. Hooks run synchronously on the main thread - keep them fast, defer uploads. Nested exports from inside a hook run plain (no hooks, no second copy). hook_mode='live' restores in-place semantics (mutations persist, hooks ship dormant in the tox); run_hooks=False skips hooks and ships them as-is (the self-updater's backup uses it). Exports whose target is - or contains - the live Embody COMP are never copy-staged (Embody-self runs live-mode; hooks on a container holding Embody are skipped with a warning in copy mode). op.Embody.ReleaseAll(root=None, out_dir=None) (or the Export All Release Toxes pulse) batch-exports every component that is BOTH Embody-tracked AND hook-bearing - tracked-and-hooked is the opt-in (third-party comps ship with their authors' hook DATs and are never batch-released); per-component failures log and continue.

Checking Status

  • get_externalizations - list all externalized operators with status
  • get_externalization_status - get dirty state, build number, timestamp, file path for a specific operator

TDXN Export - Palette COMP Handling

When exporting a TDXN-strategy COMP whose network contains TD palette components (e.g. abletonLink, Widget components, anything under Samples/Palette/), Embody consults the Tdxnpalettehandling par on the Embody COMP's TDXN page:

  • Ask (default): On first encounter of each palette COMP, a four-button dialog appears - Black Box (this COMP), Full Export (this COMP), Black Box for All, Full Export for All. The per-COMP choice is stored via comp.store('_tdn_palette_handling', ...) so repeated exports don't re-prompt.
  • Black Box: reference the palette only, emit "palette_clone": true, skip internal children. Correct for stock palette COMPs.
  • Full Export: export all children as if the COMP were a regular user COMP. Use only when palette internals have been heavily customized.

Check and override programmatically: op.Embody.par.Tdxnpalettehandling = 'blackbox' | 'fullexport' | 'ask', or force a specific COMP: op('/path/to/comp').store('_tdn_palette_handling', 'fullexport').

TDXN Export - Locked Content

A TDXN export keeps the lock flag of a locked TOP, CHOP, SOP or POP but not its frozen data. Each export that writes a COMP's .tdxn file (externalize_op, save_externalization, or a save that re-exports a changed COMP) logs ONE WARNING per exported COMP (it rides back in _logs; an unchanged COMP at save time, autosave checkpoints and ad-hoc export_network snapshots of a tracked COMP skip it) listing path (FAMILY, source: none|unknown|recooks) and the exact remedy call. externalize_op, save_externalization, export_network, and the Autoexternalize step of create_op/copy_op/create_extension never show the locked-content dialog; execute_python code that calls Update or saveTDXN still can.

  • source: none: nothing wired in survives a rebuild. Never unlock it - unlocking leaves it empty.
  • source: unknown: the source was not traced (a parameter reference, mixed inputs, a large scan). It may have none: treat it as none.
  • source: recooks: unlocking re-cooks it, but the frozen snapshot is replaced, not restored. Unlock only when a fresh cook is acceptable.
  • To keep the data, run the externalize_op('<child COMP>', tag_type='tox') the WARNING names: that child is stored as a .tox and the parent .tdxn references it (tox_ref). In TD, the dialog's Switch to TOX button does the same.