Prompt Studio API¶
The Prompt Studio module provides a structured workflow to design, version, test, evaluate, and optimize prompts within projects. It exposes cohesive APIs for projects, prompts (with versioning), test cases, evaluations, optimizations, and real-time updates.
Overview¶
- Projects group all Prompt Studio entities (prompts, test cases, evaluations, optimizations) under a workspace.
- Prompts are versioned. Every update creates a new immutable version for reproducibility.
- Test cases define inputs, expected outputs, tags, and a golden flag; they form the corpus for evaluation.
- Evaluations run a prompt (or prompt version) against a set of test cases and save metrics.
- Optimizations run strategies to iteratively improve prompts (e.g., iterative refinement, hyperparameter tuning).
- Real-time updates are available via WebSocket with SSE fallback.
Authentication follows the server's standard modes (single-user API key or multi-user JWT). Endpoints are project-scoped: reads require access, writes require write access. Rate limits apply to generation/optimization endpoints.
Auth + Rate Limits¶
- Single-user: header
X-API-KEY: <key> - Multi-user: header
Authorization: Bearer <JWT> - Rate limits: applied to generation (
/generate,/execute) and optimization endpoints; listing/CRUD use standard limits.
Tag in OpenAPI: prompt-studio.
Auth headers
- Single-user: X-API-KEY: <key>
- Multi-user: Authorization: Bearer <JWT>
Test/CI Environment Variables (Prompt Studio)¶
TLDW_PS_BACKEND=sqlite|postgres- for the heavy optimization suite, pick a single backend per run (default: sqlite).TLDW_PS_STRESS=1- enable larger datasets/iterations in heavy tests.TLDW_PS_TC_COUNT- override test-case volume (default 250; stress 1000).TLDW_PS_ITERATIONS- override iteration count (default 5; stress 10).TLDW_PS_OPT_COUNT- override concurrent optimizations (default 3; stress 8).TLDW_TEST_POSTGRES_REQUIRED=1- fail fast if Postgres probe fails (otherwise Postgres tests are skipped when unreachable).TLDW_PS_SQLITE_WAL=1- opt-in to WAL for per-test SQLite DBs (default: DELETE mode for CI tidiness).TLDW_PS_JOB_LEASE_SECONDS- lease window for processing jobs in the Prompt Studio queue (default: 60). Expired processing jobs are reclaimed.TLDW_PS_HEARTBEAT_SECONDS- heartbeat interval override for renewing job leases during processing (default: lease/2 up to 30s).
Strategy Parameters (validation highlights)¶
beam_search:beam_width≥ 2,max_candidates≥beam_width(if both provided)diversity_ratein [0, 1],prune_thresholdin [0, 1]length_penaltyin [0, 2]candidate_reranker: one ofnone|score|diversity|hybridanneal(simulated annealing):cooling_ratein (0, 1],initial_temp> 0,min_temp≥ 0 and ≤initial_temp- Optional schedule:
exponential|linear|cosine - If
schedule=linearandstep_size/epochsprovided, enforcestep_size * epochs ≤ (initial_temp - min_temp) genetic:population_size≥ 2,mutation_ratein [0, 1],crossover_ratein [0, 1],elitism≥ 0selection:tournament|roulette|rankcrossover_operator:one_point|two_point|uniformhyperparameter,random_search:max_trials≥ 1 (if provided)max_tokens_range:[min, max]with1 ≤ min < max ≤ 100000
More Examples¶
Update Project¶
curl -X PUT "http://localhost:8000/api/v1/prompt-studio/projects/update/1" \
-H "Content-Type: application/json" -H "X-API-KEY: $API_KEY" \
-d '{"description": "Updated description"}'
Delete Project (soft)¶
curl -X DELETE "http://localhost:8000/api/v1/prompt-studio/projects/delete/1" \
-H "X-API-KEY: $API_KEY"
Archive / Unarchive Project¶
curl -X POST "http://localhost:8000/api/v1/prompt-studio/projects/archive/1" -H "X-API-KEY: $API_KEY"
curl -X POST "http://localhost:8000/api/v1/prompt-studio/projects/unarchive/1" -H "X-API-KEY: $API_KEY"
Update Test Case¶
curl -X PUT "http://localhost:8000/api/v1/prompt-studio/test-cases/update/101" \
-H "Content-Type: application/json" -H "X-API-KEY: $API_KEY" \
-d '{"name": "Short text (v2)", "is_golden": true}'
Delete Test Case¶
curl -X DELETE "http://localhost:8000/api/v1/prompt-studio/test-cases/delete/101" \
-H "X-API-KEY: $API_KEY"
Delete Evaluation¶
curl -X DELETE "http://localhost:8000/api/v1/prompt-studio/evaluations/501" -H "X-API-KEY: $API_KEY"
Cancel Optimization¶
curl -X POST "http://localhost:8000/api/v1/prompt-studio/optimizations/cancel/701" \
-H "Content-Type: application/json" -H "X-API-KEY: $API_KEY" \
-d '{"reason": "Stopping for manual review"}'
Record an Optimization Iteration¶
curl -X POST "http://localhost:8000/api/v1/prompt-studio/optimizations/iterations/701" \
-H "Content-Type: application/json" -H "X-API-KEY: $API_KEY" \
-d '{"iteration_number": 4, "metrics": {"accuracy": 0.82}, "tokens_used": 1400, "cost": 0.08}'
List Optimization Iterations¶
curl -X GET "http://localhost:8000/api/v1/prompt-studio/optimizations/iterations/701?page=1&per_page=20" \
-H "X-API-KEY: $API_KEY"
Get Optimization History & Timeline¶
curl -X GET "http://localhost:8000/api/v1/prompt-studio/optimizations/history/701" -H "X-API-KEY: $API_KEY"
Endpoints¶
Projects¶
- Create:
POST /api/v1/prompt-studio/projects/ - List:
GET /api/v1/prompt-studio/projects/ - Query params:
page,per_page,status,include_deleted,search - Example response:
{ "success": true, "data": [ { "id": 1, "uuid": "f9e3...", "name": "Demo Project", "status": "active" } ], "metadata": { "page": 1, "per_page": 20, "total": 1, "total_pages": 1 } } - Get:
GET /api/v1/prompt-studio/projects/get/{project_id} - Update:
PUT /api/v1/prompt-studio/projects/update/{project_id} - Delete:
DELETE /api/v1/prompt-studio/projects/delete/{project_id}?permanent=false - Archive:
POST /api/v1/prompt-studio/projects/archive/{project_id} - Unarchive:
POST /api/v1/prompt-studio/projects/unarchive/{project_id} - Stats:
GET /api/v1/prompt-studio/projects/stats/{project_id}
Prompts (Versioned)¶
- Create:
POST /api/v1/prompt-studio/prompts/create - List:
GET /api/v1/prompt-studio/prompts/list/{project_id} - Query params:
page,per_page,include_deleted - Example response:
{ "success": true, "data": [ { "id": 12, "project_id": 1, "name": "Summarizer", "version_number": 2 } ], "metadata": { "page": 1, "per_page": 20, "total": 1, "total_pages": 1 } } - Get:
GET /api/v1/prompt-studio/prompts/get/{prompt_id} - Update (new version):
PUT /api/v1/prompt-studio/prompts/update/{prompt_id} - History:
GET /api/v1/prompt-studio/prompts/history/{prompt_id} - Revert (new version):
POST /api/v1/prompt-studio/prompts/revert/{prompt_id}/{version} - Execute (simple):
POST /api/v1/prompt-studio/prompts/execute
Test Cases¶
- Create:
POST /api/v1/prompt-studio/test-cases/create - Bulk Create:
POST /api/v1/prompt-studio/test-cases/bulk - List:
GET /api/v1/prompt-studio/test-cases/list/{project_id} - Query params:
page,per_page,is_golden,tags,search,signature_id - Example response:
{ "success": true, "data": [ { "id": 101, "project_id": 1, "name": "Short text", "is_golden": true } ], "metadata": { "page": 1, "per_page": 20, "total": 1, "total_pages": 1 } } - Get:
GET /api/v1/prompt-studio/test-cases/get/{test_case_id} - Update:
PUT /api/v1/prompt-studio/test-cases/update/{test_case_id} - Delete:
DELETE /api/v1/prompt-studio/test-cases/delete/{test_case_id}?permanent=false - Import:
POST /api/v1/prompt-studio/test-cases/import(CSV or JSON payload) - Export:
POST /api/v1/prompt-studio/test-cases/export/{project_id}(CSV or JSON) - Generate:
POST /api/v1/prompt-studio/test-cases/generate
Evaluations¶
- Create:
POST /api/v1/prompt-studio/evaluations - Supports async run via background task
- List:
GET /api/v1/prompt-studio/evaluations?project_id=...&prompt_id=...
Optimizations¶
- Create:
POST /api/v1/prompt-studio/optimizations/create - List:
GET /api/v1/prompt-studio/optimizations/list/{project_id} - Get:
GET /api/v1/prompt-studio/optimizations/get/{optimization_id} - Cancel:
POST /api/v1/prompt-studio/optimizations/cancel/{optimization_id} - Strategies:
GET /api/v1/prompt-studio/optimizations/strategies - Compare:
POST /api/v1/prompt-studio/optimizations/compare - Status/Health:
GET /api/v1/prompt-studio/status?warn_seconds=30- queue depth, processing count, and lease health (active, expiring soon, stale processing)
Real-time API¶
- WebSocket base:
WS /api/v1/prompt-studio/ws - WebSocket per project:
WS /api/v1/prompt-studio/ws/{project_id} - SSE fallback:
GET /api/v1/prompt-studio/ws?client_id=<id>&project_id=<optional>(text/event-stream) - Requires
client_idquery param; optionalproject_idto scope events
Notes
- Several endpoints also accept “simple” aliases on the base path without trailing slashes to improve client ergonomics.
- All list endpoints return a metadata object with page, per_page, total, and total_pages.
Common Schemas¶
- ProjectCreate, ProjectUpdate, ProjectResponse
- PromptCreate, PromptUpdate, PromptResponse, PromptVersion
- TestCaseCreate, TestCaseUpdate, TestCaseResponse, TestCaseBulkCreate, TestCaseImportRequest, TestCaseExportRequest, TestCaseGenerateRequest
- EvaluationCreate, EvaluationResponse, EvaluationMetrics
- OptimizationCreate, OptimizationResponse, OptimizationConfig
- Note:
OptimizationConfig.strategy_paramsallows optional strategy-specific knobs (e.g.,beam_width,cooling_rate,mutation_rate). These parameters are validated when provided for supported strategies. - Additional optional knobs currently validated when present:
beam_search:beam_width>=2,prune_thresholdin [0,1],max_candidates>=beam_widthanneal:cooling_ratein (0,1],initial_temp>0,min_temp>=0and<=initial_temp(if both set),scheduleone ofexponential|linear|cosinegenetic:population_size>=2,mutation_ratein [0,1],crossover_ratein [0,1],elitism>=0,selectionone oftournament|roulette|rank
Metrics (Prometheus)¶
- The status endpoint updates the following Prometheus gauges with label
backend=sqlite|POSTGRESQL: prompt_studio_queue_depthprompt_studio_processingprompt_studio_leases_activeprompt_studio_leases_expiring_soonprompt_studio_leases_stale_processing- Scrape via
GET /api/v1/metrics/text.
Idempotency¶
- Create endpoints (projects, prompts, optimizations) accept
Idempotency-Keyheader. - The idempotency map enforces uniqueness per user:
(entity_type, idempotency_key, user_id). - Duplicate submits with the same key and user return the canonical entity without enqueuing new work.
Quick Examples¶
Create a Project¶
curl -X POST "http://localhost:8000/api/v1/prompt-studio/projects/" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $API_KEY" \
-d '{
"name": "Demo Project",
"description": "Exploring prompt versions",
"status": "active"
}'
Create a Prompt (v1)¶
curl -X POST "http://localhost:8000/api/v1/prompt-studio/prompts/create" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $API_KEY" \
-d '{
"project_id": 1,
"name": "Summarizer",
"system_prompt": "Summarize the content clearly.",
"user_prompt": "{{text}}"
}'
Add Test Cases (Bulk)¶
curl -X POST "http://localhost:8000/api/v1/prompt-studio/test-cases/bulk" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $API_KEY" \
-d '{
"project_id": 1,
"test_cases": [
{"name": "Short text", "inputs": {"text": "Hello world"}, "expected_outputs": {"summary": "Hello world."}},
{"name": "Long text", "inputs": {"text": "..."}, "expected_outputs": {"summary": "..."}}
]
}'
Update Prompt (new version)¶
curl -X PUT "http://localhost:8000/api/v1/prompt-studio/prompts/update/12" \
-H "Content-Type: application/json" -H "X-API-KEY: $API_KEY" \
-d '{"system_prompt": "Summarize concisely.", "change_description": "Tighten style"}'
Revert Prompt to Specific Version¶
curl -X POST "http://localhost:8000/api/v1/prompt-studio/prompts/revert/12/1" -H "X-API-KEY: $API_KEY"
Export Test Cases (JSON)¶
curl -X POST "http://localhost:8000/api/v1/prompt-studio/test-cases/export/1" \
-H "Content-Type: application/json" -H "X-API-KEY: $API_KEY" \
-d '{"format": "json", "include_golden_only": false, "tag_filter": ["smoke"]}'
Import Test Cases via CSV Upload (multipart/form-data)¶
Sample CSV (save as cases.csv):
name,description,input.text,expected.summary,tags,is_golden
Short,,"Hello world","Hello world.","smoke,basic",true
Long,"Longer passage","This is a longer passage...","A concise summary...","regression",false
Upload with curl:
curl -X POST "http://localhost:8000/api/v1/prompt-studio/test-cases/import/csv-upload" \
-H "X-API-KEY: $API_KEY" \
-F project_id=1 \
-F signature_id=2 \
-F auto_generate_names=true \
-F file=@cases.csv;type=text/csv
Download a CSV template derived from a signature (fields):
curl -L "http://localhost:8000/api/v1/prompt-studio/test-cases/import/template?signature_id=2" \
-H "X-API-KEY: $API_KEY" -o template.csv
Notes:
- Use input.<field> for inputs and expected.<field> for expected outputs. Values may be raw strings or JSON; JSON will be parsed when present.
- Separate multiple tags with commas (,). The importer splits on commas.
- signature_id is optional; provide when schema validation is desired.
CSV column schema (conceptual JSON Schema):
{
"type": "object",
"properties": {
"name": { "type": "string" },
"description": { "type": "string" },
"tags": { "type": "string", "description": "Comma-separated tags" },
"is_golden": { "type": "boolean" },
"input.*": { "type": ["string", "object"], "description": "Input fields; prefix with input." },
"expected.*": { "type": ["string", "object"], "description": "Expected output fields; prefix with expected." }
},
"required": [ "input.*" ]
}
Run Evaluation¶
curl -X POST "http://localhost:8000/api/v1/prompt-studio/evaluations" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $API_KEY" \
-d '{
"project_id": 1,
"prompt_id": 12,
"name": "Baseline Eval",
"test_case_ids": [1,2,3],
"config": {"model_name": "gpt-4o", "temperature": 0.2, "max_tokens": 256}
}'
Create Optimization Job¶
curl -X POST "http://localhost:8000/api/v1/prompt-studio/optimizations/create" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $API_KEY" \
-d '{
"project_id": 1,
"name": "Refine Summarizer",
"initial_prompt_id": 12,
"test_case_ids": [1,2,3],
"optimization_config": {
"optimizer_type": "iterative",
"max_iterations": 20,
"target_metric": "accuracy",
"early_stopping": true
}
}'
Create MCTS Optimization Job (Canary/Flagged)¶
curl -X POST "http://localhost:8000/api/v1/prompt-studio/optimizations/create" \
-H "Content-Type: application/json" \
-H "X-API-KEY: $API_KEY" \
-d '{
"project_id": 1,
"name": "MCTS Sequence Run",
"initial_prompt_id": 12,
"test_case_ids": [1,2,3],
"optimization_config": {
"optimizer_type": "mcts",
"max_iterations": 20,
"target_metric": "accuracy",
"strategy_params": {
"mcts_simulations": 20,
"mcts_max_depth": 4,
"mcts_exploration_c": 1.4,
"prompt_candidates_per_node": 3,
"score_dedup_bin": 0.1,
"early_stop_no_improve": 5,
"token_budget": 50000,
"ws_throttle_every": 2,
"trace_top_k": 3
}
}
}'
Subscribe to Real-time Updates (WebSocket)¶
const ws = new WebSocket("ws://localhost:8000/api/v1/prompt-studio/ws");
ws.onopen = () => ws.send(JSON.stringify({ type: "subscribe", entity_type: "project", entity_id: 1 }));
ws.onmessage = (evt) => console.log("event", evt.data);
MCTS iteration payload fields (when type = "optimization_iteration"):
optimization_id, iteration, max_iterations, current_metric, best_metric, progress,
strategy, sim_index, depth, reward, best_reward, token_spend_so_far, trace_summary.
Reference payloads:
- Docs/Examples/PromptStudio/mcts/ROLL_OUT_NOTES.md
- Docs/Guides/Prompt_Studio_MCTS_Guide.md
Access Control & Limits¶
- Reads require project access; writes require project write access
- SecurityConfig defines limits (e.g., max prompt length, max test cases)
- Rate limiting is applied to generation/optimization endpoints
Notes¶
- Prompt updates create new versions; reverting also creates a new version
- Evaluations can run synchronously or as background tasks
- Real-time updates support both WebSocket and SSE fallback
Metrics¶
Prompt Studio emits the following metrics (names, labels) and when they are updated:
- Job queue gauges/counters
jobs.queued{job_type}: updated on job create/acquire/status refresh.jobs.processing{job_type}: updated on acquire/complete/fail/retry/status refresh.jobs.backlog{job_type}: computed as queued - processing; updated alongside gauges.jobs.stale_processing: aggregate gauge from lease stats.jobs.duration_seconds{job_type}: histogram observed when a job finishes (success/failure).jobs.queue_latency_seconds{job_type}: histogram observed on acquire (started_at - created_at).jobs.retries_total{job_type}: increments when a job is rescheduled for retry.jobs.failures_total{job_type,reason}: increments on terminal failure with exception type.jobs.lease_renewals_total{job_type}: increments on each lease heartbeat renewal.-
jobs.reclaims_total{job_type}: increments when a processing job with expired lease is reclaimed. -
Idempotency
prompt_studio.idempotency.hit_total{entity_type}: increments when a duplicated request (same Idempotency-Key) returns the canonical entity.-
prompt_studio.idempotency.miss_total{entity_type}: increments when a new mapping is recorded for a request. -
Postgres advisory locks
prompt_studio.pg_advisory.lock_attempts_total: increments per acquire attempt on Postgres.prompt_studio.pg_advisory.locks_acquired_total: increments when a job row is selected withpg_try_advisory_lock.prompt_studio.pg_advisory.unlocks_total: increments when the advisory lock is released.
The /api/v1/prompt-studio/status endpoint also updates generic gauges for Prometheus scraping:
prompt_studio_queue_depth, prompt_studio_processing, and lease gauges (prompt_studio_leases_*),
and refreshes the per-type Prompt Studio gauges (queued, processing, backlog, stale_processing).