Synced 79 commits from EveryInc/compound-engineering-plugin upstream while
preserving fork-specific customizations (Python/FastAPI pivot, Zoominfo-internal
review agents, deploy-wiring operational lessons, custom personas).
## Triage decisions (15 conflicts resolved)
Keep deleted (7) -- fork already removed these in prior cleanups:
- agents/design/{design-implementation-reviewer,design-iterator,figma-design-sync}
(no fork successor; backend-Python focus doesn't need UI/Figma agents)
- agents/docs/ankane-readme-writer (replaced by python-package-readme-writer)
- agents/review/{data-migration-expert,performance-oracle,security-sentinel}
(replaced by *-reviewer naming convention: data-migrations-reviewer,
performance-reviewer, security-reviewer)
Keep local (1):
- agents/workflow/lint.md (Python tooling: ruff/mypy/djlint/bandit; upstream
deleted the file). Fixed pre-existing duplicate "2." numbering bug.
Restore from upstream (1):
- agents/review/data-integrity-guardian.md (kept for GDPR/CCPA privacy
compliance angle not covered by data-migrations-reviewer)
Merge both (6) -- upstream structural wins layered with fork intent:
- agents/research/best-practices-researcher.md (upstream <examples> removal +
fork's Rails/Ruby -> Python/FastAPI translations)
- skills/ce-brainstorm/SKILL.md (universal-brainstorming routing + Slack
context + non-obvious angles + fork's Deploy wiring flag)
- skills/ce-plan/SKILL.md (universal-planning routing + planning-bootstrap +
fork's two Deploy wiring check bullets)
- skills/ce-review/SKILL.md (Run ID, model tiering haiku->sonnet, compact-JSON
artifact contract, file-type awareness, cli-readiness-reviewer + fork's
zip-agent-validator, design-conformance-reviewer, Stage 6 Zip Agent
Validation)
- skills/ce-review/references/persona-catalog.md (cli-readiness row + adversarial
refinement + fork's Language & Framework Conditional layer; 22 personas total)
- skills/ce-work/SKILL.md (Parallel Safety Check, parallel-subagent constraints,
Phase 3-4 compression + fork's deploy-values self-review row, with duplicate
checklist bullet collapsed to single occurrence)
## Auto-applied (no triage needed)
- 225 remote-only files: accepted as-is (new docs, brainstorms, plans,
upstream skills, tests, scripts)
- 70 local-only files: 46 preserved as-is (kieran-python, tiangolo-fastapi,
zip-agent-validator, design-conformance-reviewer, essay/proof commands,
excalidraw-png-export, etc.); 24 stayed deleted (dhh-rails-style,
andrew-kane-gem-writer, dspy-ruby Ruby skills no longer needed)
## README updated
- Removed Design section (3 deleted agents)
- Removed deleted Review entries (data-migration-expert, dhh-rails-reviewer,
kieran-rails-reviewer, performance-oracle, security-sentinel)
- Added new Review entries: design-conformance-reviewer, previous-comments-reviewer,
tiangolo-fastapi-reviewer, zip-agent-validator
- Workflow: added lint
- Docs: replaced ankane-readme-writer with python-package-readme-writer
## Known issues (not introduced by merge decisions)
- 9 detect-project-type.sh tests fail on macOS bash 3.2 (script uses
`declare -A` which requires bash 4+). Upstream regression in commit 070092d
(#568). Resolution: install bash 4+ via `brew install bash` locally;
upstream fix tracked separately.
- 2 review-skill-contract tests reference deleted agents (dhh-rails-reviewer,
data-migration-expert). Pre-existing fork inconsistency, not new.
bun run release:validate: passes (46 agents, 51 skills, 0 MCP servers)
6.9 KiB
name, description
| name | description |
|---|---|
| excalidraw-png-export | This skill should be used when creating diagrams, architecture visuals, or flowcharts and exporting them as PNG files. It uses the Excalidraw MCP to render hand-drawn style diagrams locally and Playwright to export them to PNG without sending data to any remote server. Triggers on requests like 'create a diagram', 'make an architecture diagram', 'draw a flowchart and export as PNG', or any request that needs a visual diagram delivered as an image file. |
Excalidraw PNG Export
Create hand-drawn style diagrams with the Excalidraw MCP and export them locally to PNG files. All rendering happens on the local machine. Diagram data never leaves the user's computer.
Prerequisites
First-Time Setup
Run the setup script once per machine to install Playwright and Chromium headless:
bash <skill-path>/scripts/setup.sh
This creates a .export-runtime directory inside scripts/ with the Node.js dependencies. The setup is idempotent and skips installation if already present.
Required MCP
The Excalidraw MCP server must be configured. Verify availability by checking for mcp__excalidraw__create_view and mcp__excalidraw__read_checkpoint tools.
File Location Convention
Save diagram source files alongside their PNG exports in the project's image directory. This enables re-exporting diagrams when content or styling changes.
Standard pattern:
docs/images/my-diagram.excalidraw # source (commit this)
docs/images/my-diagram.png # rendered output (commit this)
When updating an existing diagram, look for a .excalidraw file next to the PNG. If one exists, edit it and re-export rather than rebuilding from scratch.
Temporary files (raw checkpoint JSON) go in /tmp/excalidraw-export/ and are discarded after conversion.
Workflow
Step 1: Design the Diagram Elements
Translate the user's request into Excalidraw element JSON. Load excalidraw-element-format.md for the full element specification, color palette, and sizing guidelines.
Key design decisions:
- Choose appropriate colors from the palette to distinguish different components
- Use
labelon shapes instead of separate text elements - Use
roundness: { type: 3 }for rounded corners on rectangles - Include
cameraUpdateas the first element to frame the view (MCP rendering only) - Use arrow bindings (
startBinding/endBinding) to connect shapes
Step 2: Render with Excalidraw MCP
Call mcp__excalidraw__create_view with the element JSON array. This renders an interactive preview in the Claude Code UI.
mcp__excalidraw__create_view({ elements: "<JSON array string>" })
The response includes a checkpointId for retrieving the rendered state.
Step 3: Extract the Checkpoint Data
Call mcp__excalidraw__read_checkpoint with the checkpoint ID to get the full element JSON back.
mcp__excalidraw__read_checkpoint({ id: "<checkpointId>" })
Step 4: Convert Checkpoint to .excalidraw File
Use the convert.mjs script to transform raw MCP checkpoint JSON into a valid .excalidraw file. This handles all the tedious parts automatically:
- Filters out pseudo-elements (
cameraUpdate,delete,restoreCheckpoint) - Adds required Excalidraw defaults (
seed,version,fontFamily, etc.) - Expands
labelproperties on shapes/arrows into proper bound text elements
# Save checkpoint JSON to a temp file, then convert to the project's image directory:
node <skill-path>/scripts/convert.mjs /tmp/excalidraw-export/raw.json docs/images/my-diagram.excalidraw
The input JSON should be the raw checkpoint data from mcp__excalidraw__read_checkpoint (the {"elements": [...]} object). The output .excalidraw file goes in the project's image directory (see File Location Convention above).
For batch exports: Write each checkpoint to a separate raw JSON file, then convert each one:
node <skill-path>/scripts/convert.mjs raw1.json diagram1.excalidraw
node <skill-path>/scripts/convert.mjs raw2.json diagram2.excalidraw
Manual alternative: If you need to write the .excalidraw file by hand (e.g., without the convert script), each element needs these defaults:
angle: 0, roughness: 1, opacity: 100, groupIds: [], seed: <unique int>,
version: 1, versionNonce: <unique int>, isDeleted: false,
boundElements: null, link: null, locked: false
Text elements also need: fontFamily: 1, textAlign: "left", verticalAlign: "top", baseline: 14, containerId: null, originalText: "<same as text>"
Bound text (labels on shapes/arrows) needs: containerId: "<parent-id>", textAlign: "center", verticalAlign: "middle", and the parent needs boundElements: [{"id": "<text-id>", "type": "text"}].
Step 5: Export to PNG
Run the export script. Determine the runtime path relative to this skill's scripts directory:
cd <skill-path>/scripts/.export-runtime && node <skill-path>/scripts/export_png.mjs docs/images/my-diagram.excalidraw docs/images/my-diagram.png
The script:
- Starts a local HTTP server serving the
.excalidrawfile and an HTML page - Launches headless Chromium via Playwright
- The HTML page loads the Excalidraw library from esm.sh (library code only, not user data)
- Calls
exportToBlobon the local diagram data - Extracts the base64 PNG and writes it to disk
- Cleans up temp files and exits
The script prints the output path on success. Verify the result with file <output.png>.
Step 5.5: Validate and Iterate
Run the validation script on the .excalidraw file to catch spatial issues:
node <skill-path>/scripts/validate.mjs docs/images/my-diagram.excalidraw
Then read the exported PNG back using the Read tool to visually inspect:
- All label text fits within its container (no overflow/clipping)
- No arrows cross over text labels
- Spacing between elements is consistent
- Legend and titles are properly positioned
If the validation script or visual inspection reveals issues:
- Identify the specific elements that need adjustment
- Edit the
.excalidrawfile (adjust coordinates, box sizes, or arrow waypoints) - Re-run the export script (Step 5)
- Re-validate
Step 6: Deliver the Result
Read the PNG file to display it to the user. Provide the file path so the user can access it directly.
Troubleshooting
Setup fails: Verify Node.js v18+ is installed (node --version). Ensure npm has network access for the initial Playwright/Chromium download.
Export times out: The HTML page has a 30-second timeout. If it fails, check browser console output in the script's error messages. Common cause: esm.sh CDN is temporarily slow on first load.
Blank PNG: Ensure elements include all required properties (see Step 4 defaults). Missing seed, version, or fontFamily on text elements can cause silent render failures.
"READY" never fires: The exportToBlob call requires valid elements. Filter out cameraUpdate and other pseudo-elements before writing the .excalidraw file.