Files
kandev/ARCHITECTURE.md
T
jcfs 35915ff0cb refactor: Replace REST API with WebSocket-only architecture
- Remove all REST endpoints, replace with WebSocket message-based API
- Add WebSocket gateway with Hub and Client for connection management
- Add WebSocket handlers for Task, Agent, and Orchestrator services
- Add task subscription support for real-time ACP notifications
- Update all documentation to reflect WebSocket-first architecture
- Replace docs/openapi.yaml with docs/asyncapi.yaml
- Update e2e tests to use WebSocket via websocat

WebSocket endpoint: ws://localhost:8080/ws
Message format: {id, type, action, payload, timestamp}

Available actions:
- Board: board.list, board.create, board.get, board.update, board.delete
- Column: column.list, column.create, column.get
- Task: task.list, task.create, task.get, task.update, task.delete,
        task.move, task.state, task.subscribe, task.unsubscribe
- Agent: agent.list, agent.launch, agent.status, agent.logs, agent.stop,
         agent.prompt, agent.cancel, agent.session, agent.types
- Orchestrator: orchestrator.status, orchestrator.queue, orchestrator.trigger,
                orchestrator.start, orchestrator.stop, orchestrator.prompt,
                orchestrator.complete
- Health: health.check
2026-01-10 23:01:05 +00:00

12 KiB

Kandev Architecture

Quick reference for developers and AI agents working on this codebase.

System Overview

Kandev is a kanban board with AI agent orchestration. Three main components:

