<< All versions

Skill v1.0.0

currentAutomated scan100/100
sanieldoe/companions/canvas-builder
──Details
PublishedOctober 24, 2026 at 08:55 AM
Content Hashsha256:361d21f93d579843...
Git SHA146a604b63f2
──Files
Files (1 file, 4.2 KB)
SKILL.md4.2 KBactive
SKILL.md · 84 lines · 4.2 KB

version: "1.0.0" name: canvas-builder description: Teaches agents how to output structured canvas definitions for the Shapeshifter tab


Reading the Current Canvas

The canvas is a file in the vault. Before updating, always read it first:

  • Path: projects/<current-project-slug>/canvas.json
  • Use the read tool to load it, then emit the full updated canvas with your changes merged in.
  • If the file doesn't exist yet, start fresh.

Critical Rules

  • Output <canvas> as a raw tag — never inside backticks or code fences.
  • Put <canvas> at the END of your response, after all conversational text.
  • Always include ALL existing blocks — the full canvas replaces the previous one. Never drop blocks the user hasn't removed.
  • IDs are short and stable: b1, b2, b3 for blocks; t1, t2 for task items.

When to Emit a Canvas

  • User asks to add something to their canvas or Shapeshifter tab.
  • You produce a plan, outline, checklist, or structured artifact worth persisting.
  • A key decision, reference, or resource should stay permanently visible.
  • The project's scope or status changes meaningfully.

Output Format

<canvas> { "blocks": [ { "id": "b1", "type": "markdown", "content": "# Title\n\nOne-line description." }, { "id": "b2", "type": "tasks", "title": "Next steps", "items": [ { "id": "t1", "text": "Do the thing", "done": false } ]}, { "id": "b3", "type": "note", "title": "Key insight", "content": "Main idea.", "color": "amber" } ] } </canvas>

Block Types

This is a fixed block system — 10 types total. You cannot render arbitrary UI; compose these blocks to represent any content.

typerequired fieldsoptional fieldsvisual
markdowncontent—Rich text with headers, bold, lists, inline code
tasksitems ({id, text, done})titleInteractive checklist with tap-to-toggle checkboxes
notecontenttitle, color (amber/blue/green/red)Coloured left-border callout box
linksitems ({id, label, url})titleList of labelled URL rows
codecontentlanguage, titleDark-background code block with optional language label
section—labelHorizontal divider with optional centred label
button—label, content, action ('chat'/'file'), file (vault path)Tappable CTA; opens chat (default) or a vault file
filetabstabs ({id, label, file})—Tab strip that loads different vault files per tab
input—titleMulti-line text field the user can type into; content saved back to canvas
htmlcontent (complete HTML string)height (px, omit to auto-size)Sandboxed WebView — renders arbitrary HTML/CSS/JS inline

input block note: Omit content when creating — the app fills it in as the user types. Schema: { "id": "b1", "type": "input", "title": "Optional label" }

html block note: Write complete, self-contained HTML — all CSS in <style> tags, all JS in <script> tags, no external CDN links. Omit height to let the app measure automatically. Use for charts, tables, custom layouts, or anything the other block types can't express.

Example — Talk Prep Canvas

Your conversational reply goes here, then immediately after:

<canvas> { "blocks": [ { "id": "b1", "type": "markdown", "content": "# Friend Zone Talk\n\nOne point: Real friendship requires risk.\n\nKey phrase: You can't stay safe and stay close at the same time." }, { "id": "b2", "type": "tasks", "title": "Prep checklist", "items": [ { "id": "t1", "text": "Write the ME opening story", "done": false }, { "id": "t2", "text": "Find the WE illustration", "done": false }, { "id": "t3", "text": "Memorise the key phrase", "done": false } ]}, { "id": "b3", "type": "note", "title": "Opening tension", "content": "Everyone wants deep friendship. Almost nobody risks the vulnerability it requires.", "color": "blue" } ] } </canvas>

Composition Note

This is a fixed block system with 10 types. Agents cannot render arbitrary UI — only compose these blocks. Any content that doesn't fit a block type should be expressed as markdown.

All versions