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

dylanroscover / manage-annotations

MUST READ before creating, modifying, or querying annotations. Contains parameter names, coordinate model, and API quirks.

0
SKILL.md
4.5 KB

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

Manage Annotations Workflow

Creating Annotations

create_annotation(
    parent_path='/path/to/network',
    mode='annotate',     # 'annotate' (title bar), 'comment', or 'networkbox'
    title='My Group',
    text='Description of this group',
    x=..., y=..., width=..., height=...,
    color=[r, g, b],     # Optional, floats 0-1
    opacity=0.5           # Optional
)

Always favor annotations over OP comments for documenting operators or groups.

Enclosing Operators

To create an annotation that encloses a group of operators:

  1. Get positions: get_network_layout on the parent COMP (includes all operator positions and bounding box)
  2. Calculate bounding box: Find min_x, max_x, min_y, max_y (max includes operator width/height: max_x = max(op_x + op_w), max_y = max(op_y + op_h))
  3. Add padding: 70 units on left/right/bottom, 170 units on top (title bar + body text)
  4. Set coordinates:

    • nodeX = min_x - 70
    • nodeY = min_y - 70 (BELOW operators, not above!)
    • nodeWidth = max_x - min_x + 140
    • nodeHeight = max_y - min_y + 240 (70 bottom + 170 top)

Coordinate Model

  • nodeX/nodeY = bottom-left corner, width/height extend rightward and upward
  • Title bar renders at the top of the rectangle
  • Common mistake: Setting nodeY above the operators. nodeY must be BELOW (less than) the lowest operator's Y.

Querying

  • get_annotations - list all annotations in a COMP with properties and enclosed operators
  • get_enclosed_ops - get operators enclosed by an annotation, or annotations enclosing an operator
  • set_annotation - modify text, title, color, opacity, position, or size

Deleting Annotations

Delete via delete_op, never via raw .destroy() in execute_python.
delete_op resolves utility annotations, purges any tracking, and arms an
auto-save checkpoint that re-exports the parent TDXN COMP's .tdxn without
the annotation -- the deletion is durable. A raw .destroy() leaves the
stale annotations: entry in the parent's .tdxn on disk, and the next
reimport of that COMP (import_network, manager Reload, or cold open)
resurrects the annotation with its pre-delete text.

annotateCOMP Quirks

  • utility is True for every annotation -- TD UI-drawn ones are born
    that way, create_annotation sets it, and TDXN import applies it on every
    annotation it recreates. (A bare Python parent.create('annotateCOMP')
    is utility=False -- set ann.utility = True immediately to match; a
    non-utility annotation is an ordinary COMP subtree that enumeration
    sweeps will walk into.)

  • **utility=True hides the op from op(), parent.op(), AND
    .children** -- only findChildren(includeUtility=True) sees it, and a
    deep findChildren does not even DESCEND into a utility annotate's
    subtree unless includeUtility=True is passed (verified live, TD
    2025.33070). Paths THROUGH a utility annotate to its interior ops still
    resolve via op().

  • Every Envoy op-path tool resolves utility annotations (delete_op,
    set_parameter, set_op_position, get_op, ... -- they share one
    utility-aware resolver). For DISCOVERY, use get_annotations (always
    sees them) or pass include_utility=True to
    query_network/find_children -- with the default False, annotations
    are invisible in those listings.

  • Annotations are never externalized per-op -- they round-trip through
    the parent TDXN COMP's semantic annotations: section. externalize_op
    refuses them, and tagging sweeps skip them and their internals (the
    widget internals are TD-managed stock content cloned from TDAnnotate).

  • envoy_bot_* is reserved for Embot, the mascot Envoy stands on the
    operator it is working on (the Embot parameter). The read tools hide
    those parts and report how many as embot_hidden; Embody strips them
    from every saved file and deletes loose ones on save. Never create,
    move, edit or delete an annotation with that prefix -- and never name
    one of yours that way, or it will be deleted as an artifact.

  • .type returns 'annotate' (not 'annotateCOMP')
  • findChildren(type=annotateCOMP) requires the class object, not the string
  • Cannot be reliably renamed after creation (TD also ignores a name passed
    at create time -- rename right after creating instead)