┌──────────────────────────────────────────────────────────┐
│  Web UI (Next.js 16 + React 19)                         │
│  http://localhost:3000                                   │
└───────────────────────┬──────────────────────────────────┘
                        │ WebSocket (ws://localhost:8080/ws)
┌───────────────────────▼──────────────────────────────────┐
│  Backend (Go + Gin + SQLite)                             │
│  ws://localhost:8080/ws                                  │
│                                                           │
│  [Task Service] [Agent Manager] [Orchestrator]          │
│  [Event Bus: In-Memory/NATS]                            │
└───────────────────────┬──────────────────────────────────┘
                        │ ACP (JSON-RPC over stdout)
┌───────────────────────▼──────────────────────────────────┐
│  AI Agents (Docker)                                      │
│  auggie --acp                                            │
└──────────────────────────────────────────────────────────┘

Quick Start

# Install dependencies
make install

# Terminal 1: Backend
make dev-backend

# Terminal 2: Web app
make dev-web

# Build everything
make build

# Run tests
make test

Tech Stack

Web App (apps/web/)

  • Framework: Next.js 16 (App Router), React 19
  • Styling: Tailwind CSS 4, shadcn/ui
  • Language: TypeScript
  • Port: 3000

Backend (apps/backend/)

  • Language: Go 1.21+
  • Framework: Gin, Gorilla WebSocket
  • Protocol: WebSocket (message-based API)
  • Database: SQLite (WAL mode)
  • Container: Docker client
  • Logging: Zap
  • Port: 8080

Agents

  • Runtime: Docker containers
  • Protocol: ACP (JSON-RPC 2.0 over stdout)
  • Current: Augment Agent (auggie --acp)

Project Structure

.
├── Makefile               # Root build orchestration
├── ARCHITECTURE.md        # This file
├── AGENTS.md             # Agent protocol details
├── apps/
│   ├── web/              # Next.js web application
│   │   ├── app/          # Pages (App Router)
│   │   ├── components/   # React components
│   │   └── lib/          # Utilities
│   └── backend/          # Go backend services
│       ├── cmd/kandev/   # Main entry point
│       ├── internal/
│       │   ├── agent/    # Agent manager (Docker, ACP, lifecycle)
│       │   ├── task/     # Task service (CRUD, SQLite)
│       │   ├── orchestrator/  # Task execution coordinator
│   │   ├── events/       # Event bus (in-memory/NATS)
│   │   ├── gateway/      # WebSocket gateway
│   │   └── common/       # Shared utilities (config, logger, db)
│   └── pkg/
│       ├── acp/          # ACP protocol types
│       └── api/v1/       # API models
└── docs/
    └── asyncapi.yaml     # WebSocket API specification

Data Flow

  1. User creates task in web UI
  2. WebSocket task.create message → SQLite
  3. User launches agent for task
  4. WebSocket agent.launch message → Backend spawns Docker container
  5. Agent streams progress via ACP
  6. Events published to event bus
  7. WebSocket notifications pushed to UI (task.updated, agent.updated)

Backend Services

Task Service

  • Responsibility: Manage boards, columns, tasks
  • Storage: SQLite (kandev.db)
  • Tables: boards, columns, tasks

Agent Manager

  • Responsibility: Docker lifecycle, ACP streaming
  • Key Components:
    • Docker client (container management)
    • ACP session manager (JSON-RPC handler)
    • Streaming reader (parse stdout)
    • Credentials manager (mount secrets)

Orchestrator

  • Responsibility: Queue tasks, coordinate execution
  • Features: Task queue, agent launch, monitoring

WebSocket Message Types

Connection: ws://localhost:8080/ws

Message Envelope

{
  "id": "correlation-uuid",
  "type": "request|response|notification|error",
  "action": "action.name",
  "payload": {},
  "timestamp": "2026-01-10T10:30:00Z"
}

Request/Response Pattern

  • Requests include id for correlation
  • Responses include matching id
  • Notifications have no id (one-way)

Message Actions

Action Description
health.check Health check
board.list List boards
board.create Create board
board.get Get board
board.update Update board
board.delete Delete board
column.list List columns
column.create Create column
task.list List tasks
task.create Create task
task.get Get task
task.update Update task
task.delete Delete task
task.move Move task
task.state Update state
task.subscribe Subscribe to task updates
task.unsubscribe Unsubscribe from task updates
agent.list List agents
agent.launch Launch agent
agent.status Get status
agent.logs Get logs
agent.stop Stop agent
agent.prompt Send prompt
agent.cancel Cancel agent
agent.session Get session
agent.types List types
orchestrator.status Get status
orchestrator.queue Get queue
orchestrator.trigger Trigger task
orchestrator.start Start task
orchestrator.stop Stop task
orchestrator.prompt Send prompt
orchestrator.complete Complete task

Notification Types (Server → Client)

Action Description
acp.progress Agent progress update
acp.log Agent log message
acp.result Agent result
acp.error Agent error
acp.status Agent status change
acp.heartbeat Keep-alive
task.updated Task was updated
agent.updated Agent status changed

Error Response Format

{
  "id": "correlation-uuid",
  "type": "error",
  "action": "original.action",
  "payload": {
    "code": "ERROR_CODE",
    "message": "Human readable message",
    "details": {}
  },
  "timestamp": "2026-01-10T10:30:00Z"
}

Full API: See docs/asyncapi.yaml

Agent Communication Protocol (ACP)

Agents use JSON-RPC 2.0 over stdout for bidirectional communication.

Key Methods

Backend → Agent:

  • initialize - Start connection
  • session/new - Create session
  • session/load - Resume session
  • session/prompt - Send task
  • session/cancel - Cancel operation

Agent → Backend:

  • session/update - Progress notifications

Example Flow

// Backend sends
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}

// Agent responds
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"1.0",...}}

// Backend sends task
{"jsonrpc":"2.0","id":2,"method":"session/prompt","params":{"message":"Fix bug"}}

// Agent streams updates
{"jsonrpc":"2.0","method":"session/update","params":{"type":"content","data":{...}}}
{"jsonrpc":"2.0","method":"session/update","params":{"type":"complete","data":{...}}}

Details: See AGENTS.md

Configuration

Environment Variables

Variable Default Description
KANDEV_DB_PATH ./kandev.db SQLite database
PORT 8080 HTTP port
KANDEV_LOGGING_LEVEL info Log level
KANDEV_CREDENTIALS_FILE - Agent credentials

Agent Types

Augment Agent (augment-agent):

  • Image: kandev/augment-agent:latest
  • Memory: 4GB, CPU: 2 cores, Timeout: 1 hour
  • Required env: AUGMENT_SESSION_AUTH, TASK_DESCRIPTION
  • Optional env: AUGGIE_SESSION_ID (for resumption)

Development Workflow

WebSocket Usage Example (JavaScript)

const ws = new WebSocket('ws://localhost:8080/ws');

// Send request
ws.send(JSON.stringify({
  id: crypto.randomUUID(),
  type: 'request',
  action: 'board.create',
  payload: { name: 'My Project' }
}));

// Handle messages
ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.type === 'response') {
    console.log('Response:', msg.payload);
  } else if (msg.type === 'notification') {
    console.log('Notification:', msg.action, msg.payload);
  }
};

Create and Launch Agent

// Create board
ws.send(JSON.stringify({
  id: crypto.randomUUID(),
  type: 'request',
  action: 'board.create',
  payload: { name: 'My Project' }
}));

// Create task (after receiving board.create response)
ws.send(JSON.stringify({
  id: crypto.randomUUID(),
  type: 'request',
  action: 'task.create',
  payload: { board_id: BOARD_ID, title: 'Fix bug' }
}));

// Launch agent (after receiving task.create response)
ws.send(JSON.stringify({
  id: crypto.randomUUID(),
  type: 'request',
  action: 'agent.launch',
  payload: {
    task_id: TASK_ID,
    agent_type: 'augment-agent',
    workspace_path: '/path/to/project',
    env: {
      AUGMENT_SESSION_AUTH: sessionAuth,
      TASK_DESCRIPTION: 'Fix the bug'
    }
  }
}));

Session Resumption

// Get session ID from completed task
ws.send(JSON.stringify({
  id: crypto.randomUUID(),
  type: 'request',
  action: 'agent.session',
  payload: { task_id: TASK_ID }
}));

// Launch with resumption (after receiving session response)
ws.send(JSON.stringify({
  id: crypto.randomUUID(),
  type: 'request',
  action: 'agent.launch',
  payload: {
    task_id: NEW_TASK_ID,
    agent_type: 'augment-agent',
    workspace_path: '/path/to/project',
    env: {
      AUGMENT_SESSION_AUTH: sessionAuth,
      AUGGIE_SESSION_ID: SESSION_ID,
      TASK_DESCRIPTION: 'Follow-up question'
    }
  }
}));

Database

Location: ./kandev.db (SQLite with WAL mode)

Schema (apps/backend/internal/task/repository/sqlite.go):

  • boards - Board records
  • columns - Column definitions with state mapping
  • tasks - Task records with JSON metadata

Inspect:

sqlite3 kandev.db
> .tables
> SELECT * FROM tasks;

Backup:

cp kandev.db kandev.db.backup

Testing

# All tests
make test

# Backend only (216 tests)
make test-backend

# Web only
make test-web

Troubleshooting

Backend won't start

  • Port 8080 in use: lsof -i :8080
  • Docker not running: docker ps
  • DB permissions: ls -la kandev.db

Web app won't start

  • Port 3000 in use: lsof -i :3000
  • Missing deps: cd apps/web && npm install
  • Node version: node --version (need 18+)

Agents won't launch

  • Docker accessible: docker info
  • Image exists: docker images | grep kandev
  • Credentials: cat ~/.augment/session.json
  • Container logs: docker logs <container-id>

Key Files

File Purpose
Makefile Build orchestration
ARCHITECTURE.md This file
AGENTS.md Agent protocol details
docs/asyncapi.yaml WebSocket API spec
apps/backend/cmd/kandev/main.go Entry point
apps/backend/internal/agent/registry/defaults.go Agent type registry
apps/backend/internal/task/repository/sqlite.go Database schema
apps/web/app/page.tsx Web app home

Contributing

  1. Update docs when changing API (AGENTS.md + asyncapi.yaml)
  2. Run tests: make test
  3. Format code: make fmt
  4. Test full stack: make dev-backend + make dev-web

For Agent Protocol Details: See AGENTS.md For API Reference: See docs/asyncapi.yaml Last Updated: 2026-01-10