Files
kandev/AGENTS.md
T
jcfs aebb0c0c76 Implement bidirectional ACP communication with agents
- Add ACP session manager for JSON-RPC 2.0 over stdin/stdout
- Create jsonrpc package with Client for bidirectional communication
- Update agent.sh to run auggie --acp mode
- Add Docker client methods for container stdin/stdout attachment
- Update lifecycle manager to use ACP instead of log streaming
- Add new API endpoints: POST /prompt, POST /cancel, GET /session
- Update AGENTS.md with ACP protocol documentation
- Update OpenAPI spec with new endpoints and schemas

This enables:
- Sending prompts to running agents
- Cancelling agent operations
- Session management (create, load, resume)
- Real-time progress updates via session/update notifications
2026-01-10 10:51:11 +00:00

15 KiB

Kandev Agents Guide

⚠️ IMPORTANT: API documentation must be updated whenever the API changes. When modifying any endpoint, request/response types, or ACP messages, update:

  • This document (AGENTS.md)
  • The OpenAPI spec (docs/openapi.yaml)

📖 Full API Reference: See docs/openapi.yaml for the complete OpenAPI 3.0 specification. You can view it with Swagger UI, Redoc, or import it into Postman.

Overview

Kandev uses Docker containers to run AI agents that execute tasks from the Kanban board. Agents communicate with the backend using the Agent Communication Protocol (ACP), a JSON-based streaming protocol.

Architecture

┌─────────────────┐     ┌──────────────────┐     ┌─────────────────────────────────┐
│   HTTP Client   │────▶│  Kandev Backend  │────▶│      Docker Container           │
│  (Frontend/CLI) │     │   (Port 8080)    │     │  ┌─────────────────────────┐    │
└─────────────────┘     └────────┬─────────┘     │  │  auggie --acp           │    │
                                 │               │  │  (ACP Mode)             │    │
                                 │◀─────────────▶│  └─────────────────────────┘    │
                                 │   JSON-RPC    │                                 │
                                 │  stdin/stdout └─────────────────────────────────┘
                                 │
                        ┌──────────────────┐
                        │   Event Bus      │
                        │ (In-Memory)      │
                        └──────────────────┘

Bidirectional Communication:

  • Backend → Agent: session/prompt, session/cancel
  • Agent → Backend: session/update notifications

Available Agent Types

Augment Agent (augment-agent)

The primary AI coding agent powered by Auggie CLI.

Property Value
Image kandev/augment-agent:latest
Working Directory /workspace
Memory Limit 4096 MB
CPU Cores 2.0
Timeout 1 hour
Capabilities code_generation, code_review, refactoring, testing, shell_execution

Required Environment Variables:

  • AUGMENT_SESSION_AUTH - Augment CLI session authentication (from ~/.augment/session.json)
  • TASK_DESCRIPTION - The task for the agent to execute

Optional Environment Variables:

  • AUGGIE_SESSION_ID - Resume a previous session (for follow-up tasks)

Mounted Volumes:

  • {workspace} → /workspace - The project directory
  • {augment_sessions} → /root/.augment/sessions - Session persistence

Agent Communication Protocol (ACP)

Kandev uses ACP (Agent Client Protocol) for bidirectional communication with agents. ACP is based on JSON-RPC 2.0 over stdin/stdout.

ACP Mode

Agents run in ACP mode using auggie --acp. This enables:

  • Bidirectional communication: Send prompts and receive updates
  • Session management: Create, load, and resume sessions
  • Cancellation: Cancel operations in progress

JSON-RPC 2.0 Protocol

Client → Agent (Requests)

Initialize Connection:

{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {
  "protocolVersion": "1.0",
  "clientInfo": {"name": "kandev", "version": "0.1.0"},
  "capabilities": {"streaming": true}
}}

Create New Session:

{"jsonrpc": "2.0", "id": 2, "method": "session/new", "params": {}}

Resume Existing Session:

{"jsonrpc": "2.0", "id": 3, "method": "session/load", "params": {"sessionId": "abc123"}}

Send Prompt:

{"jsonrpc": "2.0", "id": 4, "method": "session/prompt", "params": {"message": "Fix the bug in main.go"}}

Cancel Operation (notification, no response):

{"jsonrpc": "2.0", "method": "session/cancel", "params": {"reason": "user requested"}}

Agent → Client (Notifications)

Session Update (progress, content, tool calls):

{"jsonrpc": "2.0", "method": "session/update", "params": {
  "type": "content",
  "data": {"text": "I'm analyzing the code..."}
}}
{"jsonrpc": "2.0", "method": "session/update", "params": {
  "type": "toolCall",
  "data": {"toolName": "file_edit", "status": "running"}
}}
{"jsonrpc": "2.0", "method": "session/update", "params": {
  "type": "complete",
  "data": {"sessionId": "abc123", "success": true}
}}

Legacy Message Format (for reference)

{
  "type": "progress",
  "agent_id": "uuid",
  "task_id": "uuid",
  "timestamp": "2026-01-10T12:00:00Z",
  "data": { ... }
}

Legacy Message Types

progress - Progress Updates

{
  "type": "progress",
  "data": {
    "progress": 50,
    "message": "Analyzing codebase...",
    "current_file": "src/main.go",
    "files_processed": 10,
    "total_files": 20
  }
}

log - Log Messages

{
  "type": "log",
  "data": {
    "level": "info",
    "message": "Starting code review",
    "metadata": { "file": "main.go" }
  }
}

Levels: debug, info, warn, error

result - Task Completion

{
  "type": "result",
  "data": {
    "status": "completed",
    "summary": "Task completed successfully",
    "artifacts": [
      { "type": "report", "path": "/workspace/report.md" }
    ]
  }
}

Status: completed, failed, cancelled

error - Error Messages

{
  "type": "error",
  "data": {
    "error": "Failed to parse file",
    "file": "broken.go",
    "details": "syntax error on line 42"
  }
}

status - Agent Status Changes

{
  "type": "status",
  "data": {
    "status": "running",
    "message": "Agent initialized"
  }
}

Status: started, running, paused, stopped

heartbeat - Keep-Alive

{
  "type": "heartbeat",
  "data": {}
}

REST API Reference

Base URL: http://localhost:8080/api/v1

Health Check

GET /health

Response:

{
  "status": "ok"
}

Boards API

Create Board

POST /boards

Request:

{
  "name": "My Project",
  "description": "Project tasks"
}

Response: 201 Created

{
  "id": "uuid",
  "name": "My Project",
  "description": "Project tasks",
  "created_at": "2026-01-10T12:00:00Z",
  "updated_at": "2026-01-10T12:00:00Z"
}

List Boards

GET /boards

Response:

{
  "boards": [...],
  "total": 5
}

Get Board

GET /boards/:boardId

Update Board

PUT /boards/:boardId

Request:

{
  "name": "Updated Name",
  "description": "Updated description"
}

Delete Board

DELETE /boards/:boardId

Columns API

Create Column

POST /boards/:boardId/columns

Request:

{
  "name": "To Do",
  "position": 0,
  "state": "TODO"
}

Response: 201 Created

{
  "id": "uuid",
  "board_id": "uuid",
  "name": "To Do",
  "position": 0,
  "state": "TODO",
  "created_at": "2026-01-10T12:00:00Z"
}

List Columns

GET /boards/:boardId/columns

Get Column

GET /columns/:columnId

Tasks API

Create Task

POST /tasks

Request:

{
  "board_id": "uuid",
  "column_id": "uuid",
  "title": "Fix login bug",
  "description": "Users cannot login with email",
  "priority": 1,
  "agent_type": "augment-agent",
  "metadata": {}
}

Response: 201 Created

{
  "id": "uuid",
  "board_id": "uuid",
  "column_id": "uuid",
  "title": "Fix login bug",
  "description": "Users cannot login with email",
  "state": "TODO",
  "priority": 1,
  "agent_type": "augment-agent",
  "position": 0,
  "created_at": "2026-01-10T12:00:00Z",
  "updated_at": "2026-01-10T12:00:00Z",
  "metadata": {}
}

Get Task

GET /tasks/:taskId

Update Task

PUT /tasks/:taskId

Request (all fields optional):

{
  "title": "Updated title",
  "description": "Updated description",
  "priority": 2,
  "metadata": { "key": "value" }
}

Delete Task

DELETE /tasks/:taskId

Update Task State

PUT /tasks/:taskId/state

Request:

{
  "state": "IN_PROGRESS"
}

States: TODO, IN_PROGRESS, BLOCKED, COMPLETED, FAILED, CANCELLED

Move Task

PUT /tasks/:taskId/move

Request:

{
  "column_id": "uuid",
  "position": 0
}

List Tasks in Board

GET /boards/:boardId/tasks

Agents API

Launch Agent

POST /agents/launch

Request:

{
  "task_id": "uuid",
  "agent_type": "augment-agent",
  "workspace_path": "/path/to/project",
  "env": {
    "AUGMENT_SESSION_AUTH": "...",
    "TASK_DESCRIPTION": "Analyze this codebase"
  },
  "priority": 1,
  "metadata": {}
}

Response: 201 Created

{
  "id": "uuid",
  "task_id": "uuid",
  "agent_type": "augment-agent",
  "container_id": "docker-container-id",
  "status": "starting",
  "progress": 0,
  "started_at": "2026-01-10T12:00:00Z"
}

List Agents

GET /agents

Response:

{
  "agents": [...],
  "total": 3
}

Get Agent Status

GET /agents/:instanceId/status

Response:

{
  "id": "uuid",
  "task_id": "uuid",
  "agent_type": "augment-agent",
  "container_id": "docker-container-id",
  "status": "running",
  "progress": 50,
  "started_at": "2026-01-10T12:00:00Z",
  "finished_at": null,
  "exit_code": null,
  "error_message": ""
}

Agent statuses: starting, running, completed, failed, stopped

Get Agent Logs

GET /agents/:instanceId/logs?tail=100

Response:

{
  "logs": [
    {
      "timestamp": "2026-01-10T12:00:00Z",
      "message": "Starting agent...",
      "stream": "stdout"
    }
  ],
  "total": 50
}

Stop Agent

DELETE /agents/:instanceId

Request (optional body):

{
  "force": false,
  "reason": "User requested stop"
}

List Agent Types

GET /agents/types

Response:

{
  "types": [
    {
      "id": "augment-agent",
      "name": "Augment Coding Agent",
      "description": "Auggie CLI-powered autonomous coding agent",
      "image": "kandev/augment-agent",
      "capabilities": ["code_generation", "code_review", "refactoring", "testing", "shell_execution"],
      "enabled": true
    }
  ],
  "total": 1
}

Get Agent Type

GET /agents/types/:typeId

Send Prompt to Agent (ACP)

POST /agents/:instanceId/prompt

Request:

{
  "message": "Fix the bug in main.go"
}

Response: 200 OK

{
  "success": true,
  "message": "Prompt sent successfully"
}

Cancel Agent Operation (ACP)

POST /agents/:instanceId/cancel

Request:

{
  "reason": "User requested cancellation"
}

Response: 200 OK

{
  "success": true,
  "message": "Cancel request sent"
}

Get Agent Session (ACP)

GET /agents/:instanceId/session

Response: 200 OK

{
  "instance_id": "uuid",
  "task_id": "uuid",
  "session_id": "abc123",
  "status": "running",
  "created_at": "2026-01-10T12:00:00Z"
}

Orchestrator API

Base: /api/v1/orchestrator

Get Orchestrator Status

GET /orchestrator/status

Get Task Queue

GET /orchestrator/queue

Response:

{
  "tasks": [
    {
      "task_id": "uuid",
      "priority": 1,
      "queued_at": "2026-01-10T12:00:00Z"
    }
  ],
  "total": 5
}

Trigger Task Execution

POST /orchestrator/trigger

Request:

{
  "task_id": "uuid",
  "force": false
}

Start Task

POST /orchestrator/tasks/:taskId/start

Stop Task

POST /orchestrator/tasks/:taskId/stop

Pause Task

POST /orchestrator/tasks/:taskId/pause

Resume Task

POST /orchestrator/tasks/:taskId/resume

Get Task Execution Status

GET /orchestrator/tasks/:taskId/status

Get Task Logs

GET /orchestrator/tasks/:taskId/logs

Get Task Artifacts

GET /orchestrator/tasks/:taskId/artifacts

Session Resumption

Agents can resume previous sessions for follow-up tasks:

  1. First task - Launch agent normally, session ID stored in task metadata
  2. Get session ID from task: GET /tasks/:taskId → metadata.auggie_session_id
  3. Follow-up task - Launch with AUGGIE_SESSION_ID env var

Example:

# Get session ID from completed task
SESSION_ID=$(curl -s http://localhost:8080/api/v1/tasks/$TASK_ID | jq -r '.metadata.auggie_session_id')

# Launch follow-up with session resumption
curl -X POST http://localhost:8080/api/v1/agents/launch \
  -H "Content-Type: application/json" \
  -d '{
    "task_id": "'$NEW_TASK_ID'",
    "agent_type": "augment-agent",
    "workspace_path": "/path/to/project",
    "env": {
      "AUGMENT_SESSION_AUTH": "...",
      "AUGGIE_SESSION_ID": "'$SESSION_ID'",
      "TASK_DESCRIPTION": "What was my previous question?"
    }
  }'

Error Responses

All error responses follow this format:

{
  "error": "error_code",
  "message": "Human readable message",
  "details": "Additional details",
  "http_status": 400
}

Common error codes:

  • bad_request (400) - Invalid request body or parameters
  • not_found (404) - Resource not found
  • validation_error (400) - Validation failed
  • internal_error (500) - Server error

Creating Custom Agents

To create a new agent type:

  1. Create Dockerfile in backend/dockerfiles/your-agent/
  2. Implement ACP - Write JSON messages to stdout
  3. Register agent in backend/internal/agent/registry/defaults.go
  4. Build image: docker build -t kandev/your-agent:latest .

Example agent script:

#!/bin/bash
echo '{"type":"status","agent_id":"'$AGENT_ID'","task_id":"'$TASK_ID'","timestamp":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","data":{"status":"started"}}'
echo '{"type":"progress","agent_id":"'$AGENT_ID'","task_id":"'$TASK_ID'","timestamp":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","data":{"progress":50,"message":"Working..."}}'
# Do work here
echo '{"type":"result","agent_id":"'$AGENT_ID'","task_id":"'$TASK_ID'","timestamp":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","data":{"status":"completed","summary":"Done!"}}'

Development Notes

Running Locally

cd backend
make build
./bin/kandev

Running Tests

cd backend
go test ./...

Environment Variables

Variable Default Description
KANDEV_DB_PATH ./kandev.db SQLite database path
PORT 8080 HTTP server port

Last Updated: 2026-01-10