OpenAPI Generation
Auto-generate OpenAPI 3.0 specs and serve Swagger UI from any Cogitator server adapter.
Every Cogitator server adapter can serve an OpenAPI document and a Swagger UI. Express, Hono and Koa use the shared generator in @cogitator-ai/server-shared, which builds an OpenAPI 3.0.3 spec with one path per registered agent, workflow and swarm. Fastify delegates to @fastify/swagger, and Tetsu to @tetsujs/openapi — see their notes.
How It Works
With the shared generator, enableSwagger registers two routes:
| Route | Content-Type | Description |
|---|---|---|
/openapi.json | application/json | Raw OpenAPI 3.0.3 spec |
/docs | text/html | Swagger UI (loaded from CDN) |
Express builds the spec once in init(), Hono on the first request (then caches it), and Koa on every request. All three build it from the agents, workflows and swarms you passed to the adapter.
Paths in the spec are relative to servers, so when you don't set swagger.servers each adapter fills in where its routes live: Express uses basePath (/cogitator by default), and Hono and Koa read the mount prefix from the request (app.route('/api/ai', cogitatorApp(...)) gives [{ url: '/api/ai' }]). Swagger UI's "Try it out" then calls the right URLs. Set swagger.servers yourself to publish absolute URLs, for example one per environment:
swagger: { servers: [{ url: 'https://api.example.com/cogitator' }] },Enabling Swagger
Express
Swagger is on by default (enableSwagger: true):
const server = new CogitatorServer({
app,
cogitator,
agents: { assistant },
config: {
enableSwagger: true,
swagger: {
title: 'My API',
version: '2.0.0',
},
},
});Hono & Koa
Both use the shared generator directly — no extra dependencies needed. Swagger is off until you enable it:
const app = cogitatorApp({
cogitator,
agents: { assistant },
enableSwagger: true,
swagger: { title: 'My API' },
});Fastify and Tetsu
Fastify uses @fastify/swagger and @fastify/swagger-ui. Install them as dependencies:
pnpm add @fastify/swagger @fastify/swagger-uiawait fastify.register(cogitatorPlugin, {
cogitator,
agents: { assistant },
enableSwagger: true,
swagger: { title: 'My API', servers: [{ url: '/cogitator' }] },
});Its document is generated from the Fastify route schemas: it describes the generic routes (/cogitator/agents/{name}/run, …) and their validated bodies, not one path per agent. Swagger UI is at <prefix>/docs and the JSON at <prefix>/docs/json.
Tetsu describes each route of cogitatorController with its Zod schemas and error responses; mount docs() from @tetsujs/openapi next to it to serve /openapi.json and /docs (Tetsu Adapter).
SwaggerConfig
Express, Fastify, Hono and Koa accept the same SwaggerConfig shape:
interface SwaggerConfig {
title?: string; // default: 'Cogitator API'
description?: string; // default: 'AI Agent Runtime API'
version?: string; // default: '1.0.0'
contact?: {
name?: string;
email?: string;
url?: string;
};
license?: {
name: string;
url?: string;
};
servers?: Array<{
url: string;
description?: string;
}>; // default: where the adapter's routes are mounted
auth?: boolean; // default: whether the adapter has `auth`
}Example with full configuration:
const swagger: SwaggerConfig = {
title: 'Acme AI Platform',
description: 'Internal agent runtime for Acme Corp',
version: '3.1.0',
contact: {
name: 'Platform Team',
email: 'platform@acme.com',
url: 'https://docs.acme.com',
},
license: {
name: 'MIT',
url: 'https://opensource.org/licenses/MIT',
},
servers: [
{ url: 'https://api.acme.com/cogitator', description: 'Production' },
{ url: 'https://staging-api.acme.com/cogitator', description: 'Staging' },
{ url: 'http://localhost:3000/cogitator', description: 'Local' },
],
};Generated Spec Structure
The spec organizes endpoints into six tags:
| Tag | Endpoints |
|---|---|
health | /health, /ready |
agents | /agents, /agents/{name}/run, /agents/{name}/resume, /agents/{name}/stream |
threads | /threads/{id} (GET, DELETE), /threads/{id}/messages |
tools | /tools |
workflows | /workflows, /workflows/{name}/run, /workflows/{name}/stream |
swarms | /swarms, /swarms/{name}/run, /swarms/{name}/stream, /swarms/{name}/blackboard |
Agent, workflow, and swarm endpoints are listed per registered name. If you register agents named assistant and coder, the spec includes /agents/assistant/run, /agents/assistant/resume, /agents/assistant/stream and the same three for coder. Paths are relative to servers.
Component Schemas
The generated spec includes schemas for all request and response types:
HealthResponse— status, uptime, timestampAgentListResponse— list of agent names, descriptions, and tool namesAgentRunRequest— input (required), context, threadIdAgentRunResponse— output, threadId, usage, toolCalls, reasoning, status (completed|paused), pendingApprovalsRunUsage— inputTokens, outputTokens, totalTokens, and reasoningTokens, cachedInputTokens, cacheWriteTokens when the model reported themStreamFinishEvent— the last event of an agent stream: type, messageId, usage (the sameRunUsageas the JSON run response)AgentResumeRequest— threadId (required), decisions, defaultDecisionPendingApproval— toolCallId, toolName, arguments, description, sideEffectsToolApprovalDecision— approved (required), reasonThreadResponse— id, messages, createdAt, updatedAtAddMessageRequest— role, content, metadataToolListResponse— tool names, descriptions, parametersWorkflowListResponse— workflow names, entry points, node listsWorkflowRunRequest— input, options (maxConcurrency, maxIterations, checkpoint)WorkflowRunResponse— workflowId, state, duration, nodeResultsSwarmListResponse— swarm names, strategies, agent listsSwarmRunRequest— input (required), context, threadId, timeoutSwarmRunResponse— swarmId, strategy, output, agentResults, usageBlackboardResponse— sectionsErrorResponse— error message and code
Security Scheme
When the adapter has an auth function (or you set swagger.auth: true), the spec declares a bearerAuth scheme and an optional top-level requirement:
{
"components": {
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer"
}
}
},
"security": [{ "bearerAuth": [] }, {}]
}The empty {} keeps every operation callable without a token, since your auth function decides what a request needs; a token you enter under Authorize in Swagger UI is sent as Authorization: Bearer <token>. Without auth the spec has no security section. Set swagger.auth: false to leave it out even when auth is configured (for example when your auth reads a cookie, not a bearer token).
Fastify adds the same scheme and requirement to its @fastify/swagger document. Its paths already include the plugin prefix, so its servers stays [{ url: '/' }].
Using the Shared Generator Directly
If you need the OpenAPI spec outside of a server adapter (for code generation, testing, or CI), import the generator from @cogitator-ai/server-shared:
import { generateOpenAPISpec, generateSwaggerHTML } from '@cogitator-ai/server-shared';
import type { OpenAPIContext, SwaggerConfig } from '@cogitator-ai/server-shared';
const context: OpenAPIContext = {
agents: { assistant: myAgent },
workflows: {},
swarms: {},
};
const config: SwaggerConfig = {
title: 'My API',
version: '1.0.0',
servers: [{ url: '/cogitator' }],
auth: true,
};
const spec = generateOpenAPISpec(context, config);
const html = generateSwaggerHTML(spec);Called directly, generateOpenAPISpec uses servers as given ([{ url: '/' }] when unset) and declares bearerAuth only with auth: true.
The generateSwaggerHTML function returns a self-contained HTML page that loads Swagger UI from a CDN and embeds the spec inline. No server-side rendering or static files required. The spec's title is HTML-escaped and the embedded JSON is escaped for a <script> block, so agent names and descriptions can't inject markup into the page.