Install
openclaw skills install excaliclawCreate reliable Excalidraw diagrams in OpenClaw using the Excalidraw MCP, with export-safe labels, Excalifont text, and clear system-diagram structure. Use when the user asks for an Excalidraw diagram, architecture diagram, system diagram, flowchart, or hand-drawn diagram.
openclaw skills install excaliclawCreate diagrams with the Excalidraw MCP in a way that survives OpenClaw rendering and Excalidraw export.
Use real Excalidraw elements, but do not rely on MCP label shortcuts for final diagrams.
Before creating or exporting a diagram, verify that the Excalidraw MCP tools are available in the current OpenClaw session.
Expected behavior:
Do not silently auto-install the MCP just because a diagram was requested. Installing an MCP is an environment change and needs explicit user approval unless the user already asked to set it up.
Reliable pattern:
Mandatory workflow for normal diagram requests:
excalidraw__create_view to render the diagram preview first as an internal quality gate. Do not skip the preview and jump straight to export unless the user explicitly asks for JSON-only or link-only output.create_view returns a checkpoint id, treat it as evidence of the previewed scene. Preserve the same elements and relationships when constructing the export payload.type: "excalidraw", version, source, elements, appState, and files.Element construction pattern:
text element for the label.containerId on the text + matching { "type": "text", "id": ... } in the shape's boundElements). This is mandatory for editable box labels unless preview/export proves it broken.startBinding and endBinding; route around labels if needed. Do not bind arrows that merely point into a lane, group, or general area without targeting a specific box.{ "type": "arrow", "id": ... } entries in both connected shapes' boundElements.read_me examples use simpler arrows. If an arrow would be expected to follow a box when moved, it must be bound in both preview and export.fontFamily: 1 on every text element to use Excalidraw's hand-drawn Excalifont.width and height on every text element.containerId, shape boundElements, and arrow startBinding/endBinding. Do not flatten bound labels or connected arrows into loose visual text/lines during export.startBinding, endBinding, and matching reciprocal arrow entries in both endpoint shapes' boundElements.Best default for editable diagrams: bind the text to the rectangle so Excalidraw treats it as the box label when the user drags or edits the box.
[
{
"type": "rectangle",
"id": "box-api",
"x": 100,
"y": 100,
"width": 180,
"height": 70,
"backgroundColor": "#d0bfff",
"fillStyle": "solid",
"roundness": { "type": 3 },
"strokeColor": "#8b5cf6",
"boundElements": [{ "type": "text", "id": "txt-api" }]
},
{
"type": "text",
"id": "txt-api",
"x": 130,
"y": 123,
"width": 120,
"height": 24,
"text": "API Server",
"fontSize": 16,
"fontFamily": 1,
"strokeColor": "#1e1e1e",
"containerId": "box-api",
"textAlign": "center",
"verticalAlign": "middle"
}
]
If bound container text fails in MCP preview or export, fall back to the same explicit text element without containerId/boundElements. Keep the label visually centered, but tell the user it may not move with the box. Do not silently fall back.
Avoid this shortcut for final deliverables:
{
"type": "rectangle",
"id": "api",
"label": { "text": "API Server" }
}
The label shortcut may look convenient, but it has proven flaky in OpenClaw/Excalidraw MCP export paths. Do not use shortcut labels in either preview or export payloads for final deliverables; otherwise exported diagrams can appear correct while losing editability.
Bind based on meaning, not just appearance. When an arrow means “this step talks to that specific step/box,” bind the endpoints to the source and target boxes. This lets Excalidraw keep the arrow attached when the user moves either box.
For arrow binding to survive editing/export, include both sides of the relationship:
startBinding and endBinding with the connected shape IDs.boundElements entry for the arrow.Prefer simple straight bound arrows first. Avoid multi-segment/elbow bound arrows unless you verify they render and remain editable correctly; they can look warped or appear unbound in Excalidraw exports. If labels or spacing make the connection awkward, fix the layout by moving boxes/labels before adding complex arrow routing.
Do not bind arrows that only point into a lane, group, note area, or nearby whitespace. For example, in swim lane diagrams, an arrow may leave one box and point generally into another lane before the next step appears; that should remain a visually positioned arrow, not a box-bound connector.
[
{
"type": "rectangle",
"id": "box-client",
"x": 100,
"y": 100,
"width": 140,
"height": 70,
"backgroundColor": "#a5d8ff",
"fillStyle": "solid",
"roundness": { "type": 3 },
"boundElements": [{ "type": "arrow", "id": "arr-client-api" }]
},
{
"type": "rectangle",
"id": "box-api",
"x": 380,
"y": 100,
"width": 140,
"height": 70,
"backgroundColor": "#d0bfff",
"fillStyle": "solid",
"roundness": { "type": 3 },
"boundElements": [{ "type": "arrow", "id": "arr-client-api" }]
},
{
"type": "arrow",
"id": "arr-client-api",
"x": 240,
"y": 135,
"width": 140,
"height": 0,
"points": [[0, 0], [140, 0]],
"endArrowhead": "arrow",
"strokeColor": "#1e1e1e",
"startBinding": { "elementId": "box-client", "fixedPoint": [1, 0.5] },
"endBinding": { "elementId": "box-api", "fixedPoint": [0, 0.5] }
}
]
Use common fixedPoint values:
[1, 0.5][0, 0.5][0.5, 0][0.5, 1]Prefer a bound arrow plus a separate text element near the arrow:
[
{
"type": "arrow",
"id": "arr-client-api",
"x": 260,
"y": 130,
"width": 120,
"height": 0,
"points": [[0, 0], [120, 0]],
"endArrowhead": "arrow",
"strokeColor": "#1e1e1e",
"startBinding": { "elementId": "box-client", "fixedPoint": [1, 0.5] },
"endBinding": { "elementId": "box-api", "fixedPoint": [0, 0.5] }
},
{
"type": "text",
"id": "txt-client-api",
"x": 290,
"y": 100,
"width": 70,
"height": 20,
"text": "HTTPS",
"fontSize": 14,
"fontFamily": 1,
"strokeColor": "#757575"
}
]
If arrow binding fails in MCP preview or export, fall back to visually positioned arrows and tell the user they may need to reconnect arrows manually. This is an explicit fallback, not a silent simplification.
Regression guard: after a diagram looks visually correct, still inspect the generated/export JSON for every semantic connector. A beautiful render is not enough; if moving either connected box would leave the arrow behind, the diagram failed the editability requirement.
Use visually positioned arrows, not bindings, when:
Default to:
"fontFamily": 1
This maps to Excalidraw's hand-drawn Excalifont in normal Excalidraw scenes.
If the user asks for font options, verify the current Excalidraw element model before giving exact numeric values. Common Excalidraw families are hand-drawn/Excalifont, normal/sans, code/monospace, and comic-style, but do not promise exact IDs without checking.
Before exporting/delivering:
fontFamily: 1.width and height.containerId + matching shape boundElements; if not, the final answer explicitly says labels are visually placed only.startBinding and endBinding with the correct shape IDs; if not, the final answer explicitly says arrows are visually placed only.boundElements entries for their connected arrows.containerId, boundElements, startBinding, and endBinding fields; do not convert editable relationships into loose shapes during export.cameraUpdate, delete, restoreCheckpoint, or other MCP-only pseudo-elements.containerId/boundElements and arrow startBinding/endBinding where present in the preview.Preview and export are different artifacts:
cameraUpdate to guide the OpenClaw live canvas and verify readability.containerId + matching shape boundElements) and bound arrows (startBinding/endBinding + reciprocal shape boundElements).Critical export criterion: never include cameraUpdate or any other MCP-only pseudo-element in an excalidraw.com export payload.
cameraUpdate is only stage direction for the OpenClaw live preview. It is not a real Excalidraw scene element.
When exporting to excalidraw.com:
create_view -> inspect/preserve the preview scene -> export_to_excalidraw with a full native scene object.cameraUpdate, delete, restoreCheckpoint, and other MCP-only pseudo-elements.containerId, shape boundElements, arrow startBinding, arrow endBinding, groupIds, or arrow labels.export_to_excalidraw. create_view takes an array, but the exporter needs a serialized full scene object.type, version, source, elements, appState, and files.elements is non-empty and contains actual shapes/arrows/text, not only preview/camera metadata.Minimal export shape:
{
"type": "excalidraw",
"version": 2,
"source": "openclaw",
"elements": [
{ "type": "rectangle", "id": "example", "x": 0, "y": 0, "width": 160, "height": 80 }
],
"appState": { "viewBackgroundColor": "#ffffff" },
"files": {}
}
If a user states a durable Excalidraw preference, such as always wanting editable links with diagram replies, update the appropriate OpenClaw memory using the workspace memory policy. Keep it concise and preference-focused; do not store one-off diagram details or broken-export noise.
For blog posts, tutorials, case studies, or debugging write-ups, keep useful intermediate Excalidraw links instead of replacing them all.
Good progression artifacts include:
Use these links as iteration evidence when they help tell the story. Do not clutter normal user deliverables with every intermediate link unless the user is writing about the process.
If labels or fonts fail again:
label shortcut fields.containerId/boundElements and use visually positioned standalone text.boundElements; if it still fails, remove startBinding/endBinding and use visually positioned arrows.Default to a readable overview unless the user explicitly asks for a dense/deep technical diagram.
fontSize: 16 as the minimum for normal labels and body text.fontSize: 20+ for titles, section headers, and key concepts.Treat arrow routing as a first-class readability concern.
Best effort rules:
Use these common patterns before inventing custom paths: