Kanban UI
A file-based task manager built for human-AI collaboration. One filesystem, two operators, no integration required.
The Problem
I use Claude Code extensively -- for building features, fixing bugs, managing task backlogs across multiple projects. But Claude Code operates through the terminal. It reads files, writes files, and moves on. It doesn't have a GUI. It doesn't have a project management tool. And the task management tools I tried all required a database, an API, or some integration layer that would need to be purpose-built for an AI coding agent to interact with.
This created a frustrating gap:
| What I Needed | What Existed |
|---|---|
| A task board I could see and drag things around on | CLI-only task lists, or heavy SaaS tools |
| A format Claude Code could read and edit natively | Databases, JSON APIs, proprietary formats |
| Real-time sync between my edits and Claude's | Tools that assume a single operator |
| Multi-project support from one place | Per-project configurations every time |
| Zero setup for Claude -- no auth, no SDK, no integration | Every tool required custom tooling |
The core tension: the tools built for humans don't work for AI agents, and the formats AI agents work with (files) don't have good UIs.
The Insight
Claude Code already knows how to read and write markdown files. That's its native medium. So instead of building an integration layer between a task manager and an AI agent, I eliminated the integration entirely:
Make the filesystem the single source of truth. Build the UI on top of it. Let Claude edit the same files directly.
No API adapter. No webhook. No database sync. Just a /tasks directory with markdown files that both a human and an AI can read and write -- and a reactive UI that watches for changes in real time.
Neither operator knows about the other. They just share a directory.
What I Built
The Stack
| Layer | Technology |
|---|---|
| Frontend | React 19, TypeScript, Vite 7 |
| Styling | Tailwind CSS v4, CSS custom properties (dark mode) |
| Drag-and-Drop | @dnd-kit (core + sortable) |
| Backend | Express.js (ES modules) |
| File Watching | Chokidar with SSE broadcasting |
| Persistence | Markdown files on disk |
No database. No ORM. No authentication. The entire persistence layer is the filesystem.
Task Format
Every task is a standalone markdown file with structured sections:
# Implement dark mode toggle
## Id
task_1734523687000
## Status
implementing
## Tags
- feature-enhancement
## Description
Add a toggle in the header that switches between light and dark themes.
Store preference in localStorage.
## Acceptance Criteria
- [ ] Toggle button renders in header
- [x] Theme persists across page reloads
- [ ] All components respect theme variables
Claude Code can change a task's status by editing one line. The UI picks it up instantly.
Six-Column Kanban Board
Tasks flow through six stages: Ideation > Planning > Backlog > Implementing > UAT > Done.
Each column is a droppable zone. Cards are sortable within columns and draggable across them. Moving a card updates the ## Status field in the markdown file and the column ordering in _board.json.
Multi-Project Architecture
This isn't a single-project tool. It's a centralized installation that manages any number of projects:
~/.kanban-ui/config.json -- Global registry (machine-specific)
~/projects/project-alpha/tasks/ -- Project A's tasks
~/projects/project-beta/tasks/ -- Project B's tasks
~/clients/acme-corp/tasks/ -- Project C's tasks
One UI. One server. A dropdown in the header switches between projects. Each project has its own task files, board configuration, notes, and roadmap. The file watcher reinitializes when you switch, and SSE broadcasts keep every open tab in sync.
Per-connection project tracking means two browser tabs can watch two different projects simultaneously without interfering with each other. Each SSE connection gets a unique client ID, and the server routes file events only to clients watching the relevant project.
Real-Time Sync via Server-Sent Events
When either operator (human or Claude) modifies a task file, the system reacts:
- Chokidar detects the filesystem change
- Watcher service identifies which project the file belongs to
- SSE broadcast sends the event to all clients watching that project
- React hooks trigger a task reload and re-render
The SSE system handles edge cases that matter in practice:
- Exponential backoff reconnection (1s > 2s > 4s > ... > 30s max) when connection drops
- Visibility change detection to proactively reconnect after laptop sleep/wake
- Grace period (2s) after auto-save to prevent SSE events from resetting your cursor position mid-edit
Auto-Save with Cursor Preservation
Task descriptions and notes auto-save on a 5-second debounce. The subtle problem: saving a file triggers Chokidar, which triggers an SSE event, which triggers a task reload, which resets the form -- including your cursor position.
The solution is a grace period. After an auto-save fires, the frontend ignores SSE updates for that task for 2 seconds. Long enough for the event to arrive and be discarded. Short enough that genuine external changes (from Claude or another tab) still come through promptly.
Acceptance Criteria with Drag Reordering
Acceptance criteria aren't just checkboxes -- they're drag-reorderable, inline-editable items. Hover reveals edit and delete controls. Click to check off. Drag handles to reprioritize. Enter to save an edit, Escape to cancel.
This detail matters because Claude Code checks off criteria as it works through a task. The ordering and completion state persist in the markdown, so both operators see the same progress.
Search, Filter, and Sort
All filtering happens client-side for instant responsiveness:
- Search: Case-insensitive title matching
- Tags: Multi-select filter (bug, feature-enhancement, refactor, new-functionality, devops)
- Epics: Multi-select filter for task grouping
- Date range: Filters the Done column by completion date (presets: last 7/30 days, this month, custom range)
- Sort: Done column can sort by completion date (newest/oldest first)
Dual View Modes
A toggle in the header switches between:
- Board view -- the standard six-column Kanban layout with horizontal scrolling
- List view -- a vertical layout grouped by status, better for smaller screens or when you want to scan everything at once
Card previews (togglable) show a 2-line description snippet directly on each card without opening the detail panel.
Project Notes and Roadmap
Each project has two long-form markdown documents accessible from the header:
- Notes -- a slide-out panel from the left for freeform project context (decisions, links, reference info)
- Roadmap -- a slide-out panel from the right for long-term planning
Both auto-save on a 5-second debounce, just like task descriptions.
Technical Decisions Worth Explaining
Why Flat File Structure?
The original design used status-based subdirectories (/tasks/backlog/, /tasks/implementing/, etc.). Moving a task between columns required moving a file between directories -- which meant the filename path changed, which broke in-flight references, and made it harder for Claude Code to operate on tasks without knowing the directory structure.
The flat structure (/tasks/*.md with a ## Status field) means filenames are stable. Claude changes one line of markdown to move a task. The UI handles ordering through _board.json, a sidecar file that Claude never needs to touch.
Why SSE Instead of WebSockets?
Server-Sent Events are one-directional (server to client), which is exactly what file watching needs. The client doesn't push events to the server -- it makes REST calls. SSE is simpler to implement, works with standard HTTP, auto-reconnects natively, and doesn't require a socket library on either end.
Why No Database?
The entire point is that the persistence layer is human-readable and AI-editable without any intermediary. A database would require an API layer for Claude to interact with tasks. Markdown files require nothing -- cat, sed, or just direct file writes. The filesystem is the API.
The Development Journey
Built across 31 commits with Claude Code as both the development tool and a target user:
| Phase | What Shipped |
|---|---|
| MVP | Basic Kanban board, task CRUD, acceptance criteria |
| UX Polish | Drag-reorderable criteria, completion dates, modal improvements |
| Multi-Project | Centralized registry, project switching, per-connection tracking |
| Metadata | Project notes, epic grouping, auto-save with cursor preservation |
| Extensibility | Roadmap feature, stable IDs, flat structure migration |
| Terminal Integration | Launch configs, AppleScript-based Ghostty spawning |
| Reliability | SSE reconnection, sleep/wake handling, list view, card previews, search/filter |
The project dogfoods itself -- its own task management uses the same /tasks directory and markdown format. Claude Code picks up tasks from the backlog, implements them, checks off acceptance criteria, and moves them to UAT. I review in the UI.
What Makes It Interesting
This isn't a complex app. It's a focused one. The interesting parts aren't in the feature count -- they're in the architectural bet:
The filesystem as a shared protocol between human and AI.
No integration code. No adapter layer. No API tokens. The contract is: "here's a directory of markdown files with a known format." Both operators can read and write them. A file watcher turns changes into real-time UI updates regardless of who made the change.
This pattern -- file-based shared state with a reactive UI layer -- could apply to other human-AI collaboration tools. Configuration management, content authoring, code review workflows. Anywhere the AI's native medium (text files) can double as the persistence layer.
The other interesting constraint: building a tool with your AI collaborator that the same AI collaborator then uses to manage its own work. The development process was recursive in a practical way -- every feature got tested by the thing that helped build it.
Current State
- 31 commits shipped
- Multi-project support with per-connection tracking
- Dual view modes (board + list)
- Real-time sync via SSE with robust reconnection
- Auto-save with cursor preservation
- Search, filter, and sort across tags, epics, and dates
- Terminal launch integration with Ghostty
- Actively used for managing its own development and other projects
Tech Summary
| Frontend | React 19 + TypeScript + Vite 7 + Tailwind CSS v4 |
| Drag-and-Drop | @dnd-kit with custom collision detection |
| Backend | Express.js with Chokidar file watching |
| Real-Time | Server-Sent Events with per-connection routing |
| Persistence | Markdown files + JSON sidecar (no database) |
| Design | Dark mode, JetBrains Mono, CSS custom properties |
| Terminal | AppleScript + Ghostty integration |
Designed and built as a personal tool. Developed collaboratively with Claude Code.