From c36a5d28c05fd633c15d3c7fc1692be5d906c18e Mon Sep 17 00:00:00 2001 From: jcfs Date: Sat, 10 Jan 2026 10:23:34 +0000 Subject: [PATCH] Add OpenAPI 3.0 specification for complete API documentation - docs/openapi.yaml: Full OpenAPI 3.0 spec (1174 lines) - All endpoints for Health, Boards, Columns, Tasks APIs - Agent lifecycle APIs (launch, stop, status, logs, types) - Orchestrator APIs (queue, trigger, task control) - Complete request/response schemas - Parameter definitions and error responses - Updated AGENTS.md to reference OpenAPI spec Compatible with Swagger UI, Redoc, and Postman. --- AGENTS.md | 9 +- docs/openapi.yaml | 1174 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1181 insertions(+), 2 deletions(-) create mode 100644 docs/openapi.yaml diff --git a/AGENTS.md b/AGENTS.md index 897dd6b736..0832f8c265 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,12 @@ # Kandev Agents Guide -> ⚠️ **IMPORTANT**: API documentation in this file must be updated whenever the API changes. -> When modifying any endpoint, request/response types, or ACP messages, update this document accordingly. +> ⚠️ **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](docs/openapi.yaml) for the complete OpenAPI 3.0 specification. +You can view it with Swagger UI, Redoc, or import it into Postman. ## Overview diff --git a/docs/openapi.yaml b/docs/openapi.yaml new file mode 100644 index 0000000000..c0a56e95c7 --- /dev/null +++ b/docs/openapi.yaml @@ -0,0 +1,1174 @@ +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' + + # ============ 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 + + 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] +