# REST API Gateway **Complete guide for accessing DevOps AI Toolkit functionality via standard HTTP REST endpoints.** ## Overview The REST API Gateway provides HTTP access to all DevOps AI Toolkit capabilities without requiring MCP protocol implementation. Perfect for: - **DevOps Engineers**: Integrate tools into automation scripts and CI/CD pipelines - **Platform Teams**: Add AI-powered Kubernetes assistance to existing HTTP-based infrastructure - **QA/Testing Teams**: Create comprehensive integration tests with simple HTTP calls - **Kubernetes Controller Developers**: Access AI tools via familiar REST patterns ### What it provides: - **Universal Tool Access**: All 9 tools available via `POST /api/v1/tools/{toolName}` endpoints - **Auto-Generated Documentation**: OpenAPI 3.0 specification with interactive documentation - **Zero Maintenance**: Automatically stays current when new tools are added - **Standard HTTP**: JSON request/response with proper status codes - **Tool Discovery**: Searchable catalog of available tools and capabilities ## Setup The REST API is automatically available when you deploy the DevOps AI Toolkit. **No special configuration is needed** - the same server provides MCP protocol, CLI, and REST API access simultaneously. **๐ŸŽฏ Follow the [Deployment Guide](../setup/deployment.md) to deploy the server.** The Kubernetes deployment automatically provides: - โœ… **REST API endpoints** on the configured ingress URL - โœ… **MCP protocol access** for AI development tools - โœ… **All dependencies** including Qdrant vector database - โœ… **Both protocols simultaneously** with no conflicts ## Quick Start ### 1. Discover Available Tools ```bash curl -s http://localhost:3456/api/v1/tools | jq '.data.tools[] | {name, description, category}' ``` **Response**: List of 9 available tools with descriptions: ```json [ { "name": "version", "description": "Get comprehensive system status including version information, Vector DB connection status, embedding service capabilities, Anthropic API connectivity, Kubernetes cluster connectivity, Kyverno policy engine status, and pattern management health check", "category": "System" }, { "name": "recommend", "description": "Deploy, create, setup, install, or run applications, infrastructure, and services on Kubernetes with AI recommendations", "category": "AI Tools" }, { "name": "remediate", "description": "AI-powered Kubernetes issue analysis that provides root cause identification and actionable remediation steps", "category": "Troubleshooting" } ] ``` ### 2. Get System Status ```bash curl -s -X POST http://localhost:3456/api/v1/tools/version \ -H "Content-Type: application/json" \ -d '{}' ``` **Response**: Comprehensive system status (truncated): ```json { "success": true, "data": { "result": { "status": "success", "system": { "version": { "version": "0.90.0", "nodeVersion": "v23.11.0", "platform": "darwin" }, "vectorDB": { "connected": true, "collections": { "patterns": {"exists": true, "documentsCount": 3}, "policies": {"exists": true, "documentsCount": 3}, "capabilities": {"exists": true, "documentsCount": 157} } }, "kubernetes": { "connected": true, "context": "kind-kind" } } } } } ``` ### 3. Access Interactive API Documentation ```bash # Get OpenAPI specification curl -s http://localhost:3456/api/v1/openapi | jq '.info' ``` **Response**: OpenAPI 3.0 specification with all tool schemas: ```json { "title": "DevOps AI Toolkit REST API", "description": "REST API gateway for DevOps AI Toolkit tools", "version": "1.0.0", "contact": { "name": "Viktor Farcic", "url": "https://devopstoolkit.live/" } } ``` ## API Reference ### Base URL and Versioning **Base URL**: `http://localhost:3456/api/v1` All endpoints use `/api/v1/` prefix for versioning. Future API changes will use new version paths (`/api/v2/`) maintaining backward compatibility. ### Core Endpoints #### Tool Discovery ```http GET /api/v1/tools ``` **Query Parameters**: - `category` - Filter by tool category (e.g., "AI Tools", "System", "Troubleshooting") - `tag` - Filter by a single tag (e.g., "kubernetes", "deployment", "analysis") - `search` - Search tool names and descriptions **Examples**: ```bash # Get all AI-powered tools curl "http://localhost:3456/api/v1/tools?category=AI%20Tools" # Find deployment-related tools curl "http://localhost:3456/api/v1/tools?tag=deployment" # Search for troubleshooting tools curl "http://localhost:3456/api/v1/tools?search=troubleshoot" ``` #### Tool Execution ```http POST /api/v1/tools/{toolName} Content-Type: application/json ``` **Request Body**: Tool-specific parameters (see OpenAPI spec for schemas) **Response**: Standardized JSON response with tool results #### OpenAPI Documentation ```http GET /api/v1/openapi ``` Returns complete OpenAPI 3.0 specification with: - All tool endpoints and schemas - Parameter descriptions and validation rules - Response formats and error codes - Interactive documentation support ### Response Format All REST API responses follow this standard format: ```json { "success": boolean, "data": { "result": any, // Tool execution result "tool": string, // Tool name "executionTime": number // Execution time in milliseconds }, "error": { // Only present if success: false "code": string, "message": string, "details": any }, "meta": { "timestamp": string, // ISO 8601 timestamp "requestId": string, // Unique request identifier "version": string // API version } } ``` ### HTTP Status Codes - **200 OK**: Successful tool execution - **400 Bad Request**: Invalid request parameters or missing required fields - **404 Not Found**: Tool does not exist - **405 Method Not Allowed**: Invalid HTTP method (tools only accept POST) - **500 Internal Server Error**: Tool execution failure or server error ## Tool Discovery and Filtering Instead of listing all tools statically, use the API to discover available tools dynamically: ### Discover All Tools ```bash curl http://your-ingress-url/api/v1/tools | jq '.data.tools[] | {name, description, category}' ``` ### Filter by Category ```bash # Get all AI-powered tools curl "http://your-ingress-url/api/v1/tools?category=AI%20Tools" # Available categories: AI Tools, Deployment, Management, System, Troubleshooting, Documentation ``` ### Filter by Tags ```bash # Find deployment-related tools curl "http://your-ingress-url/api/v1/tools?tags=deployment" # Find troubleshooting tools curl "http://your-ingress-url/api/v1/tools?tags=troubleshooting" ``` ### Search Tools ```bash # Search for specific functionality curl "http://your-ingress-url/api/v1/tools?search=kubernetes" curl "http://your-ingress-url/api/v1/tools?search=database" ``` ### Get Complete Tool Documentation For detailed parameter schemas and usage instructions: ```bash # Get OpenAPI specification with all tool schemas curl http://your-ingress-url/api/v1/openapi | jq '.paths' ``` ## Prompts Endpoints Three REST endpoints expose the shared prompt library. Each one accepts an optional `repo` parameter that, when supplied, fetches prompts from that repository instead of the one configured via `DOT_AI_USER_PROMPTS_REPO`. When `repo` is omitted, behavior is identical to the env-var-configured setup. The override can additionally carry three **optional, additive** qualifiers โ€” a subdirectory (`path`), a `branch`, and a per-request git credential (the `X-Dot-AI-Git-Token` header). They only apply to a request that already supplies `repo`, and each one defaults to today's behavior when omitted: `path` defaults to the repo root, `branch` defaults to `main`, and the credential defaults to the server's `DOT_AI_GIT_TOKEN`. > **Unchanged by default.** A request that supplies no `path`, no `branch`, and no `X-Dot-AI-Git-Token` header behaves byte-identically to v1.21.0 โ€” same clone target (repo root on `main`), same credential (`DOT_AI_GIT_TOKEN`), same response โ€” whether it uses `?repo=` or the env-var-configured repo (no `?repo=`). All three additions are opt-in per request; existing callers see zero change. A fourth endpoint โ€” `POST /api/v1/prompts/sources` โ€” works the other way around: instead of the server fetching a repo, the **caller uploads** a skill source it fetched itself, which the server then caches and renders through the same render path. It exists for sources the server cannot reach (SSO/device-gated VPNs, hardened clusters, and on-disk `--repo-dir` dev loops). It is purely additive โ€” deployments and callers that never upload see zero change. See [Ingested (CLI-uploaded) skill sources](#ingested-cli-uploaded-skill-sources) below. See the [Shared Prompt Library](../tools/prompts.md) for the user-facing tool guide. ### Endpoint Summary | Endpoint | `repo` / `path` / `branch` / `source` placement | Credential | |----------|--------------------------------------|------------| | `POST /api/v1/prompts/refresh` | JSON body: `{ "repo": "", "path": "", "branch": "" }` | `X-Dot-AI-Git-Token` header | | `GET /api/v1/prompts` | Query string: `?repo=&path=&branch=` | `X-Dot-AI-Git-Token` header | | `POST /api/v1/prompts/:promptName` | Query string: `?repo=&path=&branch=` (clone) **or** `?source=` (render an ingested source) | `X-Dot-AI-Git-Token` header | | `POST /api/v1/prompts/sources` | JSON body manifest: `{ "source", "contentHash", "files" }` โ€” no `repo`/`path`/`branch` | Never clones (n/a) | `path` and `branch` follow the same placement as `repo` on each endpoint (query string for `GET` and `POST /:promptName`, JSON body for `refresh`). The credential **always** travels as the `X-Dot-AI-Git-Token` request header โ€” never in the query string or body. See [Per-request `path`, `branch`, and credential](#per-request-path-branch-and-credential) below. The `?source=` render signal and the `POST /api/v1/prompts/sources` upload endpoint are documented under [Ingested (CLI-uploaded) skill sources](#ingested-cli-uploaded-skill-sources). > **Every endpoint is bearer-gated.** All of these requests pass through the same bearer-auth check as every non-OpenAPI route (`Authorization: Bearer `). The local-development examples below target `localhost` and omit the header for brevity; a deployed server requires it. ### The `source` field Every response from these endpoints includes a `source` field identifying which repository the prompts came from. `source` values: | Request | `source` value | |---------|----------------| | `repo` parameter supplied | The supplied URL (credentials scrubbed) | | `repo` omitted, `DOT_AI_USER_PROMPTS_REPO` set | The env-var URL (credentials scrubbed) | | `repo` omitted, no env-var repo | `"built-in"` | **Credential scrubbing**: URLs with embedded credentials are scrubbed before being echoed back. `https://user:tok@host/repo` becomes `https://***:***@host/repo`. The transform is deterministic, so the same credentialed URL always produces the same `source` value across requests. > **`source` is keyed on the repo URL only.** Adding `path`, `branch`, or the `X-Dot-AI-Git-Token` header does **not** change the `source` value for a given repo โ€” it still echoes the (scrubbed) override URL and stays stable per repo. This lets a caller use `source` as a stable skill-tagging key regardless of which subdirectory, branch, or credential it pulled with. ### Per-request `path`, `branch`, and credential These three qualifiers extend a `repo` override so a secondary source can live under a `skills/`-style subdirectory, on a non-default branch, and in a different authentication realm than the server's env-var repo. All three are optional and additive. | Qualifier | Placement | Default when omitted | |-----------|-----------|----------------------| | `path` | `?path=` (query) or `"path"` (JSON body) | Repo root | | `branch` | `?branch=` (query) or `"branch"` (JSON body) | `main` | | Credential | `X-Dot-AI-Git-Token` request header (never query/body) | Server's `DOT_AI_GIT_TOKEN` env credential | **Credential precedence.** When the `X-Dot-AI-Git-Token` header is present, the server clones the override repo with that token **for that request only**; it takes precedence over `DOT_AI_GIT_TOKEN`. When the header is absent, the override clone uses the server's `DOT_AI_GIT_TOKEN` exactly as before. The forwarded token is scoped to the host in `repo` (it is not forwarded across a cross-host redirect) and never appears in logs, error messages, the `source` field, or the cache key. > **The credential header is inert without `repo`.** A request that sends `X-Dot-AI-Git-Token` but no `?repo=` is unaffected by the header โ€” it is read only to authenticate an override clone. The env-var-configured path never changes behavior based on the header. The `path` and `branch` values map onto the same layout an env-var repo uses via `DOT_AI_USER_PROMPTS_PATH` / `DOT_AI_USER_PROMPTS_BRANCH` โ€” they are simply supplied per request instead of via deployment configuration. ### `POST /api/v1/prompts/refresh` Force-refreshes the prompts cache. Use this when you've pushed new prompts to the repository and don't want to wait for `DOT_AI_USER_PROMPTS_CACHE_TTL` to expire. **Request body** (all fields optional): | Field | Type | Description | |-------|------|-------------| | `repo` | string | Override repository URL (HTTPS). When supplied, bypasses `DOT_AI_USER_PROMPTS_REPO` for this request. | | `path` | string | Subdirectory within the override repo to load prompts from. Omit for the repo root. Only applies when `repo` is supplied. | | `branch` | string | Branch of the override repo to clone. Omit for `main`. Only applies when `repo` is supplied. | The override credential travels as the `X-Dot-AI-Git-Token` header (see [above](#per-request-path-branch-and-credential)), never as a body field. **Built-in case** (no env-var repo, no override): ```bash curl -s -X POST http://localhost:3456/api/v1/prompts/refresh \ -H "Content-Type: application/json" \ -d '{}' ``` ```json { "success": true, "data": { "refreshed": true, "promptsLoaded": 11, "source": "built-in" }, "meta": { "timestamp": "2026-05-26T19:51:50.367Z", "requestId": "rest_1779825110366_3", "version": "v1" } } ``` **Per-request override case**: ```bash curl -s -X POST http://localhost:3456/api/v1/prompts/refresh \ -H "Content-Type: application/json" \ -d '{"repo":"https://github.com/vfarcic/dot-ai-user-prompts"}' ``` ```json { "success": true, "data": { "refreshed": true, "promptsLoaded": 11, "source": "https://github.com/vfarcic/dot-ai-user-prompts" }, "meta": { "timestamp": "2026-05-26T19:52:06.738Z", "requestId": "rest_1779825126117_6", "version": "v1" } } ``` **Credential-scrubbing case**: a credentialed URL is echoed back scrubbed. ```bash curl -s -X POST http://localhost:3456/api/v1/prompts/refresh \ -H "Content-Type: application/json" \ -d '{"repo":"https://user:secrettoken@example.com/repo"}' ``` ```json { "success": true, "data": { "refreshed": true, "promptsLoaded": 11, "source": "https://***:***@example.com/repo" } } ``` > **Illustrative example** (placeholder token, non-runnable as written). The response shape is shown for reference, not captured from a live run. Replace `` with a real token โ€” it is scrubbed from logs and never appears in the response. **Subdirectory + branch + per-request credential**: load prompts from a `skills/` subdirectory on a non-default branch of a private repo, authenticating with a request-supplied token: ```bash curl -s -X POST http://localhost:3456/api/v1/prompts/refresh \ -H "Content-Type: application/json" \ -H "X-Dot-AI-Git-Token: " \ -d '{"repo":"https://forgejo.example.com/team/skills","path":"skills","branch":"team-skills"}' ``` The response has the same shape as the per-request override case above. `source` still echoes the override repo URL (`"https://forgejo.example.com/team/skills"`, credentials scrubbed) โ€” unchanged by `path`, `branch`, or the header โ€” while `promptsLoaded` reflects the prompts found under `skills/` on the `team-skills` branch. The token is used only to clone that host and never appears in the response. ### `GET /api/v1/prompts` Lists all available prompts (built-in plus user-defined). Returns the prompt names, descriptions, and any declared arguments. **Query parameters** (all optional): | Parameter | Description | |-----------|-------------| | `repo` | Override repository URL (HTTPS). When supplied, bypasses `DOT_AI_USER_PROMPTS_REPO` for this request. | | `path` | Subdirectory within the override repo to load prompts from. Omit for the repo root. Only applies when `repo` is supplied. | | `branch` | Branch of the override repo to clone. Omit for `main`. Only applies when `repo` is supplied. | The override credential travels as the `X-Dot-AI-Git-Token` header (see [above](#per-request-path-branch-and-credential)), never as a query parameter. **Built-in case**: ```bash curl -s http://localhost:3456/api/v1/prompts ``` Response (abbreviated โ€” the full response carries every prompt's metadata): ```json { "success": true, "data": { "prompts": [ { "name": "generate-cicd", "description": "Generate intelligent CI/CD workflows..." }, { "name": "generate-dockerfile", "description": "Generate production-ready..." }, { "name": "prd-create", "description": "Create documentation-first PRDs..." } ], "source": "built-in" } } ``` **Per-request override case**: ```bash curl -s "http://localhost:3456/api/v1/prompts?repo=https://github.com/vfarcic/dot-ai-user-prompts" ``` The `source` field echoes the override URL (credentials scrubbed): ```json { "success": true, "data": { "prompts": [ /* โ€ฆ */ ], "source": "https://github.com/vfarcic/dot-ai-user-prompts" } } ``` > **Illustrative example** (placeholder token, non-runnable as written). The response shape is shown for reference, not captured from a live run. Replace `` with a real token โ€” it is scrubbed from logs and never appears in the response. **Subdirectory + branch + per-request credential**: list the prompts a private cross-realm source publishes under `skills/` on a non-default branch: ```bash curl -s "http://localhost:3456/api/v1/prompts?repo=https://forgejo.example.com/team/skills&path=skills&branch=team-skills" \ -H "X-Dot-AI-Git-Token: " ``` The response shape is identical to the per-request override case above โ€” the `prompts` array carries whatever lives under `skills/` on the `team-skills` branch, and `source` still echoes `"https://forgejo.example.com/team/skills"` (unaffected by `path`, `branch`, or the header). ### `POST /api/v1/prompts/:promptName` Returns the rendered content (`messages`, optional `files`) of a single prompt by name. **Query parameters** (all optional): | Parameter | Description | |-----------|-------------| | `repo` | Override repository URL (HTTPS). When supplied, bypasses `DOT_AI_USER_PROMPTS_REPO` for this request. | | `path` | Subdirectory within the override repo to load prompts from. Omit for the repo root. Only applies when `repo` is supplied. | | `branch` | Branch of the override repo to clone. Omit for `main`. Only applies when `repo` is supplied. | | `source` | Render an already-**ingested** (CLI-uploaded) source by its identifier instead of cloning. Takes precedence over `repo`; the server never clones a `?source=` identifier. See [Ingested (CLI-uploaded) skill sources](#ingested-cli-uploaded-skill-sources). | The override credential travels as the `X-Dot-AI-Git-Token` header (see [above](#per-request-path-branch-and-credential)), never as a query parameter or body field. **Request body** (all fields optional): | Field | Type | Description | |-------|------|-------------| | `arguments` | object | Argument values for prompts that declare `arguments` in their frontmatter (substituted via `{{argumentName}}` placeholders). | **Per-request override example**: ```bash curl -s -X POST "http://localhost:3456/api/v1/prompts/prd-create?repo=https://github.com/vfarcic/dot-ai-user-prompts" \ -H "Content-Type: application/json" \ -d '{}' ``` ```json { "success": true, "data": { "messages": [ /* prompt content */ ], "source": "https://github.com/vfarcic/dot-ai-user-prompts" } } ``` > **Illustrative example** (placeholder token, non-runnable as written). The response shape is shown for reference, not captured from a live run. Replace `` with a real token โ€” it is scrubbed from logs and never appears in the response. **Subdirectory + branch + per-request credential**: render a prompt that lives under `skills/` on a non-default branch of a private cross-realm repo: ```bash curl -s -X POST "http://localhost:3456/api/v1/prompts/deploy-app?repo=https://forgejo.example.com/team/skills&path=skills&branch=team-skills" \ -H "Content-Type: application/json" \ -H "X-Dot-AI-Git-Token: " \ -d '{}' ``` The response carries the rendered `messages` for the prompt resolved under `skills/` on the `team-skills` branch; `source` still echoes `"https://forgejo.example.com/team/skills"`, unchanged by `path`, `branch`, or the header. ## Ingested (CLI-uploaded) skill sources Every endpoint above has the server **fetch** the source: the caller names a repo and the server clones it. After the per-request credential override, that model reaches any source a server-side clone can authenticate to. Two classes of source remain unreachable โ€” and in both, the laptop where the CLI runs **can** fetch while the server **cannot**: 1. **Sources the server cannot authenticate or route to**, even with a static token โ€” VPNs gated by SSO / OIDC / device attestation, and managed/hardened clusters with no egress path the operator can open. 2. **On-disk directories** โ€” work-in-progress skills on a developer's filesystem with no remote at all. For these, the CLI fetches the source locally and **uploads** it; the server caches it and renders it through the **same** render path โ€” one renderer, server-side, so a CLI-fetched skill renders byte-identically to one cloned from `?repo=`. Upload via `POST /api/v1/prompts/sources`; render via `POST /api/v1/prompts/:promptName?source=`. > **Bearer-gated, like every endpoint here.** Both the upload and the `?source=` render pass through the same `Authorization: Bearer ` check as the rest of the API. ### Source-identifier key space An uploaded source is keyed by a **stable identifier** that the render request later names verbatim via `?source=`: | CLI flag | Identifier | Server behavior | |----------|------------|-----------------| | `--repo-fetch ` | the git URL verbatim (credentials scrubbed in echoes) | render from the **ingested** source; the server **never clones** this URL โ€” the whole point is that it cannot reach it | | `--repo-dir --source-label