@orderful/droid 0.47.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.claude-plugin/plugin.json +2 -0
  2. package/CHANGELOG.md +10 -0
  3. package/dist/tools/brain/.claude-plugin/plugin.json +1 -1
  4. package/dist/tools/brain/TOOL.yaml +1 -1
  5. package/dist/tools/brain/skills/brain/SKILL.md +3 -1
  6. package/dist/tools/brain/skills/brain/references/workflows.md +4 -2
  7. package/dist/tools/comments/.claude-plugin/plugin.json +1 -1
  8. package/dist/tools/comments/TOOL.yaml +1 -1
  9. package/dist/tools/comments/skills/comments/SKILL.md +14 -0
  10. package/dist/tools/excalidraw/.claude-plugin/plugin.json +22 -0
  11. package/dist/tools/excalidraw/TOOL.yaml +16 -0
  12. package/dist/tools/excalidraw/commands/excalidraw.md +34 -0
  13. package/dist/tools/excalidraw/skills/excalidraw/SKILL.md +100 -0
  14. package/dist/tools/excalidraw/skills/excalidraw/references/element-templates.md +336 -0
  15. package/dist/tools/excalidraw/skills/excalidraw/references/format-spec.md +102 -0
  16. package/dist/tools/plan/.claude-plugin/plugin.json +1 -1
  17. package/dist/tools/plan/TOOL.yaml +1 -1
  18. package/dist/tools/plan/skills/plan/SKILL.md +2 -0
  19. package/dist/tools/plan/skills/plan/references/workflows.md +11 -2
  20. package/package.json +1 -1
  21. package/src/tools/brain/.claude-plugin/plugin.json +1 -1
  22. package/src/tools/brain/TOOL.yaml +1 -1
  23. package/src/tools/brain/skills/brain/SKILL.md +3 -1
  24. package/src/tools/brain/skills/brain/references/workflows.md +4 -2
  25. package/src/tools/comments/.claude-plugin/plugin.json +1 -1
  26. package/src/tools/comments/TOOL.yaml +1 -1
  27. package/src/tools/comments/skills/comments/SKILL.md +14 -0
  28. package/src/tools/excalidraw/.claude-plugin/plugin.json +22 -0
  29. package/src/tools/excalidraw/TOOL.yaml +16 -0
  30. package/src/tools/excalidraw/commands/excalidraw.md +34 -0
  31. package/src/tools/excalidraw/skills/excalidraw/SKILL.md +100 -0
  32. package/src/tools/excalidraw/skills/excalidraw/references/element-templates.md +336 -0
  33. package/src/tools/excalidraw/skills/excalidraw/references/format-spec.md +102 -0
  34. package/src/tools/plan/.claude-plugin/plugin.json +1 -1
  35. package/src/tools/plan/TOOL.yaml +1 -1
  36. package/src/tools/plan/skills/plan/SKILL.md +2 -0
  37. package/src/tools/plan/skills/plan/references/workflows.md +11 -2
@@ -23,6 +23,7 @@
23
23
  "./src/tools/droid/skills/droid/SKILL.md",
24
24
  "./src/tools/droid/skills/droid-bootstrap/SKILL.md",
25
25
  "./src/tools/edi-schema/skills/edi-schema/SKILL.md",
26
+ "./src/tools/excalidraw/skills/excalidraw/SKILL.md",
26
27
  "./src/tools/meeting/skills/meeting/SKILL.md",
27
28
  "./src/tools/pii/skills/pii/SKILL.md",
28
29
  "./src/tools/plan/skills/plan/SKILL.md",
@@ -41,6 +42,7 @@
41
42
  "./src/tools/comments/commands/comments.md",
42
43
  "./src/tools/droid/commands/setup.md",
43
44
  "./src/tools/edi-schema/commands/edi-schema.md",
45
+ "./src/tools/excalidraw/commands/excalidraw.md",
44
46
  "./src/tools/meeting/commands/meeting.md",
45
47
  "./src/tools/pii/commands/pii.md",
46
48
  "./src/tools/plan/commands/plan.md",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @orderful/droid
