AgentSkillsCN

canvas-gen

从 beads 问题中生成 Obsidian Canvas 文件。使用方法:/canvas-gen [epic-id]

SKILL.md
--- frontmatter
name: canvas-gen
version: 1.0.0
description: "Generate Obsidian Canvas files from beads issues. Use: /canvas-gen [epic-id]"
allowed-tools: [Bash, Read, Write, Glob]
lifecycle:
  status: active
  created_at: "2026-01-26"

/canvas-gen — Canvas Generation from Beads

TL;DR: Auto-generate Obsidian Canvas files from beads issues for visual task tracking.


Usage

code
/canvas-gen                   # Generate from all in-progress issues
/canvas-gen <epic-id>         # Generate from specific epic
/canvas-gen --template=work   # Use work session template
/canvas-gen --output=<name>   # Custom output filename

Canvas Types

TemplateUse CaseStructure
workActive work sessionEpic → Tasks → Subtasks
hierarchySkill/agent overviewLayers with relationships
timelineSprint/week viewDate-ordered columns

Execution

code
1. PARSE input:
   epic_id = PARSE argument (optional)
   template = PARSE --template flag (default: "work")
   output_name = PARSE --output flag (default: auto-generated)

2. FETCH beads data:
   IF epic_id:
       issues = Bash("bd show {epic_id} --format=json")
       children = Bash("bd list --parent={epic_id} --format=json")
   ELSE:
       issues = Bash("bd list --status=in_progress --format=json")

3. GENERATE canvas structure:
   canvas = {
       nodes: [],
       edges: []
   }

   # Layout constants
   NODE_WIDTH = 250
   NODE_HEIGHT = 60
   COLUMN_GAP = 300
   ROW_GAP = 100

   # Position tracking
   x_offset = 0
   y_offset = 0

   # Generate nodes by status
   FOR EACH status IN ["in_progress", "blocked", "pending", "completed"]:
       status_issues = issues.filter(i => i.status == status)
       column_y = 0

       FOR EACH issue IN status_issues:
           node = {
               id: issue.id,
               type: "text",
               x: x_offset,
               y: column_y,
               width: NODE_WIDTH,
               height: NODE_HEIGHT,
               text: FORMAT_NODE_TEXT(issue),
               color: STATUS_COLOR(status)
           }
           canvas.nodes.push(node)
           column_y += ROW_GAP

       x_offset += COLUMN_GAP

4. GENERATE edges (dependencies):
   FOR EACH issue IN issues:
       IF issue.blocked_by:
           FOR EACH blocker_id IN issue.blocked_by:
               edge = {
                   id: GENERATE_ID(),
                   fromNode: blocker_id,
                   toNode: issue.id,
                   fromSide: "right",
                   toSide: "left"
               }
               canvas.edges.push(edge)

5. FORMAT_NODE_TEXT(issue):
   RETURN "**{issue.id}**\n{issue.title}\n_{issue.status}_"

6. STATUS_COLOR(status):
   MATCH status:
       "in_progress" → "5"  # Purple
       "blocked"     → "1"  # Red
       "pending"     → "4"  # Yellow
       "completed"   → "4"  # Green (using yellow, no green in Obsidian)
   DEFAULT → "0"

7. WRITE canvas file:
   IF output_name:
       filename = output_name + ".canvas"
   ELSE:
       filename = "beads-" + DATE + ".canvas"

   filepath = "obsidian-vault/canvas/" + filename
   Write(filepath, JSON.stringify(canvas, null, 2))

8. OUTPUT confirmation:
   OUTPUT "✅ Canvas generated: {filepath}"
   OUTPUT "Nodes: {canvas.nodes.length} | Edges: {canvas.edges.length}"
   OUTPUT "Open in Obsidian to view"

Output Format

Canvas JSON Structure

json
{
  "nodes": [
    {
      "id": "beads-abc",
      "type": "text",
      "x": 0,
      "y": 0,
      "width": 250,
      "height": 60,
      "text": "**beads-abc**\nImplement feature X\n_in_progress_",
      "color": "5"
    }
  ],
  "edges": [
    {
      "id": "edge-1",
      "fromNode": "beads-xyz",
      "toNode": "beads-abc",
      "fromSide": "right",
      "toSide": "left"
    }
  ]
}

Color Reference

Obsidian Canvas colors:

Color CodeColorUse For
"0"Default-
"1"RedBlocked
"2"OrangePriority
"3"YellowPending
"4"GreenCompleted
"5"CyanIn Progress
"6"PurpleEpic

Integration

With /retro

After /retro extracts entities, /canvas-gen can visualize:

  • Skills used → nodes
  • Agents spawned → child nodes
  • Dependencies → edges

With /next

/next shows ready issues; /canvas-gen can highlight them in canvas view.


Examples

Example 1: Current Work

code
/canvas-gen

✅ Canvas generated: obsidian-vault/canvas/beads-2026-01-26.canvas
Nodes: 5 | Edges: 2
Open in Obsidian to view

Example 2: Specific Epic

code
/canvas-gen beads-epic-001

✅ Canvas generated: obsidian-vault/canvas/epic-001.canvas
Nodes: 8 | Edges: 5
Epic: "MVP Implementation" with 7 child issues

Error Handling

ConditionRecovery
No beads issues foundOutput empty canvas with note
bd command failsFallback to reading .beads/issues.jsonl
Invalid epic IDWarn and show available epics

Notes

  • Canvas files are JSON, git-tracked
  • Regenerate anytime — canvas reflects current beads state
  • Manual edits to canvas preserved if regenerating with different filename
  • Use --output to avoid overwriting custom layouts