A local, single-user web app for hand-wiring the dependency graph (DAG) of the tasks you're working on. It answers, at a glance: what's running / blocked / done, what starts when something else finishes, and what's independent work — replacing scratch notes and in-head tracking.
It is fully manual: you add nodes, draw the dependency wires by hand, and take rich-text notes on both nodes and wires. It only ever writes its own board files; nothing here decides or runs anything for you.
Dependency relationships ("this can't start until that's done") usually live only in your head.
Tools like Claude Code's /tasks can record blocks/blockedBy, but in practice those fields
are almost always empty — so the wiring has to come from you. DAG Wireboard gives you a sleek
canvas to draw and keep that mental model: the nodes and wires are yours.
-
Manual DAG editor — double-click empty canvas to add a node right there (or + Add task, which drops it at the nearest free spot mid-screen), drag nodes anywhere (positions persist), drag from a node's handle to another to create a wire, drag a wire's endpoint to reconnect, click a wire to manage it. Cycles are rejected (it stays a DAG).
-
Named boards — keep separate boards for separate efforts. + New board spins up a fresh, empty board with a custom name; switch between them from the board picker. The 🗑 button next to the picker deletes the current board after a confirmation that shows what it holds (Enter confirms, Esc cancels). Deleted boards are moved to
~/.dag-wireboard/boards/.trash/, so they can be restored by moving the file back. The default board can't be deleted. -
Fast canvas — scroll / two-finger swipe pans in any direction; pinch or Ctrl/Cmd+scroll zooms (Shift+scroll pans horizontally with a mouse wheel). Saves show up on the board instantly (no polling); the board re-syncs when the tab regains focus, so edits from another tab appear. Wires don't animate (an animated SVG wire costs main-thread time every frame); a wire feeding a running node is drawn solid amber.
-
Rich-text notes (Tiptap) on any node and any wire, via a slide-in detail panel. Ctrl/Cmd+S in the panel runs Save (instead of the browser's save-page dialog).
-
"Ready to start" signal — a waiting node whose upstream is all done gets a pulsing READY badge.
-
Keyboard-first — a first-run tip bar shows the essentials (dismiss it with Got it; it stays gone), buttons name their shortcut in their tooltip, and
?(or the ? Shortcuts button) opens the full list:Key Action N/ double-clickNew node at the cursor (mid-screen if the pointer isn't on the canvas) EWire mode: click the source (or start with one selected), then the target; Shift+click keeps chaining; Esc cancels Delete/BackspaceDelete the selection — nodes ask for confirmation (with wire/note counts), wires don't 1234Set selected nodes to waiting / running / blocked / done EnterOpen the selected node or wire Ctrl/Cmd+C,Ctrl/Cmd+V,Ctrl/Cmd+DCopy, paste, duplicate the selected nodes (copies never land on another card) Ctrl/Cmd+SSave the open panel F/MFit the board / toggle the minimap Arrow keys Nudge the selected nodes (saved) EscCancel wire mode, or close the panel and clear the selection Shift+drag box-selects and Ctrl/Cmd+click adds to the selection; every shortcut acts on the whole selection. Shortcuts are off while you type in a field or a dialog is open, and browser shortcuts (
Ctrl+N,Ctrl+F, …) are left alone. -
Minimap toggle — show or hide the canvas minimap; the preference persists across reloads.
-
Futuristic HUD theme — dark blueprint canvas, neon status-glow nodes, glass panels.
| Color | Status |
|---|---|
| 🟢 green | done |
| 🟠 amber | running |
| ⚪ grey | waiting |
| 🔴 red | blocked |
A waiting node whose upstream is all done shows a green READY badge.
Prerequisites: Python 3.12+, Node 18+ / npm.
# 1. Install (editable) — pulls backend deps and adds the `dag-wireboard` command
pip install -e .
# 2. Build the frontend (outputs web/dist, which the server serves)
cd web && npm install && npm run build && cd ..
# 3. Launch — starts the server (127.0.0.1 only) and opens your browser
dag-wireboard # → http://127.0.0.1:8765dag-wireboard binds 127.0.0.1, opens your browser at the board, and is callable from any
directory once installed. Running it again while it's already up just reopens the tab instead of
erroring on the busy port. (The classic python3 -m server.app still works too.)
Press + New board (or use the default board), click + Add task, wire nodes together, and take notes.
Optional flags: --no-open (don't launch a browser), --port <n> (default 8765),
--boards-dir <path> (default ~/.dag-wireboard/boards).
cd web && npm run dev # Vite dev server with hot reload, proxies /api → :8765
# in another terminal:
python3 -m server.appEarlier versions could import git branches and a Claude Code task session. That import has been
removed. Old board files still open: any imported branch/task you had touched (notes, position,
wires, edited title/status) is converted to a regular node on load, so no wire or note is lost;
untouched imported nodes are not kept. Imported titles and statuses were read live from git /
Claude Code and never stored, so a migrated node you hadn't renamed shows its id (e.g. 1) as its
title and waiting as its status — rename it as needed. Before the first write, the original file is
copied to ~/.dag-wireboard/boards/.legacy/ so nothing is irrecoverable.
| Layer | Responsibility |
|---|---|
adapters/overlay.py |
The only writer. Per-board JSON saved atomically (temp-file + os.replace, per-board lock). Owns CRUD, the cycle guard, legacy-board migration, and merge(board) → the final {nodes, edges} graph. |
adapters/boards.py |
Board registry: the always-present default board and minted ids for named boards → JSON files. |
server/app.py |
Thin FastAPI HTTP layer. Wires adapters to the API, guards non-localhost writes, serves web/dist. |
web/ |
React + Vite + React Flow UI (canvas, detail drawer, Tiptap notes), built to web/dist. |
Data model. Each board (~/.dag-wireboard/boards/<id>.json) stores its label, nodes
(id, label, status, detail), wires, per-node/per-wire notes, and positions. Edges are exactly
your wires (from → to means "from must finish before to"); a wire can only join two existing
nodes. Reads never write the file.
- Binds
127.0.0.1only — never exposed to the network; no auth (single local user). - A CSRF / DNS-rebinding guard rejects any write whose
Origin/Hostisn't localhost. - Board ids are validated (
[A-Za-z0-9_-]{1,64}) before they become file names, so a request can't read or write outside the boards dir. Reads never create a board and writes never recreate a deleted one (404). - Write endpoints mutate only the board files under the boards dir.
python3 -m pytest -q # backend: adapters, overlay/merge, API integration
cd web && npx vitest run # frontend unit: cycle / layout / merge / api client / minimap
cd web && npx playwright test # frontend e2e smoke (needs: npx playwright install chromium,
# or PW_CHANNEL=chrome to use the system Google Chrome).
├── server/app.py # FastAPI: API + static serving (127.0.0.1)
├── adapters/
│ ├── overlay.py # the only writer: store + CRUD + cycle guard + merge
│ └── boards.py # board registry
├── web/ # React + Vite + React Flow app
│ ├── src/{api.ts,types.ts,lib/,graph/,components/,theme.css}
│ └── tests/ # vitest + playwright
├── tests/ # backend pytest
└── docs/ # screenshots
Shipped: everything above, including named manual boards. Backlog: cross-session / cross-repo boards, undo/redo, multi-tab live sync.
