Files
kandev/docs/openapi.yaml
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

1294 lines
31 KiB
YAML

openapi: 3.0.3
info:
title: Kandev API
description: |
Kandev is a Kanban board system with AI agent orchestration capabilities.
## Overview
- **Task Service**: Manages tasks, boards, and columns
- **Agent Manager**: Manages Docker container lifecycle for AI agents
- **Orchestrator**: Coordinates agent execution
## Agent Communication Protocol (ACP)
Agents communicate via JSON messages on stdout. See AGENTS.md for details.
⚠️ **This documentation must be updated when API changes.**
version: 1.0.0
contact:
name: Kandev Team
license:
name: MIT
servers:
- url: http://localhost:8080/api/v1
description: Local development server
tags:
- name: Health
description: Health check endpoints
- name: Boards
description: Kanban board management
- name: Columns
description: Board column management
- name: Tasks
description: Task management
- name: Agents
description: AI agent lifecycle management
- name: Agent Types
description: Available agent type configurations
- name: Orchestrator
description: Task orchestration and execution control
paths:
/health:
get:
tags: [Health]
summary: Health check
operationId: healthCheck
responses:
'200':
description: Service is healthy
content:
application/json:
schema:
$ref: '#/components/schemas/HealthResponse'
# ============ BOARDS ============
/boards:
get:
tags: [Boards]
summary: List all boards
operationId: listBoards
responses:
'200':
description: List of boards
content:
application/json:
schema:
$ref: '#/components/schemas/BoardsListResponse'
post:
tags: [Boards]
summary: Create a new board
operationId: createBoard
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateBoardRequest'
responses:
'201':
description: Board created
content:
application/json:
schema:
$ref: '#/components/schemas/Board'
'400':
$ref: '#/components/responses/BadRequest'
/boards/{boardId}:
parameters:
- $ref: '#/components/parameters/boardId'
get:
tags: [Boards]
summary: Get a board by ID
operationId: getBoard
responses:
'200':
description: Board details
content:
application/json:
schema:
$ref: '#/components/schemas/Board'
'404':
$ref: '#/components/responses/NotFound'
put:
tags: [Boards]
summary: Update a board
operationId: updateBoard
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateBoardRequest'
responses:
'200':
description: Board updated
content:
application/json:
schema:
$ref: '#/components/schemas/Board'
'404':
$ref: '#/components/responses/NotFound'
delete:
tags: [Boards]
summary: Delete a board
operationId: deleteBoard
responses:
'204':
description: Board deleted
'404':
$ref: '#/components/responses/NotFound'
/boards/{boardId}/columns:
parameters:
- $ref: '#/components/parameters/boardId'
get:
tags: [Columns]
summary: List columns in a board
operationId: listColumns
responses:
'200':
description: List of columns
content:
application/json:
schema:
$ref: '#/components/schemas/ColumnsListResponse'
post:
tags: [Columns]
summary: Create a column in a board
operationId: createColumn
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateColumnRequest'
responses:
'201':
description: Column created
content:
application/json:
schema:
$ref: '#/components/schemas/Column'
'400':
$ref: '#/components/responses/BadRequest'
/boards/{boardId}/tasks:
parameters:
- $ref: '#/components/parameters/boardId'
get:
tags: [Tasks]
summary: List tasks in a board
operationId: listTasksInBoard
responses:
'200':
description: List of tasks
content:
application/json:
schema:
$ref: '#/components/schemas/TasksListResponse'
# ============ COLUMNS ============
/columns/{columnId}:
parameters:
- $ref: '#/components/parameters/columnId'
get:
tags: [Columns]
summary: Get a column by ID
operationId: getColumn
responses:
'200':
description: Column details
content:
application/json:
schema:
$ref: '#/components/schemas/Column'
'404':
$ref: '#/components/responses/NotFound'
# ============ TASKS ============
/tasks:
post:
tags: [Tasks]
summary: Create a new task
operationId: createTask
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTaskRequest'
responses:
'201':
description: Task created
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
'400':
$ref: '#/components/responses/BadRequest'
/tasks/{taskId}:
parameters:
- $ref: '#/components/parameters/taskId'
get:
tags: [Tasks]
summary: Get a task by ID
operationId: getTask
responses:
'200':
description: Task details
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
'404':
$ref: '#/components/responses/NotFound'
put:
tags: [Tasks]
summary: Update a task
operationId: updateTask
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateTaskRequest'
responses:
'200':
description: Task updated
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
'404':
$ref: '#/components/responses/NotFound'
delete:
tags: [Tasks]
summary: Delete a task
operationId: deleteTask
responses:
'204':
description: Task deleted
'404':
$ref: '#/components/responses/NotFound'
/tasks/{taskId}/state:
parameters:
- $ref: '#/components/parameters/taskId'
put:
tags: [Tasks]
summary: Update task state
operationId: updateTaskState
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateTaskStateRequest'
responses:
'200':
description: Task state updated
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
'404':
$ref: '#/components/responses/NotFound'
/tasks/{taskId}/move:
parameters:
- $ref: '#/components/parameters/taskId'
put:
tags: [Tasks]
summary: Move task to different column
operationId: moveTask
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MoveTaskRequest'
responses:
'200':
description: Task moved
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
'404':
$ref: '#/components/responses/NotFound'
# ============ AGENTS ============
/agents:
get:
tags: [Agents]
summary: List all active agents
operationId: listAgents
responses:
'200':
description: List of agents
content:
application/json:
schema:
$ref: '#/components/schemas/AgentsListResponse'
/agents/launch:
post:
tags: [Agents]
summary: Launch a new agent
operationId: launchAgent
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LaunchAgentRequest'
responses:
'201':
description: Agent launched
content:
application/json:
schema:
$ref: '#/components/schemas/AgentInstance'
'400':
$ref: '#/components/responses/BadRequest'
/agents/types:
get:
tags: [Agent Types]
summary: List available agent types
operationId: listAgentTypes
responses:
'200':
description: List of agent types
content:
application/json:
schema:
$ref: '#/components/schemas/AgentTypesListResponse'
/agents/types/{typeId}:
parameters:
- $ref: '#/components/parameters/typeId'
get:
tags: [Agent Types]
summary: Get agent type by ID
operationId: getAgentType
responses:
'200':
description: Agent type details
content:
application/json:
schema:
$ref: '#/components/schemas/AgentType'
'404':
$ref: '#/components/responses/NotFound'
/agents/{instanceId}/status:
parameters:
- $ref: '#/components/parameters/instanceId'
get:
tags: [Agents]
summary: Get agent status
operationId: getAgentStatus
responses:
'200':
description: Agent status
content:
application/json:
schema:
$ref: '#/components/schemas/AgentInstance'
'404':
$ref: '#/components/responses/NotFound'
/agents/{instanceId}/logs:
parameters:
- $ref: '#/components/parameters/instanceId'
get:
tags: [Agents]
summary: Get agent logs
operationId: getAgentLogs
parameters:
- name: tail
in: query
description: Number of lines to return from end
schema:
type: string
default: "100"
- name: follow
in: query
description: Stream logs in real-time
schema:
type: boolean
default: false
responses:
'200':
description: Agent logs
content:
application/json:
schema:
$ref: '#/components/schemas/LogsResponse'
'404':
$ref: '#/components/responses/NotFound'
/agents/{instanceId}:
parameters:
- $ref: '#/components/parameters/instanceId'
delete:
tags: [Agents]
summary: Stop an agent
operationId: stopAgent
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/StopAgentRequest'
responses:
'200':
description: Agent stopped
content:
application/json:
schema:
$ref: '#/components/schemas/AgentInstance'
'404':
$ref: '#/components/responses/NotFound'
/agents/{instanceId}/prompt:
parameters:
- $ref: '#/components/parameters/instanceId'
post:
tags: [Agents]
summary: Send prompt to agent (ACP)
description: Send a message/prompt to a running agent via ACP protocol
operationId: sendAgentPrompt
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SendPromptRequest'
responses:
'200':
description: Prompt sent successfully
content:
application/json:
schema:
$ref: '#/components/schemas/SendPromptResponse'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalError'
/agents/{instanceId}/cancel:
parameters:
- $ref: '#/components/parameters/instanceId'
post:
tags: [Agents]
summary: Cancel agent operation (ACP)
description: Send a cancellation request to a running agent via ACP protocol
operationId: cancelAgent
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CancelAgentRequest'
responses:
'200':
description: Cancel request sent
content:
application/json:
schema:
$ref: '#/components/schemas/CancelAgentResponse'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalError'
/agents/{instanceId}/session:
parameters:
- $ref: '#/components/parameters/instanceId'
get:
tags: [Agents]
summary: Get agent ACP session
description: Get the current ACP session information for an agent
operationId: getAgentSession
responses:
'200':
description: Session information
content:
application/json:
schema:
$ref: '#/components/schemas/GetSessionResponse'
'404':
$ref: '#/components/responses/NotFound'
# ============ ORCHESTRATOR ============
/orchestrator/status:
get:
tags: [Orchestrator]
summary: Get orchestrator status
operationId: getOrchestratorStatus
responses:
'200':
description: Orchestrator status
content:
application/json:
schema:
$ref: '#/components/schemas/OrchestratorStatus'
/orchestrator/queue:
get:
tags: [Orchestrator]
summary: Get task queue
operationId: getQueue
responses:
'200':
description: Task queue
content:
application/json:
schema:
$ref: '#/components/schemas/QueueResponse'
/orchestrator/trigger:
post:
tags: [Orchestrator]
summary: Manually trigger task execution
operationId: triggerTask
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TriggerTaskRequest'
responses:
'200':
description: Task triggered
'400':
$ref: '#/components/responses/BadRequest'
/orchestrator/tasks/{taskId}/start:
parameters:
- $ref: '#/components/parameters/taskId'
post:
tags: [Orchestrator]
summary: Start task execution
operationId: startTask
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/StartTaskRequest'
responses:
'200':
description: Task started
'404':
$ref: '#/components/responses/NotFound'
/orchestrator/tasks/{taskId}/stop:
parameters:
- $ref: '#/components/parameters/taskId'
post:
tags: [Orchestrator]
summary: Stop task execution
operationId: stopTask
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/StopTaskRequest'
responses:
'200':
description: Task stopped
'404':
$ref: '#/components/responses/NotFound'
/orchestrator/tasks/{taskId}/pause:
parameters:
- $ref: '#/components/parameters/taskId'
post:
tags: [Orchestrator]
summary: Pause task execution
operationId: pauseTask
responses:
'200':
description: Task paused
'404':
$ref: '#/components/responses/NotFound'
/orchestrator/tasks/{taskId}/resume:
parameters:
- $ref: '#/components/parameters/taskId'
post:
tags: [Orchestrator]
summary: Resume task execution
operationId: resumeTask
responses:
'200':
description: Task resumed
'404':
$ref: '#/components/responses/NotFound'
/orchestrator/tasks/{taskId}/status:
parameters:
- $ref: '#/components/parameters/taskId'
get:
tags: [Orchestrator]
summary: Get task execution status
operationId: getTaskExecutionStatus
responses:
'200':
description: Task execution status
content:
application/json:
schema:
$ref: '#/components/schemas/TaskStatusResponse'
'404':
$ref: '#/components/responses/NotFound'
/orchestrator/tasks/{taskId}/logs:
parameters:
- $ref: '#/components/parameters/taskId'
get:
tags: [Orchestrator]
summary: Get task execution logs
operationId: getTaskLogs
responses:
'200':
description: Task logs
content:
application/json:
schema:
$ref: '#/components/schemas/OrchestratorLogsResponse'
'404':
$ref: '#/components/responses/NotFound'
/orchestrator/tasks/{taskId}/artifacts:
parameters:
- $ref: '#/components/parameters/taskId'
get:
tags: [Orchestrator]
summary: Get task artifacts
operationId: getTaskArtifacts
responses:
'200':
description: Task artifacts
content:
application/json:
schema:
$ref: '#/components/schemas/ArtifactsResponse'
'404':
$ref: '#/components/responses/NotFound'
# ============ COMPONENTS ============
components:
parameters:
boardId:
name: boardId
in: path
required: true
description: Board ID
schema:
type: string
format: uuid
columnId:
name: columnId
in: path
required: true
description: Column ID
schema:
type: string
format: uuid
taskId:
name: taskId
in: path
required: true
description: Task ID
schema:
type: string
format: uuid
instanceId:
name: instanceId
in: path
required: true
description: Agent instance ID
schema:
type: string
format: uuid
typeId:
name: typeId
in: path
required: true
description: Agent type ID
schema:
type: string
responses:
BadRequest:
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
InternalError:
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
schemas:
# ============ COMMON ============
Error:
type: object
properties:
error:
type: string
description: Error code
message:
type: string
description: Human readable message
details:
type: string
description: Additional details
http_status:
type: integer
description: HTTP status code
required: [error, message, http_status]
HealthResponse:
type: object
properties:
status:
type: string
example: ok
required: [status]
# ============ BOARDS ============
Board:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
description:
type: string
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
required: [id, name, created_at, updated_at]
CreateBoardRequest:
type: object
properties:
name:
type: string
minLength: 1
description:
type: string
required: [name]
UpdateBoardRequest:
type: object
properties:
name:
type: string
description:
type: string
BoardsListResponse:
type: object
properties:
boards:
type: array
items:
$ref: '#/components/schemas/Board'
total:
type: integer
required: [boards, total]
# ============ COLUMNS ============
Column:
type: object
properties:
id:
type: string
format: uuid
board_id:
type: string
format: uuid
name:
type: string
position:
type: integer
state:
type: string
enum: [TODO, IN_PROGRESS, DONE]
created_at:
type: string
format: date-time
required: [id, board_id, name, position, created_at]
CreateColumnRequest:
type: object
properties:
name:
type: string
minLength: 1
position:
type: integer
default: 0
state:
type: string
enum: [TODO, IN_PROGRESS, DONE]
required: [name]
ColumnsListResponse:
type: object
properties:
columns:
type: array
items:
$ref: '#/components/schemas/Column'
total:
type: integer
required: [columns, total]
# ============ TASKS ============
Task:
type: object
properties:
id:
type: string
format: uuid
board_id:
type: string
format: uuid
column_id:
type: string
format: uuid
title:
type: string
description:
type: string
state:
type: string
enum: [TODO, IN_PROGRESS, BLOCKED, COMPLETED, FAILED, CANCELLED]
priority:
type: integer
agent_type:
type: string
position:
type: integer
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
metadata:
type: object
additionalProperties: true
description: Includes auggie_session_id after agent execution
required: [id, board_id, column_id, title, state, created_at, updated_at]
CreateTaskRequest:
type: object
properties:
board_id:
type: string
format: uuid
column_id:
type: string
format: uuid
title:
type: string
minLength: 1
description:
type: string
priority:
type: integer
default: 0
agent_type:
type: string
metadata:
type: object
additionalProperties: true
required: [board_id, column_id, title]
UpdateTaskRequest:
type: object
properties:
title:
type: string
description:
type: string
priority:
type: integer
agent_type:
type: string
metadata:
type: object
additionalProperties: true
UpdateTaskStateRequest:
type: object
properties:
state:
type: string
enum: [TODO, IN_PROGRESS, BLOCKED, COMPLETED, FAILED, CANCELLED]
required: [state]
MoveTaskRequest:
type: object
properties:
column_id:
type: string
format: uuid
position:
type: integer
required: [column_id]
TasksListResponse:
type: object
properties:
tasks:
type: array
items:
$ref: '#/components/schemas/Task'
total:
type: integer
required: [tasks, total]
# ============ AGENTS ============
AgentInstance:
type: object
properties:
id:
type: string
format: uuid
task_id:
type: string
format: uuid
agent_type:
type: string
container_id:
type: string
status:
type: string
enum: [starting, running, completed, failed, stopped]
progress:
type: integer
minimum: 0
maximum: 100
started_at:
type: string
format: date-time
finished_at:
type: string
format: date-time
nullable: true
exit_code:
type: integer
nullable: true
error_message:
type: string
metadata:
type: object
additionalProperties: true
required: [id, task_id, agent_type, status, progress, started_at]
LaunchAgentRequest:
type: object
properties:
task_id:
type: string
format: uuid
agent_type:
type: string
example: augment-agent
workspace_path:
type: string
description: Absolute path to the project directory
env:
type: object
additionalProperties:
type: string
description: Environment variables (AUGMENT_SESSION_AUTH, TASK_DESCRIPTION, etc.)
priority:
type: integer
default: 0
metadata:
type: object
additionalProperties: true
required: [task_id, agent_type, workspace_path]
StopAgentRequest:
type: object
properties:
force:
type: boolean
default: false
reason:
type: string
SendPromptRequest:
type: object
properties:
message:
type: string
description: The prompt message to send to the agent
required: [message]
SendPromptResponse:
type: object
properties:
success:
type: boolean
message:
type: string
required: [success]
CancelAgentRequest:
type: object
properties:
reason:
type: string
description: Reason for cancellation
CancelAgentResponse:
type: object
properties:
success:
type: boolean
message:
type: string
required: [success]
GetSessionResponse:
type: object
properties:
instance_id:
type: string
task_id:
type: string
session_id:
type: string
status:
type: string
enum: [initializing, ready, running, completed, failed]
created_at:
type: string
format: date-time
required: [instance_id, status, created_at]
AgentsListResponse:
type: object
properties:
agents:
type: array
items:
$ref: '#/components/schemas/AgentInstance'
total:
type: integer
required: [agents, total]
AgentType:
type: object
properties:
id:
type: string
name:
type: string
description:
type: string
image:
type: string
capabilities:
type: array
items:
type: string
enabled:
type: boolean
required: [id, name, image, enabled]
AgentTypesListResponse:
type: object
properties:
types:
type: array
items:
$ref: '#/components/schemas/AgentType'
total:
type: integer
required: [types, total]
LogsResponse:
type: object
properties:
logs:
type: array
items:
type: object
properties:
timestamp:
type: string
format: date-time
message:
type: string
stream:
type: string
enum: [stdout, stderr]
total:
type: integer
required: [logs, total]
# ============ ORCHESTRATOR ============
OrchestratorStatus:
type: object
properties:
running:
type: boolean
queue_size:
type: integer
active_tasks:
type: integer
QueueResponse:
type: object
properties:
tasks:
type: array
items:
$ref: '#/components/schemas/QueuedTask'
total:
type: integer
required: [tasks, total]
QueuedTask:
type: object
properties:
task_id:
type: string
format: uuid
priority:
type: integer
queued_at:
type: string
format: date-time
estimated_start:
type: string
format: date-time
nullable: true
required: [task_id, priority, queued_at]
TriggerTaskRequest:
type: object
properties:
task_id:
type: string
format: uuid
force:
type: boolean
default: false
required: [task_id]
StartTaskRequest:
type: object
properties:
agent_type:
type: string
priority:
type: integer
default: 0
StopTaskRequest:
type: object
properties:
reason:
type: string
force:
type: boolean
default: false
TaskStatusResponse:
type: object
properties:
task_id:
type: string
format: uuid
state:
type: string
agent_instance_id:
type: string
format: uuid
agent_type:
type: string
started_at:
type: string
format: date-time
nullable: true
progress:
type: integer
current_operation:
type: string
estimated_completion:
type: string
format: date-time
nullable: true
required: [task_id, state, progress]
OrchestratorLogsResponse:
type: object
properties:
logs:
type: array
items:
type: object
properties:
timestamp:
type: string
format: date-time
level:
type: string
enum: [debug, info, warn, error]
message:
type: string
metadata:
type: object
additionalProperties: true
total:
type: integer
required: [logs, total]
ArtifactsResponse:
type: object
properties:
artifacts:
type: array
items:
$ref: '#/components/schemas/Artifact'
Artifact:
type: object
properties:
id:
type: string
name:
type: string
type:
type: string
enum: [report, code, log]
size:
type: integer
format: int64
created_at:
type: string
format: date-time
download_url:
type: string
required: [id, name, type, size, created_at]