| name | canvas-comments |
| description | Use when a Fused canvas.toml contains (or needs) a [[comments]] block — e.g. the user asks to check/fix/resolve canvas comments, review feedback pins on a canvas, or leave comments on a canvas for someone else. Covers reading, writing, and resolving comments via the fused CLI pull/push workflow. |
Fused canvas comments ([[comments]] in canvas.toml)
Pinned comment threads on a Fused canvas serialize as top-level [[comments]] blocks in canvas.toml. Comments with status = "open" are your work queue; resolving one is a three-field contract plus a reply, so the Workbench UI correctly attributes the work to AI.
Read: find the work
- Get the canvas locally:
fused workbench canvas pull <name> -o <dir> (or use the folder you have).
- Every
[[comments]] block where status = "open" is an actionable request.
anchor_udf = "<udfName>" tells you WHICH node it's about — the fix belongs in <udfName>.py (or .json/.md/.html with that stem). No anchor_udf ⇒ canvas-level comment; read content for scope.
Resolve: the full contract (all four steps, not just status)
After actually making the fix the comment asks for:
[[comments]]
id = "cmt-a"
status = "resolved"
resolved_by = "ai"
resolved_at = 1749600200000
[[comments.replies]]
id = "reply-<unique>"
content = "Changed the default to 7. Done."
created_at = 1749600200000
created_by = "ai"
Setting only status = "resolved" is wrong — without resolved_by = "ai" the UI cannot attribute the resolution, and without a reply the user doesn't know what changed.
Write: adding a new comment
[[comments]]
id = "cmt-<unique>"
x = 120.0
y = 80.0
anchor_udf = "process_data"
offset_x = 24.0
offset_y = 16.0
content = "non-empty text"
status = "open"
created_by = "ai"
created_at = 1749600000000
Field reference (snake_case in TOML — never camelCase)
| Field | Notes |
|---|
id, content, x, y | required; blank/whitespace content ⇒ row dropped on parse |
status | open | resolving | resolved; omitted ⇒ open |
anchor_udf, offset_x, offset_y | anchor by UDF name, not node id; unknown name ⇒ anchor silently dropped |
created_by, resolved_by | "user" | "ai"; omitted = user |
created_at, updated_at, resolved_at | ms epoch integers |
replies | [[comments.replies]] with id, content, created_at, optional updated_at, created_by |
Never write a TOML null/empty value — omit absent fields entirely. Comments sort by created_at on export; don't reorder blocks by hand.
Verify, then push
fused workbench canvas validate <dir>
fused workbench canvas push <dir> --canvas <name>
Common mistakes
- Resolving without
resolved_by = "ai" / resolved_at / a reply (the #1 miss).
- camelCase keys (
createdAt) in TOML — the parser ignores them; data silently lost.
- Anchoring by node id instead of
anchor_udf name.
- Marking
resolved without actually making the code change the comment asks for.
- Editing/deleting other people's
ids or created_ats — append, don't rewrite history.