* feat: add multi-select and drag-to-move for file tree and changes panel
Add Shift-click range and Ctrl/Cmd-click toggle selection to the file
tree and staged/unstaged changes sections. Includes bulk actions
(delete, stage, unstage, discard), drag-and-drop file moving into
directories, keyboard shortcuts (Escape, Ctrl+A), and E2E tests.
* fix: move bulk action components to file-row to fix max-lines lint
* style: apply prettier formatting to all changed files
* fix: bulk delete all selected items and update anchor on stale shift-click
* fix: address CodeRabbit review comments
- Keep original file-row-* data-testid for backwards compat
- Remove eager onClearSelection from bulk actions (auto-pruned by hook)
- Variant-scope bulk-discard/bulk-unstage test ids
- Remove index.lock deletion from E2E GitHelper retry loop
* fix: fix E2E tests — create files after session open, remove DnD test
- Create files AFTER opening session so WS detects git status changes
- Add proper git env vars (GIT_AUTHOR_NAME, etc.) matching existing tests
- Use element.press("Escape") instead of page keyboard for proper focus
- Remove drag-to-directory test (Playwright dragTo doesn't support HTML5
dataTransfer events needed by our DnD implementation)
* fix: rename E2E task titles to avoid ambiguous 'Changes' tab selector
* fix: make file list focusable for Escape key handler in E2E tests
* fix: improve selection styling and ignore right-clicks in selection handler
- Use text-accent-foreground on selected rows for dark mode readability
- Override child span colors with [&_span]:text-accent-foreground
- Use hover:bg-accent/80 instead of hover:bg-muted on selected items
- Skip selection handling on right-click (button === 2) so context menu
works without clearing multi-selection
* fix: plain click should not select — only Ctrl/Cmd+click and Shift+click
Plain click now clears any selection and performs the original action
(open file / toggle folder / open diff). Selection only happens with
modifier keys. handleClick returns boolean to indicate whether the
click was consumed by selection logic.
* fix: fix multi-select bugs and expand E2E test coverage
Bug fixes:
- Change isSelected from boolean to function prop so children compute
their own selection state (fixes nested file selection)
- Inline TreeNodeRow JSX into TreeNodeItem so ContextMenuTrigger asChild
can attach refs directly (fixes right-click context menu)
- Set lastClickedRef on plain click so shift-click has a valid anchor
- Add click-outside handler to clear selection
E2E tests expanded to 14 file-tree tests + 3 changes-panel tests:
- Ctrl-click select, toggle, multi-select
- Plain click clears selection
- Shift-click range after plain click and ctrl-click anchors
- Directory selection and nested file selection
- Right-click context menu (single + bulk delete)
- Click outside clears selection
- Escape clears selection
* fix: move AlertDialog outside ContextMenu to fix delete action
The AlertDialog wrapping the ContextMenu caused Radix focus management
to intercept context menu item selection, making Delete trigger Rename.
Moving AlertDialog to a sibling of ContextMenu fixes the conflict.
* fix: reorder context menu — Delete first, Rename second
Radix ContextMenu auto-focuses the first item on open, which caused
accidental Rename triggers. Putting Delete first (the more common
action for selection) avoids this.
* fix: don't clear selection when clicking context menu or dialog
The click-outside handler was clearing selection when clicking on
context menu items or confirmation dialog buttons (rendered in portals
outside the tree container). Now skips clearing for elements with
role=menu, role=alertdialog, or role=dialog.
Also extended the bulk delete E2E test to verify both files are
actually removed after confirming the dialog.
* fix: hide file count in delete dialog when folder children not loaded
When a folder hasn't been expanded, its children aren't loaded yet so
countFilesInTree returns 0. Instead of showing "0 files", hide the
count entirely and just show "delete <folder name>".
* fix: show confirmation dialog for bulk discard in changes panel
Bulk discard was calling git.discard() directly, bypassing the
confirmation dialog. Now routes through handleBulkDiscardClick which
opens the DiscardDialog with a bulk message ("discard changes to N
files") before executing.
* fix: address remaining CodeRabbit review comments
- Deduplicate filenames on move: when moving files with identical names
to the same directory, append "(1)", "(2)" etc. to avoid collisions.
Both tree update and rename API calls use the same deduplication.
- Replace void operator with .catch(() => {}) for bulk stage/unstage
to prevent unhandled promise rejections.
- Add document-level dragend listener as safety net to clear stuck drag
state if the element's onDragEnd doesn't fire (Escape, out-of-window).
* test: add unit tests for file tree move deduplication and visible paths
* fix: address all remaining PR review comments
- Move onSelectionChange out of React state updater (side effect fix)
- Stabilize keyboard listener deps (pass callbacks not object)
- Remove unnecessary useMemo in BulkActionBar
- Fix ghost-restore on partial bulk delete (remove all at once)
- Fix blank filename on single-file bulk discard
- Add aria-selected and role=treeitem for accessibility
- Extract computeNextSelection params into object (max-params lint)
* fix: add missing bulk action props to WorkingTreeProps type
WorkingTreeSections referenced onBulkStage, onBulkUnstage, and
onBulkDiscard but WorkingTreeProps Pick didn't include them, causing
a TypeScript build failure.
* fix: address final review comments
- Add unit tests for computeNextSelection (8 tests covering ctrl-click,
shift-click range, stale anchor, reverse range, shift+ctrl extend)
- Extract shared E2E helpers (GitHelper, makeGitEnv, openTaskSession,
createStandardProfile) to e2e/helpers/git-helper.ts
- Fix misleading comment in bulk delete (says "re-insert only failed"
but implementation restores full snapshot)
* fix: use Promise.all for bulk delete to prevent partial rollback
Individual .catch() handlers could restore already-deleted files
if a later delete failed. Now uses Promise.all so rollback only
happens if any delete rejects.
* test: add renderHook tests for useMultiSelect hook behaviors
- Stale-path pruning: items shrink → selected paths auto-pruned
- Plain click: returns false, clears existing selection
- selectAll/clearSelection: work correctly, fire onSelectionChange
- Install @testing-library/react for renderHook support
* fix: handle false returns from onDeleteFile in bulk delete Promise.all
* chore: remove unused @testing-library/react-hooks dependency
Kandev
Manage and run tasks in parallel. Orchestrate agents. Review changes. Ship value.
Workflows | Roadmap | Contributing | Architecture
What
Organize work across kanban and pipeline views with opinionated workflows and execute multiple tasks in parallel. Assign agents from any provider, and review their output in an integrated workspace - file editor, file tree, terminal, browser preview, and git changes in one place. Terminal agent TUIs are great for running agents, but reviewing and iterating on changes there doesn't scale.
Run it locally or self-host it on your own infrastructure and access it from anywhere via Tailscale or any VPN.
Open source, multi-provider, no telemetry, not tied to any cloud.
Vision
Humans stay in control. Define tasks, build agentic workflows with gates, review every change, decide what ships.
- Review-first - Humans support production systems. We need to understand (yet) and trust the code that gets deployed.
- Your workflow - Every team is different, and not every developer uses AI the same way. Define workflows once, share them across the team, and give everyone a consistent process for working with agents - regardless of experience level.
- Remote agents - Running multiple agents on a large codebase can quickly saturate a local machine. The goal is a single control plane: offload execution to servers, orchestrate from anywhere, including your phone.
Features
- Multi-agent support - Claude Code, Codex, GitHub Copilot, Gemini CLI, Amp, Auggie, OpenCode
- Parallel task execution – start and manage multiple tasks from different sources simultaneously, boosting productivity with AI agents
- Integrated workspace - Built-in terminal, code editor with LSP, git changes panel, embedded vscode and chat in one IDE-like view
- Kanban task management - Drag-and-drop boards, columns, and workflow automation
- Agentic workflows - Multi-step pipelines that chain agents through automated task routing. See docs/workflows.md
- CLI passthrough - Drop into raw agent CLI mode for direct terminal interaction with any supported agent, leverage the full power of their TUIs
- Workspace isolation - Git worktrees prevent concurrent agents from conflicting
- Flexible runtimes - Run agents as local processes, in isolated Docker containers or in remote executors like sprites.dev
- Session management - Resume and review agent conversations
- Stats - Track your productivity with stats on the completed tasks, agent turns, etc
Supported ACP Agents
| Agent | Protocol |
|---|---|
| Claude Code | ACP (@zed-industries/claude-agent-acp) |
| Codex | ACP (@zed-industries/codex-acp) |
| GitHub Copilot | ACP |
| Gemini CLI | ACP |
| Amp | ACP (amp-acp) |
| Auggie | ACP |
| OpenCode | ACP |
All agents communicate via ACP (Agent Client Protocol). Some agents support ACP natively, while others use ACP adapter packages that bridge their native protocols. CLI Passthrough mode is also available for direct terminal interaction with any agent CLI. If your agent isn't supported yet, open an issue or submit a PR with the integration. See Adding a New Agent CLI for a step-by-step guide.
Bring your own TUI agents
There is support for running any agent as TUI inside a terminal. Just add the cli command in the agent profile settings and the task will start the agent inside a PTY terminal instead of using ACP.
Supported Executors
| Executor | Description |
|---|---|
| Local Process | Runs the agent as a local process on the host machine |
| Docker | Runs the agent in an isolated Docker container |
| Sprites | Runs the agent in a remote cloud environment via sprites.dev |
Each executor uses git worktrees for workspace isolation, preventing concurrent agents from conflicting.
Quick Start
NPX (recommended)
npx kandev
This downloads pre-built backend + frontend bundles and starts them locally. The worktrees and sqlite db will be created in ~/.kandev by default. Should work on macOS, Linux, and Windows (WSL or native).
From Source
# Clone the repository
git clone git@github.com:kdlbs/kandev.git
cd kandev
# Start in production mode
make start
Prerequisites: Go 1.26+, Node.js 18+, pnpm, Docker (optional - needed for container runtimes)
High level architecture
graph LR
UI[Web UI] --> Backend
Backend["Backend (Orchestrator)"]
Backend --> W1 & W2
subgraph W1[Local Process]
Agent1[Agent CLI] --- WT1[Worktree]
end
subgraph W2[Docker Container]
Agent2[Agent CLI] --- WT2[Worktree]
end
We also want to add support for these remote runtimes:
- Remote SSH - run agents on remote servers over SSH, using docker or local processes with workspace isolation
- K8s operator - run agents in a Kubernetes cluster, with auto-scaling and resource management.
Development
Project Structure
apps/
├── backend/ # Go backend (orchestrator, lifecycle, agentctl, WS gateway)
├── web/ # Next.js frontend (SSR, Zustand, real-time subscriptions)
├── cli/ # CLI tool (npx kandev launcher)
└── packages/ # Shared UI components & types
Prerequisites
- Go 1.21+
- Node.js 18+
- pnpm
- Docker (optional)
Running Dev Servers
# Start everything (backend + frontend with auto ports)
make dev
# Or run separately
make dev-backend # Backend on :8080
make dev-web # Frontend on :37429
Testing & Linting
make test # Run all tests (backend + web)
make lint # Run all linters
make typecheck # TypeScript type checking
make fmt # Format all code
Pre-commit Hooks
# Install pre-commit (https://pre-commit.com/#install)
pipx install pre-commit
# Install git hooks
pre-commit install
Comparison to Other Tools
There are a few similar tools in this space, and new ones appearing everyday. Here's what sets this one apart:
- Server-first architecture - Not a desktop app. Runs as a server you can access from any device, including your phone. Start a task away from your computer and check in on it later.
- Remote runtimes - Run agents on remote servers and Docker hosts, not just your local machine.
- Multi-provider - Use Claude Code, Codex, Copilot, Gemini, Amp, Auggie, and OpenCode side by side. Not locked to one vendor.
- CLI passthrough and chat - Interact with agents through structured chat messages or drop into raw CLI mode for full agent TUI capabilities.
- Open source and self-hostable - No vendor lock-in, no telemetry, runs on your infrastructure.
Contributing
Contributions are welcome! Please read CONTRIBUTING.md before opening a PR.
See the issue tracker for open tasks.
Acknowledgments
Built with these excellent open-source projects:
Monaco Editor · Tiptap · xterm.js · dockview · CodeMirror · dnd-kit · Mermaid · Recharts · TanStack Table · Zustand · Shadcn/UI · Radix UI · Tailwind CSS
