A visual node-graph editor for Claude Code skills. Think Blender's shader nodes, but for editing AI agent workflows.
Claude Code skills are markdown files that define complex workflows - prompts, tool invocations, conditional gates, checklists, and inter-skill calls. Editing them as raw markdown makes it hard to see the flow, locate misbehaviors, or understand how sections connect. Skill Editor decomposes these files into typed, color-coded nodes on a canvas with bidirectional linking to the markdown source.
The main canvas shows skill workflows as connected nodes. Each node type has a distinct color:
- Purple - Prompt nodes (instruction text)
- Green - Tool nodes (Bash, Read, Write, etc.)
- Yellow - Gate nodes (conditional branches)
- Blue - Checklist nodes (ordered steps)
- Red - Skill Call nodes (references to other skills)
- Gray - Frontmatter (skill metadata)
Side-by-side graph and markdown source with bidirectional linking:
- Click a node to highlight its source lines
- Click a line in the source to select the corresponding node
- Draggable resize handle between panels
- Visual node graph - Drag, zoom, pan, connect nodes on a React Flow canvas with minimap
- Three view modes - Graph (full canvas), Split (graph + source side-by-side), Source (full markdown editor)
- Bidirectional linking - Click a node to see its source lines; click source to select the node
- Node palette - Drag new Prompt, Tool, Gate, Checklist, or Skill Call nodes onto the canvas
- Properties panel - Edit any node's content, tool config, gate conditions, checklist items inline
- Skill browser - Browse all skills from user (
~/.claude/skills/), plugin, and project directories - Read-only plugin skills - Plugin skills open as read-only with a "Fork to User Skills" option
- Create new skills - Start from scratch with a Frontmatter skeleton
- File watcher - Auto-reloads when skill files change on disk (with dirty-state protection)
- Undo/Redo - Ctrl+Z / Ctrl+Shift+Z with 50-entry history
- Save - Ctrl+S writes back to
.mdfile +.skill-layout.jsonsidecar for node positions
┌─────────────────────────────────────────────────────┐
│ Browser (React + React Flow + CodeMirror) │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ Skill │ │ Canvas / │ │ Properties │ │
│ │ Browser │ │ Markdown │ │ Panel │ │
│ │ │ │ Panel │ │ │ │
│ └──────────┘ └──────────────┘ └───────────────┘ │
└────────────────────────┬────────────────────────────┘
│ REST + WebSocket
┌────────────────────────┴────────────────────────────┐
│ FastAPI Backend │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ Scanner │ │ Parser │ │ File Watcher │ │
│ │ │ │ md ↔ graph│ │ (watchdog) │ │
│ └──────────┘ └──────────┘ └──────────────────┘ │
└──────────────────────────────────────────────────────┘
│ │
┌────┴────┐ ┌─────┴─────┐
│ SKILL.md │ │ .skill- │
│ (source │ │ layout. │
│ of truth)│ │ json │
└──────────┘ └───────────┘
The .md skill file is the source of truth. The editor stores layout metadata (node positions, viewport state) in a .skill-layout.json sidecar file alongside each skill.
Node types map to skill constructs:
| Node Type | Color | What it represents |
|---|---|---|
| Frontmatter | Gray | YAML metadata (name, description, allowed-tools) |
| Prompt | Purple | Blocks of instruction text |
| Tool | Green | Tool invocations (Bash, Read, Write, etc.) |
| Gate | Yellow | Conditional branches, <HARD-GATE> blocks |
| Checklist | Blue | Ordered step lists |
| Skill Call | Red | References to other skills |
The parser converts between markdown and a graph model:
- Extracts YAML frontmatter
- Detects
<HARD-GATE>blocks - Splits body by H2/H3 headers into sections
- Classifies each section by content patterns (numbered lists, code blocks, skill references, etc.)
- Creates sequential edges between nodes
- Tracks source line numbers for bidirectional linking
The parser doesn't need to be perfect on first import - you can split/merge nodes visually and save to make the editor's structure canonical.
Backend:
- Python 3.11+
- FastAPI + Uvicorn
- watchdog (file system monitoring)
- python-frontmatter + PyYAML
Frontend:
- React 19
- @xyflow/react 12 (React Flow - node graph)
- CodeMirror 6 (markdown editor)
- Tailwind CSS 4
- Python 3.11+
- Node.js 18+
- Claude Code with skills (
~/.claude/skills/)
git clone https://github.com/OshriNap/skill-editor.git
cd skill-editor
# Backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r backend/requirements.txt
# Frontend
cd frontend
npm install
npm run build
cd ..# Start the backend (serves both API and built frontend)
source .venv/bin/activate
uvicorn backend.main:app --host 0.0.0.0 --port 8085Open http://localhost:8085 in your browser.
Run backend and frontend dev servers separately for hot reload:
# Terminal 1: Backend
source .venv/bin/activate
uvicorn backend.main:app --host 0.0.0.0 --port 8085 --reload
# Terminal 2: Frontend (with API proxy to backend)
cd frontend
npm run devFrontend dev server runs on port 5175 with API requests proxied to the backend.
# Create user service
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/skill-editor.service << 'EOF'
[Unit]
Description=Skill Editor Backend
After=network.target
[Service]
Type=simple
WorkingDirectory=/path/to/skill-editor
ExecStart=/path/to/skill-editor/.venv/bin/uvicorn backend.main:app --host 0.0.0.0 --port 8085
Restart=always
RestartSec=5
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now skill-editorIf you want to serve it under a path prefix (e.g., /skill-editor):
handle /skill-editor* {
uri strip_prefix /skill-editor
reverse_proxy localhost:8085
}
The frontend uses relative URLs and a dynamic <base> tag, so it works correctly behind path prefixes.
| Endpoint | Method | Purpose |
|---|---|---|
/api/health |
GET | Health check |
/api/skills |
GET | List all discovered skills |
/api/skills/{path} |
GET | Parse skill into graph + layout + raw markdown |
/api/skills/{path} |
PUT | Save graph back to .md + layout sidecar |
/api/skills/new |
POST | Create a new skill |
/api/skills/{path}/raw |
GET | Get raw markdown only |
/api/skills/{path}/fork |
POST | Fork a plugin skill to user skills |
/api/ws |
WS | File change notifications |
Path parameters are base64url-encoded absolute paths to skill directories.
~/.claude/skills/- User skills (editable)~/.claude/plugins/cache/- Plugin skills (read-only, can be forked)- Project-level
.claude/skills/if present
| Shortcut | Action |
|---|---|
| Ctrl+S | Save current skill |
| Ctrl+Z | Undo |
| Ctrl+Shift+Z | Redo |
| Delete | Delete selected node |
- Execution tracing - Replay past sessions through the graph, highlighting which nodes fired
- Skill diffing - Visual diff between skill versions (git integration)
- Skill templates - Pre-built node patterns for common workflows
MIT