API & SDKs
21 endpoints. JSON in, JSON out. Three verbs: Show (paste examples), Get (find a recipe), Run (call it). The whole API surface fits on one screen of code — see the SDK at the bottom.
5-minute integration
# 1. install (or skip and use curl)
npm install @kolmogorov/recipe # Node
pip install kolmogorov-recipe # Python
# 2. mint a free key (10k calls/month, no card)
KS=$(curl -sX POST https://kolmogorov-stack-production.up.railway.app/v1/signup \
-H "Content-Type: application/json" -d '{"email":"you@company.com"}' \
| python -c "import sys,json;print(json.load(sys.stdin)['api_key'])")
# 3. show it your examples (paste 4-8)
curl -X POST https://kolmogorov-stack-production.up.railway.app/v1/synthesize \
-H "Authorization: Bearer $KS" -H "Content-Type: application/json" \
-d '{
"name": "classify-issue-type",
"output_spec": { "type": "enum", "values": ["bug","feature","question"] },
"positives": [
{ "input": "deploy keeps crashing on startup", "expected": "bug" },
{ "input": "would love an export to CSV", "expected": "feature" },
{ "input": "how do I rotate my API key?", "expected": "question" }
]
}'
# → { accepted: true, concept_id: "cpt_…", quality_score: 1.0 }
# 4. run it forever
curl -X POST https://kolmogorov-stack-production.up.railway.app/v1/run \
-H "Authorization: Bearer $KS" -H "Content-Type: application/json" \
-d '{ "concept_id": "cpt_…", "input": "404 on /dashboard" }'
# → { output: "bug", latency_us: 41, cache: null }
Auth
Authorization: Bearer ks_… # tenant key (mint via /v1/signup)
X-API-Key: ks_… # alternative header
Authorization: Bearer ks_admin_… # admin only, provisions tenants
POST /v1/signup public
Mint a tenant + key for free. 10,000 calls/month included. No card.
{ "email": "you@company.com", "name": "acme" (optional) }
→ { "api_key": "ks_…", "tenant": { "id": "tenant_…", "plan": "free", "quota": 10000, "used": 0 } }
GET /v1/account
Returns the calling tenant's plan, quota, used, remaining.
POST /v1/account/rotate-key
Rotate this tenant's key. Old key stops working immediately.
Show — synthesis
Paste examples, get back a tested recipe. (legacy alias: /v1/synthesize; both names work.)
POST /v1/synthesize
Synthesize a recipe from positive and negative examples. Optionally publishes to your registry.
{
"name": "classify-issue-type",
"tags": ["classifier","support"],
"visibility": "private" | "public",
"publish": true,
"output_spec": { "type": "enum", "values": ["bug","feature","question"] },
"positives": [ { "input": "...", "expected": ... }, ... ],
"negatives": [ { "input": "...", "expected_not": ... }, ... ],
"priors": { "hint": "free text", "max_size_bytes": 2048 }
}
→ {
"accepted": true,
"concept_id": "cpt_…",
"version_id": "ver_…",
"quality_score": 0.94,
"pass_rate_positive": 1.0,
"reject_rate_negative": 1.0,
"latency_p50_us": 87,
"size_bytes": 412,
"source": "function generate(input, lib) { … }",
"source_hash": "…",
"strategy": "claude" | "pattern",
"test_trace": [ { kind, input, output, pass, latency_us } ],
"attempts_n": 1,
"duration_ms": 2114
}
POST /v1/synthesize/stream
SSE stream of synthesis events: start, plan, strategy_begin, candidate, verified, accepted, published, done.
const res = await fetch('/v1/synthesize/stream', { method:'POST',
headers:{ Authorization:'Bearer '+key, 'Content-Type':'application/json' },
body: JSON.stringify({...}) });
const reader = res.body.getReader();
// parse "event: ...\ndata: {...}\n\n" frames
POST /v1/synthesize/batch
Up to 25 recipes in one request. Sequential synthesis, single round-trip.
{ "items": [ { "name": "...", "positives": [...], "output_spec": {...} }, ... ] }
POST /v1/verify
Re-run a recipe's test trace without publishing.
{ "source": "function generate(...){...}", "positives":[...], "negatives":[...] }
POST /v1/publish
Publish a hand-edited recipe straight to the registry. Verifies in flight.
{ "name": "my-recipe", "source": "function generate(input,lib){...}", "positives":[...], "negatives":[...], "tags":["..."] }
Get — registry
GET /v1/concepts ?tag=&limit=
List recipes owned by your tenant.
GET /v1/concepts/:id
Fetch a recipe and its versions.
GET /v1/concepts/:id/stats
Per-recipe usage: invocation count, latency p50/p95/p99, cache hit rate, error rate, last_invoked_at.
DELETE /v1/concepts/:id
GET /v1/concepts/:id/lineage
Upstream synthesizers and downstream dependents.
POST /v1/search
Semantic search by what the recipe does. Type "extract email addresses" — not the exact name.
{ "query": "find recipes about extracting prices", "k": 10, "tag": "extractor" }
→ { "matches": [ { concept_id, name, score, version_id, ... }, ... ] }
GET /v1/public/concepts public
GET /v1/public/concepts/:id public
POST /v1/public/run public
Dispatch any public recipe. No auth needed. Convenient for embedded demos.
Run — runtime
POST /v1/run
Dispatch a single recipe (head version) or a specific version. Output is cached for identical input.
{ "concept_id": "cpt_…", "input": "any json", "use_cache": true }
{ "version_id": "ver_…", "input": "any json" }
→ { "output": ..., "latency_us": 87, "cache": null | "L1" | "L2", "version_id": "...", "concept": "..." }
POST /v1/compose
Search top-K recipes by query, dispatch them in parallel, compose outputs with one of four strategies.
{
"query": "classify intent",
"input": "where is my order",
"k": 5,
"strategy": "attention" | "voting" | "top1" | "sequential",
"tag": "classifier"
}
→ {
"output": "question",
"dispatched": [ { name, concept_id, score, output, latency_us, cache }, ... ],
"strategy": "attention"
}
GET /v1/telemetry
Total invocations, average latency, p50/p95/p99, cache hit-rate, recent invocation log, sparkline.
GET /v1/library
The current built-in subroutine library — version + signatures.
SDKs
Pick your language. The TypeScript and Python clients are the supported ones; the Go and Java snippets below are minimal but production-shaped.
Node / TypeScript
// npm install @kolmogorov/recipe
import { Recipe } from '@kolmogorov/recipe';
const r = new Recipe({ apiKey: process.env.KS_KEY });
// teach once
const recipe = await r.show('classify-issue-type', {
examples: [
{ input: 'deploy keeps crashing', expected: 'bug' },
{ input: 'love an export button', expected: 'feature' },
{ input: 'how do I rotate keys?', expected: 'question' },
],
shape: { type: 'enum', values: ['bug','feature','question'] },
});
// run forever
console.log(await r.run(recipe.id, '404 on /dashboard')); // 'bug'
Python
# pip install kolmogorov-recipe
from kolmogorov_recipe import Recipe
r = Recipe(api_key=os.environ['KS_KEY'])
recipe = r.show(
name='classify-issue-type',
examples=[
{'input': 'deploy crashes', 'expected': 'bug'},
{'input': 'export to csv', 'expected': 'feature'},
{'input': 'rotate key?', 'expected': 'question'},
],
shape={'type': 'enum', 'values': ['bug','feature','question']},
)
print(r.run(recipe['concept_id'], '404 on /dashboard')) # 'bug'
Go
// HTTP, no SDK needed
req, _ := http.NewRequest("POST",
"https://kolmogorov-stack-production.up.railway.app/v1/run",
bytes.NewBufferString(`{"concept_id":"cpt_…","input":"404 on /dashboard"}`))
req.Header.Set("Authorization", "Bearer "+os.Getenv("KS_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
Java
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://kolmogorov-stack-production.up.railway.app/v1/run"))
.header("Authorization", "Bearer " + System.getenv("KS_KEY"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(
"{\"concept_id\":\"cpt_…\",\"input\":\"404 on /dashboard\"}"))
.build();
Claude Code MCP server
Drop-in MCP server: npx @kolmogorov/recipe-mcp. Adds recipe.show, recipe.run, recipe.search to your Claude Code session.
# in your ~/.claude/mcp.json
{
"mcpServers": {
"recipe": {
"command": "npx",
"args": ["-y","@kolmogorov/recipe-mcp"],
"env": { "KS_API_KEY": "ks_…" }
}
}
}
Errors
| code | meaning |
|---|---|
| 400 | missing required field, bad JSON, or recipe quality below gate |
| 401 | missing or invalid API key |
| 403 | tenant cannot read this recipe; admin-only endpoint hit by non-admin |
| 404 | recipe or version not found |
| 429 | rate limit (token bucket) or monthly quota exceeded — see Retry-After |
| 500 | synthesis backend error |