2
2
 
3
+ ## 0.48.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#299](https://github.com/Orderful/droid/pull/299) [`2c8ba4b`](https://github.com/Orderful/droid/commit/2c8ba4b222330bf6ade9b1fc4e727fe750a70203) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add excalidraw tool for generating Excalidraw diagrams in Obsidian brain vault
8
+
9
+ ### Patch Changes
10
+
11
+ - [#300](https://github.com/Orderful/droid/pull/300) [`33b07c3`](https://github.com/Orderful/droid/commit/33b07c31ecc8f1d21661cc947e88a41555470206) Thanks [@frytyler](https://github.com/frytyler)! - Add --holistic flag to check commands (comments, brain, plan). When used, groups related comments into thematic clusters and responds cohesively instead of one-by-one, avoiding fractured responses when comments are part of the same train of thought.
12
+
3
13
  ## 0.47.0
4
14
 
5
15
  ### Minor Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "droid-brain",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Your scratchpad (or brain) - a collaborative space for planning and research. Create docs with /brain plan, /brain research, or /brain review. Use @mentions for async discussion. Docs persist across sessions.",
5
5
  "author": {
6
6
  "name": "Orderful",
@@ -1,6 +1,6 @@
1
1
  name: brain
2
2
  description: "Your scratchpad (or brain) - a collaborative space for planning and research. Create docs with /brain plan, /brain research, or /brain review. Use @mentions for async discussion. Docs persist across sessions."
3
- version: 0.4.1
3
+ version: 0.4.2
4
4
  status: beta
5
5
 
6
6
  includes:
@@ -121,10 +121,12 @@ Full procedure: `references/workflows.md` § Adding
121
121
 
122
122
  ## Checking Comments
123
123
 
124
- **Trigger:** `/brain check`
124
+ **Trigger:** `/brain check` or `/brain check --holistic`
125
125
 
126
126
  Find `> @droid` comments in active doc and address each. Preserve original comment, add response below with `> @{user_mention}`.
127
127
 
128
+ With `--holistic`: group related comments into thematic clusters and respond cohesively to each cluster instead of one-by-one. Unrelated comments still get individual responses. See `comments` skill for full holistic mode behaviour.
129
+
128
130
  Full procedure: `references/workflows.md` § Checking
129
131
 
130
132
  ## Cleaning Up Resolved Threads
@@ -150,9 +150,11 @@ Detailed procedures for each brain operation.
150
150
 
151
151
  ## Checking
152
152
 
153
- **Trigger:** `/brain check`
153
+ **Trigger:** `/brain check` or `/brain check --holistic`
154
154
 
155
- **Prefer `comments` skill:** If the `comments` skill is installed, use `/comments check` instead - it provides better comment detection, cleanup workflows, and supports the full `@droid`/`@user` convention. The workflow below is a fallback for basic comment handling.
155
+ **Prefer `comments` skill:** If the `comments` skill is installed, use `/comments check` (or `/comments check --holistic`) instead - it provides better comment detection, cleanup workflows, and supports the full `@droid`/`@user` convention. The workflow below is a fallback for basic comment handling.
156
+
157
+ **Holistic mode (`--holistic`):** Pass the flag through to the comments skill. If using the fallback workflow below, apply the same principle: after step 4 (finding all comments), group related comments into thematic clusters and respond cohesively to each cluster at the last comment in the group. Unrelated comments get individual responses as normal.
156
158
 
157
159
  **Directionality:** The @mention is the **target**, not the author:
158
160
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "droid-comments",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "Enable inline conversations using @droid/@user markers. Tag @droid to ask the AI, AI responds with @{your-name}. Use /comments check to address markers, /comments cleanup to remove resolved threads. Ideal for code review notes and async collaboration.",
5
5
  "author": {
6
6
  "name": "Orderful",
@@ -1,6 +1,6 @@
1
1
  name: comments
2
2
  description: "Enable inline conversations using @droid/@user markers. Tag @droid to ask the AI, AI responds with @{your-name}. Use /comments check to address markers, /comments cleanup to remove resolved threads. Ideal for code review notes and async collaboration."
3
- version: 0.3.6
3
+ version: 0.3.7
4
4
  status: beta
5
5
 
6
6
  includes:
@@ -82,6 +82,7 @@ When you find a `@droid` marker:
82
82
 
83
83
  - `/comments check` - Scan for AI markers and address each one
84
84
  - `/comments check {path}` - Scope to specific file or directory
85
+ - `/comments check --holistic` - Read all comments, then respond cohesively to related clusters
85
86
  - `/comments cleanup` - Find resolved comment threads and remove them
86
87
 
87
88
  ## Behavior
@@ -101,6 +102,8 @@ When you find a `@droid` marker:
101
102
 
102
103
  #### Pass 2: Respond & Write
103
104
 
105
+ **Default mode (no flag):** Respond to each comment individually, in order.
106
+
104
107
  1. For each comment, determine intent:
105
108
  - **Action request** ("do X", "add Y", "fix Z") → Execute the action
106
109
  - **Question** ("what do you think", "should we") → Respond with `> @{user_mention}`
@@ -109,6 +112,17 @@ When you find a `@droid` marker:
109
112
  - If `preserve_comments: true` → Keep the original `@droid` comment (add response below it)
110
113
  - If `preserve_comments: false` → Remove the original comment after addressing
111
114
 
115
+ **Holistic mode (`--holistic`):** Respond cohesively to related comments instead of one-by-one.
116
+
117
+ 1. **Group related comments** — identify thematic clusters (comments exploring the same question, building on each other, or pulling in different directions on the same topic). Comments that are unrelated stay standalone.
118
+ 2. **For each cluster of related comments:**
119
+ - Synthesize the thread of thought — what is the user working through?
120
+ - Respond once at the **last comment in the cluster** with a cohesive answer that addresses the whole group
121
+ - Earlier comments in the cluster get a brief forward-reference: `> @{user_mention} Addressed below with the related comments.`
122
+ - The synthesized response should feel like engaging with a complete idea, not stitching together fragments
123
+ 3. **For standalone (unrelated) comments:** Respond individually, same as default mode
124
+ 4. **Handle `preserve_comments`** the same as default mode
125
+
112
126
  ### On `/comments cleanup`:
113
127
 
114
128
  1. Find AI tag and `> @{user_mention}` pairs where conversation appears resolved
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "droid-excalidraw",
3
+ "version": "0.1.0",
4
+ "description": "Generate Excalidraw diagrams from conversation context and save them to your Obsidian brain vault. Requires brain tool configured, Obsidian, and the Excalidraw plugin.",
5
+ "author": {
6
+ "name": "Orderful",
7
+ "url": "https://github.com/orderful"
8
+ },
9
+ "repository": "https://github.com/orderful/droid",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "droid",
13
+ "ai",
14
+ "excalidraw"
15
+ ],
16
+ "skills": [
17
+ "./skills/excalidraw/SKILL.md"
18
+ ],
19
+ "commands": [
20
+ "./commands/excalidraw.md"
21
+ ]
22
+ }
@@ -0,0 +1,16 @@
1
+ name: excalidraw
2
+ description: "Generate Excalidraw diagrams from conversation context and save them to your Obsidian brain vault. Requires brain tool configured, Obsidian, and the Excalidraw plugin."
3
+ version: 0.1.0
4
+ status: experimental
5
+
6
+ includes:
7
+ skills:
8
+ - name: excalidraw
9
+ required: true
10
+ commands:
11
+ - name: excalidraw
12
+ is_alias: false
13
+ agents: []
14
+
15
+ dependencies:
16
+ - brain
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: excalidraw
3
+ description: "Generate Excalidraw diagrams in your Obsidian brain vault"
4
+ argument-hint: "[{description} | check]"
5
+ ---
6
+
7
+ # /excalidraw
8
+
9
+ **User invoked:** `/excalidraw $ARGUMENTS`
10
+
11
+ **Your task:** Invoke the **excalidraw skill** with these arguments.
12
+
13
+ ## Usage
14
+
15
+ ```
16
+ /excalidraw {description} # Generate a new diagram from context
17
+ /excalidraw check # Review changes in the active drawing
18
+ ```
19
+
20
+ ## Examples
21
+
22
+ - `/excalidraw flow chart of the auth system` → Generate an auth flow diagram
23
+ - `/excalidraw architecture for the orders service` → Generate a system architecture diagram
24
+ - `/excalidraw ER diagram for orders and products` → Generate an entity relationship diagram
25
+ - `/excalidraw check` → Read the active drawing and describe what's in it
26
+
27
+ ## Notes
28
+
29
+ - Diagrams are saved to your Obsidian brain vault as `.excalidraw.md` files
30
+ - Requires the brain tool configured with a `brain_dir`
31
+ - Requires Obsidian with the Excalidraw plugin installed
32
+ - See the **excalidraw skill** for complete documentation
33
+
34
+ **Reserved keywords:** `check`
@@ -0,0 +1,100 @@
1
+ ---
2
+ name: excalidraw
3
+ description: "Generate Excalidraw diagrams from conversation context and write them to the Obsidian brain vault. Use when user says 'draw this', 'diagram this flow', 'visualize this architecture', 'sketch this out', or '/excalidraw'. Also '/excalidraw check' to review changes in the active drawing."
4
+ argument-hint: "[{description} | check]"
5
+ allowed-tools: [Read, Write, Glob, Bash]
6
+ ---
7
+
8
+ # Excalidraw
9
+
10
+ Generate `.excalidraw.md` diagrams from conversation context — architecture diagrams, flow charts, system overviews, entity relationships. Files land in the brain vault and open directly in Obsidian's Excalidraw plugin.
11
+
12
+ ## Hard Dependencies
13
+
14
+ This tool requires **all three** of the following:
15
+
16
+ | Dependency | Why |
17
+ |-----------|-----|
18
+ | **brain tool configured** | Uses `brain_dir` for file placement |
19
+ | **Obsidian** | Files use `.excalidraw.md` — Obsidian-specific format |
20
+ | **Excalidraw plugin for Obsidian** | Required to render `.excalidraw.md` files |
21
+
22
+ **Dependency check (run first, every time):**
23
+
24
+ ```bash
25
+ droid config --get tools.brain
26
+ ```
27
+
28
+ Parse the JSON output. If `brain_dir` is missing or empty, **stop and inform the user:**
29
+
30
+ > The excalidraw tool requires the brain tool to be configured with a `brain_dir`. Run `droid config --set tools.brain.brain_dir=/path/to/vault` to configure it. You also need Obsidian with the Excalidraw plugin installed to open the generated files.
31
+
32
+ Do not proceed until `brain_dir` is confirmed.
33
+
34
+ ## Commands
35
+
36
+ **Reserved keywords:** `check`
37
+
38
+ | Command | Action |
39
+ |---------|--------|
40
+ | `/excalidraw {description}` | Generate a new diagram from conversation context |
41
+ | `/excalidraw check` | Review changes in the active drawing |
42
+
43
+ ## `/excalidraw {description}`
44
+
45
+ 1. **Check dependencies** — run `droid config --get tools.brain`, abort if `brain_dir` not set
46
+ 2. **Analyse context** — read the conversation to understand what to diagram. If unclear, ask what the user wants visualised
47
+ 3. **Pick a layout style** — flow chart, architecture, entity relationship, or concept map (see `references/element-templates.md` § Layout Styles)
48
+ 4. **Propose colour assignments** — before generating, present the user with a short table mapping each colour to a logical group in the diagram (e.g., "Blue = API services, Green = data stores, Orange = external systems"). Ask if they'd like to adjust. This ensures the legend is meaningful, not arbitrary.
49
+ 5. **Determine file placement:**
50
+ - If there's an active brain doc in the session, place the `.excalidraw.md` next to it (same directory, matching name prefix)
51
+ - Otherwise, place in `{brain_dir}/0-Inbox/diagrams/`
52
+ 6. **Create the target directory** if it doesn't exist:
53
+ ```bash
54
+ mkdir -p "{target_directory}"
55
+ ```
56
+ 7. **Generate the `.excalidraw.md` file** — see `references/format-spec.md` for the exact file format, `references/element-templates.md` for element JSON templates and the colour palette. **Always include a colour legend** in the bottom-left corner of the canvas (see `references/element-templates.md` § Colour Legend)
57
+ 8. **Write the file** using the Write tool
58
+ 9. **Emit an Obsidian link:**
59
+ ```
60
+ obsidian://open?vault={vault_name}&file={url-encoded-relative-path}
61
+ ```
62
+ Where `vault_name` = last path component of `brain_dir` (strip trailing slashes), and `relative_path` is the file path relative to `brain_dir`.
63
+
64
+ ## `/excalidraw check`
65
+
66
+ 1. **Find the active drawing** — the most recently discussed or generated `.excalidraw.md` file in the session. If none, search `{brain_dir}` for recently modified `.excalidraw.md` files and ask which one
67
+ 2. **Read the file** using the Read tool and parse the JSON from the `%%` block (that's the plugin's working copy)
68
+ 3. **Extract all elements** and build a mental model of the diagram:
69
+ - List all boxes/rectangles with their text content and colours
70
+ - List all arrows and what they connect
71
+ - List all standalone text labels
72
+ - Note spatial grouping (what's near what)
73
+ 4. **Summarise what you see** — describe the diagram in plain language
74
+ 5. **If you generated the original:** compare against what you wrote and call out what the user added, moved, removed, or changed
75
+ 6. **Offer next steps:** add more elements, reflect changes into a brain doc, or flesh out specific elements
76
+
77
+ **Tips for Check:**
78
+ - Focus on content and relationships, not pixel positions
79
+ - Call out new elements by name: "You added a 'Redis Cache' box between the API and DB"
80
+ - If the user added sticky notes, treat them like comments — respond to them
81
+ - If the diagram diverged significantly, offer to regenerate with the new structure as baseline
82
+
83
+ ## File Placement Rules
84
+
85
+ | Situation | Target directory |
86
+ |-----------|-----------------|
87
+ | Active brain doc in session | Same directory as the brain doc |
88
+ | No active brain doc | `{brain_dir}/0-Inbox/diagrams/` |
89
+
90
+ File name: use a kebab-case slug from the diagram description (e.g., `auth-flow.excalidraw.md`).
91
+
92
+ ## When NOT to Use
93
+
94
+ - User wants a polished presentation diagram (suggest FigJam/Figma instead)
95
+ - Simple lists or tables that don't benefit from spatial layout
96
+
97
+ ## Reference Files
98
+
99
+ - `references/format-spec.md` — `.excalidraw.md` file format specification
100
+ - `references/element-templates.md` — Element JSON templates, colour palette, sizing guidelines
@@ -0,0 +1,336 @@
1
+ # Element Templates and Colour Palette
2
+
3
+ ## Common Properties (all elements)
4
+
5
+ Every element must include these fields:
6
+
7
+ ```json
8
+ {
9
+ "version": 1,
10
+ "seed": 1,
11
+ "versionNonce": 1,
12
+ "index": "a0",
13
+ "isDeleted": false,
14
+ "updated": 1,
15
+ "link": null,
16
+ "locked": false,
17
+ "groupIds": [],
18
+ "boundElements": [],
19
+ "strokeStyle": "solid",
20
+ "frameId": null,
21
+ "opacity": 100,
22
+ "angle": 0,
23
+ "roughness": 1
24
+ }
25
+ ```
26
+
27
+ **Element ID convention:** Increment `index` for each element: `"a0"`, `"a1"`, `"a2"`, etc. Use short unique alphanumeric strings for `id` fields (e.g., `"box_api"`, `"text_api"`, `"arrow_api_db"`).
28
+
29
+ ## Rectangle (container)
30
+
31
+ ```json
32
+ {
33
+ "type": "rectangle",
34
+ "id": "box_unique_id",
35
+ "x": 0, "y": 0,
36
+ "width": 260, "height": 120,
37
+ "strokeColor": "#1e1e1e",
38
+ "backgroundColor": "#d0ebff",
39
+ "fillStyle": "solid",
40
+ "strokeWidth": 2,
41
+ "roundness": { "type": 3 },
42
+ "boundElements": [
43
+ { "type": "text", "id": "text_for_this_box" }
44
+ ],
45
+ "version": 1,
46
+ "seed": 1,
47
+ "versionNonce": 1,
48
+ "index": "a0",
49
+ "isDeleted": false,
50
+ "updated": 1,
51
+ "link": null,
52
+ "locked": false,
53
+ "groupIds": [],
54
+ "strokeStyle": "solid",
55
+ "frameId": null,
56
+ "opacity": 100,
57
+ "angle": 0,
58
+ "roughness": 1
59
+ }
60
+ ```
61
+
62
+ ## Text (bound to container)
63
+
64
+ Bound text lives inside a rectangle. The `containerId` on the text and the matching `boundElements` on the rectangle must reference each other.
65
+
66
+ ```json
67
+ {
68
+ "type": "text",
69
+ "id": "text_for_this_box",
70
+ "x": 10, "y": 10,
71
+ "width": 240, "height": 100,
72
+ "text": "Service Name\n\nHandles auth\nManages sessions",
73
+ "fontSize": 16,
74
+ "fontFamily": 1,
75
+ "textAlign": "center",
76
+ "verticalAlign": "middle",
77
+ "strokeColor": "#1e1e1e",
78
+ "backgroundColor": "transparent",
79
+ "fillStyle": "solid",
80
+ "strokeWidth": 1,
81
+ "containerId": "box_unique_id",
82
+ "originalText": "Service Name\n\nHandles auth\nManages sessions",
83
+ "autoResize": true,
84
+ "lineHeight": 1.25,
85
+ "hasTextLink": false,
86
+ "rawText": "",
87
+ "version": 1,
88
+ "seed": 1,
89
+ "versionNonce": 1,
90
+ "index": "a1",
91
+ "isDeleted": false,
92
+ "updated": 1,
93
+ "link": null,
94
+ "locked": false,
95
+ "groupIds": [],
96
+ "boundElements": [],
97
+ "strokeStyle": "solid",
98
+ "frameId": null,
99
+ "opacity": 100,
100
+ "angle": 0,
101
+ "roughness": 1
102
+ }
103
+ ```
104
+
105
+ ## Text (standalone — titles, labels)
106
+
107
+ Same as bound text but with `"containerId": null` and no parent rectangle reference.
108
+
109
+ ```json
110
+ {
111
+ "type": "text",
112
+ "id": "title_text",
113
+ "x": 100, "y": 20,
114
+ "width": 400, "height": 40,
115
+ "text": "My Architecture Diagram",
116
+ "fontSize": 28,
117
+ "fontFamily": 1,
118
+ "textAlign": "center",
119
+ "verticalAlign": "middle",
120
+ "strokeColor": "#1e1e1e",
121
+ "backgroundColor": "transparent",
122
+ "fillStyle": "solid",
123
+ "strokeWidth": 1,
124
+ "containerId": null,
125
+ "originalText": "My Architecture Diagram",
126
+ "autoResize": true,
127
+ "lineHeight": 1.25,
128
+ "hasTextLink": false,
129
+ "rawText": "",
130
+ "version": 1,
131
+ "seed": 1,
132
+ "versionNonce": 1,
133
+ "index": "a0",
134
+ "isDeleted": false,
135
+ "updated": 1,
136
+ "link": null,
137
+ "locked": false,
138
+ "groupIds": [],
139
+ "boundElements": [],
140
+ "strokeStyle": "solid",
141
+ "frameId": null,
142
+ "opacity": 100,
143
+ "angle": 0,
144
+ "roughness": 1
145
+ }
146
+ ```
147
+
148
+ ## Arrow
149
+
150
+ For connected arrows, `startBinding` and `endBinding` must reference the source and target element IDs. The `points` array defines the arrow path relative to the arrow's `x`/`y` origin.
151
+
152
+ ```json
153
+ {
154
+ "type": "arrow",
155
+ "id": "arrow_unique_id",
156
+ "x": 260, "y": 60,
157
+ "width": 80, "height": 0,
158
+ "strokeColor": "#868e96",
159
+ "backgroundColor": "transparent",
160
+ "fillStyle": "solid",
161
+ "strokeWidth": 2,
162
+ "roundness": { "type": 2 },
163
+ "startBinding": { "elementId": "source_box_id", "focus": 0, "gap": 5 },
164
+ "endBinding": { "elementId": "target_box_id", "focus": 0, "gap": 5 },
165
+ "startArrowhead": null,
166
+ "endArrowhead": "arrow",
167
+ "points": [[0, 0], [80, 0]],
168
+ "version": 1,
169
+ "seed": 1,
170
+ "versionNonce": 1,
171
+ "index": "a3",
172
+ "isDeleted": false,
173
+ "updated": 1,
174
+ "link": null,
175
+ "locked": false,
176
+ "groupIds": [],
177
+ "boundElements": [],
178
+ "strokeStyle": "solid",
179
+ "frameId": null,
180
+ "opacity": 100,
181
+ "angle": 0,
182
+ "roughness": 1
183
+ }
184
+ ```
185
+
186
+ For vertical arrows, adjust `height` instead of `width` and set points accordingly (e.g., `[[0, 0], [0, 80]]`).
187
+
188
+ ## Sticky Note
189
+
190
+ A sticky note is a rectangle with bound text that auto-resizes to fit content. Useful for annotations, callouts, and concept maps.
191
+
192
+ ```json
193
+ {
194
+ "type": "rectangle",
195
+ "id": "note_unique_id",
196
+ "x": 0, "y": 0,
197
+ "width": 200, "height": 80,
198
+ "strokeColor": "#e8590c",
199
+ "backgroundColor": "#ffe8cc",
200
+ "fillStyle": "solid",
201
+ "strokeWidth": 1,
202
+ "roundness": { "type": 3 },
203
+ "customData": { "legacyTextWrap": true },
204
+ "boundElements": [
205
+ { "type": "text", "id": "note_text_id" }
206
+ ],
207
+ "version": 1,
208
+ "seed": 1,
209
+ "versionNonce": 1,
210
+ "index": "a4",
211
+ "isDeleted": false,
212
+ "updated": 1,
213
+ "link": null,
214
+ "locked": false,
215
+ "groupIds": [],
216
+ "strokeStyle": "solid",
217
+ "frameId": null,
218
+ "opacity": 100,
219
+ "angle": 0,
220
+ "roughness": 1
221
+ }
222
+ ```
223
+
224
+ With matching bound text (same pattern as bound text above, with `"containerId": "note_unique_id"`).
225
+
226
+ ## Colour Palette
227
+
228
+ Use Excalidraw's built-in colours for consistency:
229
+
230
+ | Purpose | `strokeColor` | `backgroundColor` |
231
+ |---------|--------------|------------------|
232
+ | Primary / highlighted | `#2f9e44` | `#b2f2bb` (green) |
233
+ | Secondary | `#1971c2` | `#d0ebff` (blue) |
234
+ | Tertiary | `#e8590c` | `#ffe8cc` (orange) |
235
+ | Neutral / supporting | `#868e96` | `#e9ecef` (grey) |
236
+ | Warning / attention | `#e03131` | `#ffc9c9` (red) |
237
+ | Purple / alternate | `#6741d9` | `#d0bfff` (purple) |
238
+ | Labels / arrows | `#868e96` | `transparent` |
239
+ | Title text | `#1e1e1e` | `transparent` |
240
+
241
+ **Colour grouping rule:** Use one colour per logical group (e.g., all API services blue, all data stores green). Before generating, propose the colour assignments to the user so they can adjust. This ensures the legend is meaningful, not arbitrary.
242
+
243
+ ## Colour Legend
244
+
245
+ **Every diagram must include a colour legend.** Place it in the bottom-left corner of the canvas, below and to the left of the main diagram content.
246
+
247
+ The legend is a vertical stack of small colour swatches (rectangles) with labels explaining what each colour represents in this specific diagram. Only include colours that are actually used.
248
+
249
+ ```
250
+ ┌──────────────────┐
251
+ │ Legend │ ← title text (fontSize: 16, bold)
252
+ │ │
253
+ │ ■ API Services │ ← small coloured rectangle + label
254
+ │ ■ Data Stores │
255
+ │ ■ External │
256
+ │ ■ Infrastructure │
257
+ └──────────────────┘
258
+ ```
259
+
260
+ **Implementation:** Use a group of elements:
261
+ - One standalone title text element ("Legend", fontSize: 16)
262
+ - For each colour: a small rectangle (30x20px) + standalone text label to its right
263
+ - Stack vertically with 8px gap between rows
264
+ - Position below the main diagram content with ~60px margin
265
+
266
+ Example swatch element:
267
+ ```json
268
+ {
269
+ "type": "rectangle",
270
+ "id": "legend_swatch_blue",
271
+ "x": 100, "y": 600,
272
+ "width": 30, "height": 20,
273
+ "strokeColor": "#1971c2",
274
+ "backgroundColor": "#d0ebff",
275
+ "fillStyle": "solid",
276
+ "strokeWidth": 1,
277
+ "roundness": { "type": 3 }
278
+ }
279
+ ```
280
+
281
+ With a matching label:
282
+ ```json
283
+ {
284
+ "type": "text",
285
+ "id": "legend_label_blue",
286
+ "x": 140, "y": 600,
287
+ "width": 120, "height": 20,
288
+ "text": "API Services",
289
+ "fontSize": 14,
290
+ "fontFamily": 1,
291
+ "textAlign": "left",
292
+ "verticalAlign": "middle",
293
+ "strokeColor": "#1e1e1e",
294
+ "backgroundColor": "transparent",
295
+ "containerId": null
296
+ }
297
+ ```
298
+
299
+ Repeat for each colour used in the diagram, incrementing y by 28px per row.
300
+
301
+ ## Sizing Guidelines
302
+
303
+ | Element | Recommended size |
304
+ |---------|-----------------|
305
+ | Box width | 200–300px (varies by text length) |
306
+ | Box height | 80–160px (varies by content lines) |
307
+ | Horizontal gap between boxes | 80–120px |
308
+ | Vertical gap between rows | 60–100px |
309
+ | Title font size | 28 |
310
+ | Box text font size | 16–20 |
311
+ | Label font size | 14 |
312
+
313
+ **Text width estimate:** ~8px per character at `fontSize: 16`
314
+
315
+ **Arrow labels:** Place as standalone text near the arrow midpoint.
316
+
317
+ ## Layout Style Guidance
318
+
319
+ ### Flow Chart
320
+ For processes, workflows, request lifecycles. Arrange top-to-bottom or left-to-right with directional arrows. Each step is a box; decisions can use diamond shapes (rotated rectangles).
321
+
322
+ ### Architecture Diagram
323
+ For system components, services, layers. Use grouped boxes with labels, arrows showing data flow between services. Group related services with a larger background rectangle.
324
+
325
+ ### Entity Relationship
326
+ For data models, schemas, relationships. Boxes represent entities with field lists inside. Lines (not arrows) show relationships; label the line with cardinality (1:N, etc.).
327
+
328
+ ### Concept Map
329
+ For brainstorming, exploring ideas. Loose arrangement, grouped by theme. Connecting lines with labels, sticky notes for annotations. Less rigid than a flow chart.
330
+
331
+ ## Tips
332
+
333
+ - Keep text concise — bullet points over paragraphs
334
+ - Add a title text element at the top of the canvas
335
+ - For large diagrams, organise in clear rows/columns — the user can rearrange in Excalidraw
336
+ - Start elements at coordinates (100, 100) or higher to leave canvas margin