# Orquesta — Full Documentation > Prompt to Production platform. Teams write prompts, AI agents run on customer machines, the dashboard tracks everything. Backend: Next.js 16 + self-hosted Supabase + Socket.io. LLM layer: multi-model and multi-tier with smart routing. This document is the concatenated public surface of Orquesta intended for AI assistants and crawlers. Last updated automatically from the live system. --- ## 1. Architecture Three independently versioned components: - **Dashboard** (`getorquesta.com`) — Next.js 16 + React 18 + Tailwind v4. Self-hosted Supabase at `db.getorquesta.com` (PostgreSQL 15 + GoTrue + PostgREST + Storage). Socket.io realtime at `ws.getorquesta.com`. Hosted on AWS EC2 (orquesta-platform). - **orquesta-agent** (npm: `orquesta-agent`) — Node.js daemon that runs on the customer's machine, executes prompts via Claude CLI (or any configured LLM), streams logs back to the dashboard via WebSocket. - **orquesta-cli** (npm: `orquesta-cli`) — Standalone TUI coding assistant (React Ink) with its own multi-role orchestration engine. Optional dashboard sync via CLI tokens. Two SDK / CDN surfaces: - **orquesta-embed** (CDN at `/embed/v1/orquesta.min.js`) — Drop-in widget for third-party sites. Two modes: floating widget panel, sidebar builder overlay. - **Apuchat** (MCP at `apuchat.com/mcp`, server name still `rogerthat`) — Coordination channel layer used by both humans and AI agents. --- ## 2. PromptOps Orquesta is built around PromptOps: the practice of treating prompts as production assets. A prompt in Orquesta is versioned, routed to the right model tier, audited, and gated before it can ship code. The PromptOps lifecycle in Orquesta: 1. **Write** — anyone on the team submits a prompt from the dashboard, Linear, Telegram, API, or embed widget. 2. **Classify & route** — Batuta classifies the prompt and routes it to fast, balanced, or premium model tiers. 3. **Execute** — the agent runs on the customer's machine, streams logs, and produces a git commit. 4. **Review** — a teammate reviews the diff; quality gates enforce sign-off for sensitive paths. 5. **Ship** — the PR merges and deploys; every step is recorded in the audit trail. Read more at https://getorquesta.com/promptops. ### Assisted Mode (QA document in, reviewed diff out) Assisted Mode inverts step 4 for QA work. A QA teammate pastes a whole findings document into a project's Assisted panel; Orquesta reads it as ONE document (findings are deduplicated and prioritized against each other, not handled one prompt at a time) and classifies each finding as `defect_obvious`, `defect_ambiguous`, `product_decision` or `not_reproducible`. The dividing line is **obvious defect vs. product decision, never difficulty**. Only `defect_obvious` runs unattended — a control that does nothing contradicts its own label, so a hard fix still runs. A trivial-to-build feature nobody agreed on does not. `not_reproducible` goes back to QA without running. Unlike auto-evaluate, which blocks a prompt *before* it runs, assisted executes first and the reviewer opens a diff that already exists. Constraints that make that safe: - One run = one plan = one branch (`assisted/YYYYMMDD-xxxxxxxx`) = one PR, items executed strictly serially. - Auto-deploy is refused for the whole run server-side; an assisted branch never reaches production on its own. - Every diff passes a gate before the next item starts. Migrations, credential-shaped files, deletions, oversized diffs and empty diffs HALT the run; dependency, CI, auth and binary changes are flagged for the reviewer without stopping the queue. - Any project member can start a run (QA has trigger authority). Reviewing belongs to owners, admins, and members flagged `assisted_reviewer`. Internal endpoints (not part of the frozen `/api/v1` surface): `POST|GET /api/projects/:id/assisted-runs`, `GET /api/projects/:id/assisted-runs/:runId`, `POST .../advance`, `POST .../items/:itemId/review`. --- ## 3. Public API (`/api/v1/*`) All endpoints documented in machine-readable form at: - https://getorquesta.com/openapi.json (OpenAPI 3.1 JSON) - https://getorquesta.com/openapi.yaml (OpenAPI 3.1 YAML) - https://getorquesta.com/docs/api (ReDoc renderer) ### Authentication Pass an API key on every request: ``` Authorization: Bearer ``` or: ``` X-API-Key: ``` Three accepted token prefixes: | Prefix | Type | Scope | Granted Scopes | |--------|------|-------|-----------------| | `oak_` | Org API key | Organization, optionally restricted to chosen projects | DB-stored (any subset of `prompts:read`, `prompts:write`, `logs:read`, `projects:read`, `agents:read`, `analytics:read`) | | `oclt_` | CLI token | Organization | All four read scopes (synthesized) | | `oat_` | Agent token | Single project | All four read scopes; queries restricted to that project | Generate keys from https://getorquesta.com/dashboard/settings (API Keys section). Each key's scopes and its project restriction are chosen at creation and editable afterwards without re-issuing the token; a key created without an explicit scope list is read-only. A call outside a key's scopes returns 403 naming the missing scope; a call touching a project outside its restriction returns 404 (indistinguishable from a project that does not exist). ### Endpoints #### POST /api/v1/chat/completions — Batuta LLM proxy (OpenAI-compatible) Drop-in replacement for OpenAI's `/v1/chat/completions`. Pass any model id from `GET /api/v1/models`, or the synthetic `batuta-auto` to enable per-prompt classification. Request: ```json { "model": "batuta-auto", "messages": [ {"role": "user", "content": "Refactor this codebase to use async/await."} ] } ``` Optional routing headers: - `X-Batuta-Force-Tier: fast | balanced | premium` — pin tier (overrides classifier). - `X-Batuta-Session-ID: ` — opaque conversation id for cross-model attribution. Response includes routing telemetry headers: - `X-Batuta-Routed-From: batuta-auto` - `X-Batuta-Routed-To: ` - `X-Batuta-Tier: fast | balanced | premium` Error shapes are OpenAI-compatible: ```json { "error": { "message": "...", "type": "auth_error|billing_error|routing_error|proxy_error" } } ``` #### GET /api/v1/models Lists available models in OpenAI-compatible `{ object: "list", data: [...] }` shape. #### GET /api/v1/prompts List prompts in your organization. Query params: `projectId`, `createdBy`, `status` (csv), `from`, `to` (ISO), `offset` (default 0), `limit` (default 50, max 500). Response: `{ prompts: [...], pagination: { offset, limit, total, hasMore } }`. Each prompt includes: `id, content, status, source, projectId, projectName, createdBy/Email/Name, parentPromptId, complexity, tags, isStarred, tokensUsed, costCents, cliType, model, gitBranch, gitCommitSha, gitCommitUrl, linearIssueIdentifier, linearIssueUrl, createdAt, startedAt, completedAt, error`. #### POST /api/v1/prompts Submit a prompt for execution. Body: `{ projectId, content, context?, tags?, source? }` (`content` max 50,000 chars; `source` is `api` (default) or `dashboard`). Requires a token attributable to a user: a CLI token (`oclt_`), or an org API key (`oak_`) holding `prompts:write`. Agent tokens (`oat_`) are rejected. The prompt is created `pending`; the project's agent picks it up on its next heartbeat (15s) — there is no separate execute call. Poll `GET /api/v1/prompts/{id}` or `GET /api/v1/logs?promptId=...` for progress. A project you cannot reach returns 404. Response: `201 { prompt: { id, projectId, content, status, source, createdBy, createdAt } }`. #### GET /api/v1/prompts/{id} Single prompt detail. Same fields as the list, plus `context` (the structured payload sent at prompt creation). #### PATCH /api/v1/prompts/{id} Update collaboration fields: `{ is_starred?, tags?, assigned_to?, complexity? }`. Same write credentials as POST. `assigned_to` must belong to the same organization. #### POST /api/v1/prompts/{id}/cancel Stop a `pending` or `running` prompt: the agent is told to kill it and the prompt is marked `failed` ("Cancelled by user"). Returns `{ cancelled, status }`; a prompt that already finished keeps its outcome. Same write credentials as POST. #### GET /api/v1/logs Execution logs for a prompt (`?promptId=...`) or recent logs for a project (`?projectId=...`). One of the two query params is required. `limit` default 100, max 500. With `promptId`, `afterSequence=N` returns only logs with `sequence > N` (incremental polling). Each log: `id, promptId, level, category, message, details, durationMs, sequence, timestamp`. Note: `message` is truncated at 10K chars; full output is in `details` (e.g. `details.output.content`, `details.tool_result.output`). #### GET /api/v1/projects Lists projects in your org. Agent tokens see only their project. #### GET /api/v1/agents Lists registered agent installations with online status and project bindings. #### GET /api/v1/users Org-scoped tokens return organization members; agent tokens return project members. Useful for resolving `createdBy` to `email` / `fullName`. --- ## 4. orquesta-cli ### Install ```bash npm install -g orquesta-cli ``` ### Interactive mode ```bash orquesta # interactive TUI orquesta --token oclt_xxx # connect to dashboard orquesta -p "Add user authentication" # one-shot ``` ### Multi-role orchestration (v0.2.0+) The cli splits one LLM call into three roles, each routable to a different model: - **planner** — breaks the request into a TODO DAG (often Opus or batuta-auto). - **executor workers** — fan out tasks in parallel (Sonnet, batuta-auto, gpt-4o, etc.). Capped by `maxParallelWorkers` (default 3). - **refiner** (optional) — consolidates the final response (Sonnet or gpt-4o-mini). Configure with the `/role` slash command inside the cli: ``` /role show current pins /role planner opus-4-7 pin planner model /role executor claude-sonnet-4-6 pin executor (workers) model /role refiner gpt-4o-mini pin + enable refiner pass /role refiner off disable refiner /role parallel 5 set max parallel workers /role worktree on isolate file-touching workers in git worktrees /role clear reset all pins to currentModel ``` Three execution modes: 1. **claude -p (default)** — all roles route to `batuta-auto`; server uses Claude web subscription. 2. **Full API-direct** — every role hits a model API directly. Real parallelism, real cost. 3. **Hybrid (recommended)** — planner stays on `batuta-auto` (subscription absorbs cost); workers go API-direct. ### Audit log ``` /audit lifetime stats /audit day last 24h /audit week last 7d /audit tail [N] raw events (default 20) /audit clear wipe local log ``` Audit lives at `~/.orquesta-cli/audit.jsonl`. Captures structural facts only (model ids, latencies, todo counts) — never prompt or response text. --- ## 5. orquesta-agent Local daemon that executes prompts triggered from the dashboard. Installs via npm, runs as a systemd service (recommended) or in the foreground. ```bash npm install -g orquesta-cli orquesta-agent orquesta-agent --token ``` Token comes from the dashboard's project setup wizard. The agent reports online status, executes prompts via Claude CLI, streams logs over WebSocket, and exposes a local bridge at `127.0.0.1:7790` for in-prompt browser sessions. ### IDE hooks (mirror, not dispatch) The daemon above is dispatch: Orquesta sends work down to the machine. Hooks are the opposite — the developer keeps working in their own IDE and Orquesta mirrors what happened. No daemon runs and nothing is executed back into the editor. ```bash orquesta-agent init --token # wires Claude Code + Cursor orquesta-agent init --token --client cursor # or just one ``` It writes `.orquesta.json` (project binding, gitignored — it holds the raw token) plus `.claude/settings.json` and/or `.cursor/hooks.json`. Claude Code's `UserPromptSubmit`/`PostToolUse`/`Stop` map to Cursor's `beforeSubmitPrompt`/`postToolUse`+`afterShellExecution`+`afterFileEdit`/`stop`, plus `afterAgentResponse` for the assistant's reply. Mirrored prompts land with `source: terminal` and a `cli_type` of `claude-code` or `cursor-cli`, and are excluded from agent dispatch so a hooked session is never re-executed. Every hook exits 0, so an unreachable Orquesta can never block a prompt. --- ## 6. MCP Server Orquesta is an MCP (Model Context Protocol) server at: ``` https://getorquesta.com/api/mcp ``` Streamable HTTP, stateless (no session id, no server-initiated stream — POST JSON-RPC, get JSON back). Two ways to authenticate: 1. **OAuth 2.1** (what a hosted client does on its own). Paste the URL and click Authorize — no API key is created or copied. The 401 carries `WWW-Authenticate: Bearer resource_metadata="https://getorquesta.com/.well-known/oauth-protected-resource"`; from there the client reads `/.well-known/oauth-authorization-server`, registers itself at `POST /api/oauth/register` (RFC 7591 dynamic client registration, public clients, no secret), sends the user to `/oauth/authorize` with PKCE S256, and exchanges the code at `POST /api/oauth/token` for an `omt_` access token (30 days) plus a rotating refresh token. The consent screen is where the user picks which organization to expose; the token then reaches exactly the projects that user can see, and is revoked from Settings → API keys like any other token. 2. **A bearer token pasted by hand**: `Authorization: Bearer oak_...` (org API key) or `oclt_` (CLI token); `oat_` agent tokens connect read-only. Still supported for clients with no OAuth path. Hooks require a process on the developer's machine, so they cannot reach a tool that runs in the cloud. MCP closes that gap: an assistant in Lovable, ChatGPT, Claude Code, Cursor or VS Code can read a project's history and write its own work back into it with nothing installed. ```bash claude mcp add --transport http orquesta https://getorquesta.com/api/mcp \ --header "Authorization: Bearer oak_..." ``` ```json { "mcpServers": { "orquesta": { "url": "https://getorquesta.com/api/mcp", "headers": { "Authorization": "Bearer oak_..." } } } } ``` Tools: | Tool | Purpose | Requires | |---|---|---| | `list_projects` | Projects the key can see, with ids | `projects:read` | | `recent_context` | Briefing: what is running, succeeded, failed | `prompts:read` | | `list_prompts` | Recent work with status, author, CLI, branch | `prompts:read` | | `get_prompt_logs` | Full tool log of one prompt | `logs:read` | | `submit_prompt` | Queue work for the project's local agent | `prompts:write` + a connected agent | | `report_session` | Record work already done elsewhere | `prompts:write` | The two writes are not interchangeable. `submit_prompt` inserts a `pending` prompt that the agent's heartbeat dispatches to the customer machine. `report_session` inserts a finished prompt with `source: external_agent` — the heartbeat only dispatches pending/evaluating/running, so a session reported from Lovable is inert and can never be replayed on anyone's laptop. Agent tokens are refused by both writes. A key only reaches the projects its owner belongs to; a project that is missing, in another organization, or outside the ACL returns the same "not visible to this token" answer so ids cannot be enumerated. --- ## 7. Batuta LLM smart routing When a prompt arrives with `model: "batuta-auto"`, the proxy: 1. Classifies the prompt via a lightweight heuristic (length, code presence, tool requirements, complexity). 2. Scores it into a tier: - **fast** → Claude Haiku 4.5 (or claude-cli-haiku via subscription) - **balanced** → Claude Sonnet 4.6 - **premium** → Claude Opus 4.7 3. Forwards to the chosen upstream and returns the OpenAI-compatible response. 4. Annotates response headers (`X-Batuta-Routed-To`, `X-Batuta-Tier`) so the caller can observe the decision. Users on the Max ($12/user/mo) tier can route through the subscription lane (`claude-cli` provider), absorbing token cost in their existing Claude Max subscription. --- ## 8. Token Pricing & Plans - **Starter** — free, individual developers. - **Pro** — $6/user/mo, growing teams. Includes 500K tokens/mo of Batuta chat. - **Max** — $12/user/mo. Everything in Pro plus Orquesta CLI, autonomous SSH, cloud VMs, **and Batuta Standard included (5M tokens/mo)** — no separate add-on needed. Batuta LLM add-on tiers (for orgs that need more than what their base plan includes): - **Standard** — $19/mo, 5M tokens/mo, $5/M overage. Bundled with Max. - **Plus** — $49/mo, 15M tokens/mo, $4/M overage. - **Pro** — $99/mo, 40M tokens/mo, $3.50/M overage. - **Team** — $199/mo, 100M tokens/mo, $3/M overage. Shared team pool. Annual billing available with discount. Custom enterprise contracts via oscar@getorquesta.com. --- ## 9. Security - Agent runs on the customer's machine; source code never leaves their infra. - Credentials encrypted with AES-256-GCM at rest. - Row-level security on every Supabase table. - API keys are SHA-256 hashed before DB lookup (only the prefix is visible). - Custom security sweep runs every 5 minutes on shared VMs. - VM provisioning includes auto-firewall (UFW + DOCKER-USER chain + per-port allowlist) and SSH key isolation. --- ## 10. OSS Edition Self-hosted Orquesta is open-source at https://github.com/Orquesta-live/orquesta-oss (Next.js 15 + Prisma + SQLite + Better Auth). Publishes prompts/projects to the public feed at https://getorquesta.com/oss. --- ## 11. Useful Links - Homepage: https://getorquesta.com - Sign up: https://getorquesta.com/signup - Docs: https://getorquesta.com/docs - API spec (JSON): https://getorquesta.com/openapi.json - API reference (ReDoc): https://getorquesta.com/docs/api - Pricing: https://getorquesta.com/#pricing - OSS feed: https://getorquesta.com/feed - OSS repo: https://github.com/Orquesta-live/orquesta-oss - Trust & security: https://getorquesta.com/trust - Contact: oscar@getorquesta.com --- Generated for AI consumers. For interactive use, see https://getorquesta.com/docs.