# AIRigs Recipes > Reproducible local-AI recipes: an engine, its arguments, the models it serves, and the > self-reported performance of that setup on a benchmarked AIRigs rig. Read-only to > everyone; writing requires an AIRigs OAuth2 access token. ## Verification and pinning semantics - "Verified" (on a rig) is AIRigs' label for a rig whose self-reported benchmark passed its own checks. Recipes does not re-measure hardware, does not attest that a measurement happened, and cannot detect a fabricated payload that AIRigs accepted. - A recipe benchmark is self-reported by the author (normally via the CLI). Recipes validates types, ranges, timestamps and the rig revision, but it is evidence of a claim, not proof. - Rig verification metadata is carried from AIRigs as verification.method / verification.plausibilityChecked / verification.reason. When plausibilityChecked is false, the catalogue did not resolve a GPU and the rig benchmark was not plausibility-checked; Recipes shows a distinct warning on the rig card and near the benchmark, and exposes verification in the recipe JSON. Publishing remains allowed because the gate is about the measurement/revision, not attestation. - "Pinned" means the page renders the rig snapshot and revision (rigRevision) stored when the recipe was published. If AIRigs later reports a different rig revision, the recipe is marked rigStale and keeps the pinned numbers with a warning; it does not rewrite history. If the rig disappears, the snapshot is kept and marked rigMissing. - The generated script is built from the recipe's own engine/args/models; it is not a recording of the measurement. A rigStale warning means the script may target hardware that no longer matches the numbers on the page. Site: https://recipes.airigs.net API: https://recipes.airigs.net/api/v1 OpenAPI 3.1: https://recipes.airigs.net/api/v1/openapi.json Version: 1.0.0 AIRigs (identity + rigs): https://airigs.net ## Authentication AIRigs is the OAuth2 provider. Register a confidential client whose redirect URI is https://recipes.airigs.net/auth/callback and request the scopes: user:read rig:read rig:write recipe:read recipe:write Web sign-in uses the authorization-code flow with PKCE (S256). The standalone CLI uses the AIRigs device-authorization flow (RFC 8628) and then calls this API with the resulting access token: Authorization: Bearer The token is introspected against https://airigs.net/oauth/introspect (client-authenticated, RFC 7662) and cached by token hash for at most 60 seconds. The token may have been issued to another client (for example the CLI's public client); only active === true and the scope required by the route are enforced. Write endpoints require the "recipe:write" scope; rig verification additionally uses "rig:read" against AIRigs. Supported engines (the authoritative list is also published as x-airigs-engines in openapi.json): vllm, sglang, llamacpp, strata, omlx, ollama, custom rigId is an opaque string matching ^r_[A-Za-z0-9_-]{1,92}$ — never an integer. ## Endpoints GET https://recipes.airigs.net/api/v1/health GET https://recipes.airigs.net/api/v1/me GET https://recipes.airigs.net/api/v1/recipes?q=&engine=&model=&author=&sort=recent|fastest&page=&limit= GET https://recipes.airigs.net/api/v1/recipes/{slug} POST https://recipes.airigs.net/api/v1/recipes POST https://recipes.airigs.net/api/v1/recipes/{slug}/benchmark DELETE https://recipes.airigs.net/api/v1/recipes/{slug}/benchmark (author, drafts only) POST https://recipes.airigs.net/api/v1/recipes/{slug}/publish PATCH https://recipes.airigs.net/api/v1/recipes/{slug} DELETE https://recipes.airigs.net/api/v1/recipes/{slug} GET https://recipes.airigs.net/api/v1/recipes/{slug}/script?format=sh|raw GET https://recipes.airigs.net/api/v1/models/search?q=&source=huggingface|modelscope&limit=1..20 (auth required) GET https://recipes.airigs.net/api/v1/rigs GET https://recipes.airigs.net/api/v1/openapi.json Errors are JSON: {"status":{"code":422,"message":"..."},"errors":[{"path":"benchmark.ttftMs","message":"..."}]} ## Publishing checklist A recipe publishes only when all of these hold, re-checked at publish time: - rigId belongs to the author's AIRigs account and the rig is currently verified - at least one model - at least one engine argument, or a launchCommand (single line), or customInstructions - a recipe benchmark whose rigId equals the recipe rigId **and** whose server-stamped rigRevision equals the revision of the currently verified rig The rig and its benchmark are snapshotted onto the recipe at publish, together with the rig's integer revision. POST /benchmark fetches the author's current verified rig and stamps benchmark.rigRevision itself; a client-supplied value is ignored. Publishing rejects a benchmark measured on any other revision (422, path benchmark.rigRevision). A PATCH that changes rigId atomically clears benchmark, benchmarkRigRevision and the benchmark state and rebinds the snapshot; the response carries notice and cleared:['benchmark'], and publishing is blocked until a new benchmark is attached. DELETE /benchmark clears a draft benchmark. Lifecycle writes are conditional on the recipe version: a concurrent publish/retarget/attach that lost the race returns 409 with the current state instead of overwriting it. A published recipe's benchmark stays bound to its pinned rig revision; stale writes cannot remove it. Older rows are protected by an updatedAt/status/benchmark fallback until the one-time make migrate backfills an integer version and versionAt on every recipe. If AIRigs later reports a different rig revision the recipe is marked rigStale and keeps rendering the pinned snapshot; if the rig disappears it is marked rigMissing and the snapshot is still served. Neither case rewrites the published numbers. ## Benchmark payload POST /api/v1/recipes/{slug}/benchmark with Content-Type: application/json: { "schemaVersion": 1, "rigId": "r_example", "rigRevision": 7, "engine": "vllm", "startedAt": "2026-10-24T10:00:00.000Z", "finishedAt": "2026-10-24T10:12:00.000Z", "modelIds": [ "Qwen/Qwen2.5-32B-Instruct-AWQ" ], "contextTokens": 32768, "concurrency": 8, "requests": 128, "ttftMs": 240.5, "promptTokensPerSec": 1800.2, "outputTokensPerSec": 54.7, "totalTokensPerSec": 1854.9, "vramPeakBytes": 22548578304, "ramPeakBytes": 68719476736, "powerAvgW": 612, "gpuUtilPct": 97, "notes": "temperature 0, 512 output tokens per request" } Required: schemaVersion (1), rigId, engine, startedAt, finishedAt, modelIds (>=1), concurrency, ttftMs, outputTokensPerSec, vramPeakBytes, powerAvgW. Timestamps are ISO 8601, finishedAt >= startedAt, the run must last between 1 second and 6 hours, finishedAt may be at most 5 minutes in the future, and rigId must match the recipe and the pattern ^r_[A-Za-z0-9_-]{1,92}$. rigRevision above is server-stamped on attach (7 is an example); do not try to set it. ## CLI (standalone repository) The benchmark harness and CLI are a separate project at https://git.fedesito.me/fedes1to/airigs-cli. Install it from that repository: pipx install 'git+https://git.fedesito.me/fedes1to/airigs-cli.git' pipx inject airigs torch # optional: TFLOPS, measured bandwidth, P2P Point it at these endpoints: export AIRIGS_URL=https://airigs.net export RECIPES_URL=https://recipes.airigs.net airigs login airigs doctor Full loop: airigs bench --output bench.json airigs rig submit --name "workstation" --benchmark bench.json airigs recipe init --name "70B on 2x4090" airigs recipe validate airigs recipe submit # draft; --publish runs publish checks airigs recipe bench --endpoint http://localhost:8000/v1 --engine vllm --context 8192 --concurrency 4 --requests 16 --model --publish airigs recipe script --out run.sh airigs recipe run --yes -- --port 8000 Agent/CI flags: --json on every command (before or after the subcommand), --yes for deletes and recipe run, --no-browser for login, --verbose (tokens redacted), AIRIGS_TOKEN / RECIPES_TOKEN for auth, AIRIGS_YES=1 as the non-TTY confirmation gate. Exit codes: 1 general, 3 auth/forbidden, 4 not found/conflict, 5 validation, 6 rate limit. Errors are {"error": "...", "status": 422} on stderr when --json is set. Installation, commands and configuration: https://recipes.airigs.net/docs/cli and https://git.fedesito.me/fedes1to/airigs-cli. ## Script download GET /api/v1/recipes/{slug}/script?format=sh returns a deterministic POSIX sh script: single-quoted arguments, no control characters, no server-side execution. The "raw" format returns the same bytes as text/plain. The script is generated from recipe fields (engine, models, arguments, or the author's launchCommand), not from the benchmark and not from the live rig. If the recipe is rigStale, the script still describes the published recipe while the page warns that AIRigs now reports a different rig revision. Engine templates: vllm, sglang, llamacpp, strata, omlx, ollama, custom. "custom" recipes require a launchCommand and the generated script refuses to run it unless AIRIGS_YES=1 or --yes is passed. ## Rate limits and proxy behaviour Recipes applies fixed-window limits before doing work or calling AIRigs. They are counted per resolved client IP. In development the health endpoint reports request.ip and the effective request.trustProxy for diagnostics; a production process omits that object. - API authentication attempts: 60/min per IP and 200/min globally, charged on every bearer request (cached or not) so cache membership is not observable; only the upstream introspection call is skipped for cached tokens. Exceeding it returns 429. - Public recipe list (page and API): 60/min per IP and 600/min globally. - Recipe detail pages: 120/min per IP. Script downloads: 60/min per IP. - Authenticated endpoints that call AIRigs (GET /me, GET /rigs, recipe create/benchmark/ publish/PATCH) are limited to 60/min per IP, in addition to the authentication budget. - Dashboard and submit pages: 60/min per IP; page publish: 30/min per IP. - Model catalogue search: 30/min per IP plus a 300/min global budget for cache misses. - Login and OAuth callback: 20/min per IP. Recipe submission: 30/min per IP. - AIRigs introspection itself is budgeted by the provider (240/min per source IP). Recipes maps a provider 429 or 5xx to **503** with Retry-After; it does not retry inside the request. TRUST_PROXY is false by default, so X-Forwarded-For is ignored and all clients share the socket-address bucket. Set it to an explicit proxy address/CIDR list only when a trusted proxy overwrites the header; true/1 is refused in production. This is why a spoofed X-Forwarded-For cannot reset a limiter bucket on the default deployment. ## Notes for agents - Published recipes are public; drafts are visible only to their author (session or bearer). - Do not scrape /dashboard or /submit; they require a session. - The model search endpoint proxies AIRigs' catalogue and requires an authenticated session or bearer token. It is rate limited per client and by a global upstream budget, caps the query at 80 characters and the limit at 20, and refuses oversized upstream responses. - Listing endpoints are rate limited per IP and globally; page is capped at 50 and q at 80 characters. Search uses the text index, not unanchored regexes. - There is no server-side shell execution. The only shell text this site produces is the downloadable script.