Mode Maker · API

Author a mode as a config object

Same mode system, same certification, no canvas. Every field below is a key on the mode config that /api/mode-builder writes and that POST /v1/tests and POST /v1/certify then measure. Steps are unlocked — set them in any order, in one call or six.

The visual builder is the same system with a different instrument. If you would rather see the deliberation as a map than as a body, use Mode Maker (subscriber) — it writes this identical object.

01

Brief

required

Identity and framing. name and ticker are the only hard requirements on a create. mode_key is derived server-side from the name and made unique — you do not set it, and it is permanent once the mode is published, because it is what a deliberation call resolves against.

Display name. Shown on the listing. Required.
Required on create. Exactly four letters, A to Z, stored upper case and shown as Q:XXXX. Unique across every Mode on Quorum; a claimed ticker is refused with 409 ticker_taken. Suggested from the name (GET /api/mode-builder?suggest_ticker=<name>) and yours to edit (?check_ticker= answers availability). Optional on a PATCH: omit it to keep the stored one. It is not mode_key and does not route.
Up to 500 characters. Doubles as the listing tagline fallback.
Request

      
02

Panel

default: dynamic

Whether seats are filled dynamically per request or pinned to a fixed pool. Pinning trades adaptability for reproducibility — certification cares about the latter. Every id is validated server-side; an id that does not resolve is a hard 400, never a silent fallback.

Two rules refuse a save. A new Mode must send pool_strategy; without it the answer is 400 seat_selection_required, because a silent default would pick for you. And "fixed" needs all six seats: three engine_ids and three backup_engine_ids, or 400 six_seats_required.

"dynamic" | "fixed". Required on a new Mode; an edit that omits it keeps the stored one.
Fixed pools only: exactly 3, comma-separated, seat order. Ignored when dynamic.
Fixed pools only: exactly 3, position-aligned (the first backs up seat 1).
Required on create: the lowest subscription tier that may run the Mode. A missing or empty value is refused with 400 tier_required, never defaulted. Optional on a PATCH: omit it to keep the stored one. A floor, not a setting: the server clamps it up to the highest tier any engine you picked actually requires.
Request

      
03

Depth

default: standard · gated

Round ceiling and whether seats critique each other. The ceiling is a cap, not a target — the Judge exits early when the panel has converged, which is most of the time. The four depth presets are real named configurations, not a slider:

deliberation_depthmax roundstoken scaledepth floor
light10.5×—
standard21.0×—
deep31.5×1
exhaustive52.0×2
One of the four presets above.
"gated" activates critique on harder questions only.
Request

      
04

Q Staff

optional

Per-mode overrides for the three non-seat roles. Leave them unset and the mode inherits Quorum's current assignment, which moves as the field moves. Set one and it is pinned until you change it — the server validates that the engine exists, is active, and covers every input modality your own seats require, and returns 400 rather than quietly substituting a different one.

Picks the winning line of reasoning.
Classifies difficulty and question type.
Writes the final answer.
Request

      
05

Mandate

not built

Domain grounding — injected context and jurisdiction. This is where a mode stops being a parameter tweak and becomes a real product. It is listed here because the lever set is real and reviewable, and omitting it would misrepresent the shape of the config object. It accepts no fields today.

Injected context requires document ingestion, and jurisdiction requires a real regional grounding source. Neither is built. The prosumer builder shows this step in the same locked state — same system, same honesty.
06

Listing & commercial

required to publish

What the Marketplace shows, and what a customer is billed to call the mode through the API. Ingredients — provider families, round band, whether seats critique each other — are derived from the config above rather than written here, so you cannot claim a panel shape the mode does not run. Your own revenue share is not settable from this object at all: the payout weight is server-forced, permanently, whatever the request body contains.

One line on the card. Falls back to description.
The stop on the Builder's price slider, from 0 (the lowest). Leave it empty for the recommended setting. Callers pay the engines at cost, the platform fee and the Mode's fee; GET /v1/models publishes the fee per 1M tokens, by tier.
Publish

        

Publishing creates an org for payout tracking if you do not have one, sets the listing to moderation_status: "pending", and returns the real slug. Visibility is forced to public server-side and is never read from the request.

—

The whole object

Everything above, composed. This is the exact body /api/mode-builder accepts — POST to create a draft (name and ticker required), PATCH with mode_id to update one. Omitted keys keep their defaults.

POST /api/mode-builder

    

This page composes the request body from the fields above. It does not send it — copy it into your own client, or use the visual builder if you would rather save from a UI.

07

Test, then certify

Both take a project API key and reference the mode by model — the id from GET /v1/models (a ticker such as QRUM:STAN), not the internal mode key.

/v1/tests is the Lab run the Builder launches: known-answer questions graded against their answers, split across the tiers the mode permits, with optional punch-up. You choose the questions per difficulty (easy, medium, hard), up to 100 each and 300 in total. Each question is priced at the mode’s normal API price at 25% off, billed to the organization and charged only for answered questions. Send dry_run: true for the priced quote without launching. Up to 10 launches per organization per 24h. A connected app (OAuth) bills the person’s plan at real cost instead.

Request
POST /v1/tests
Authorization: Bearer <api_key>

{
  "model": "QRUM:STAN",
  "questions": { "easy": 10, "medium": 10, "hard": 10 },
  "dry_run": true
}
Response
{
  "ok": true,
  "dry_run": true,
  "model": "QRUM:STAN",
  "total_questions": 30,
  "quote": { ... },
  "billed_usd": ...,
  "max_usd": ...,
  "price_basis": "...",
  "per_difficulty": { ... },
  "price": { "lines": [ ... ], "discount_pct": 25, "max_total_usd": ... },
  "note": "A maximum, not a bill: ..."
}

/v1/certify is the certification the Builder runs: a fixed 150-question known-answer set, 50 each of easy, medium and hard, graded against their answers and priced per question by depth at 25% off, charged only for questions answered. Send dry_run: true for the quote and punch_up: true to add the Builder’s punch-up once the certificate is graded. The mode must already have a Marketplace listing. On completion the run pins the same public card an in-app certification pins, and the finished batch carries certification.pinned. Only the owning organization can certify. An API key bills the organization; a connected app (OAuth) bills the person’s plan at real cost. Up to 3 launches per organization per 24h.

Request
POST /v1/certify
Authorization: Bearer <api_key>

{
  "model": "QRUM:STAN"
}
Response
{
  "ok": true,
  "batch_id": "…",
  "model": "QRUM:STAN",
  "total_questions": 150,
  "billed_usd": ...,
  "max_usd": ...,
  "price_basis": "...",
  "per_difficulty": { ... },
  "status_url": "/v1/certify?batch_id=…"
}

Real, disclosed constraint, returned in the response rather than buried: the shared execution engine processes roughly one question per minute per batch. A 150-question certification run takes about two and a half hours, not seconds. Poll status_url — GET /v1/certify?batch_id=… and GET /v1/tests?batch_id=… both return progress, and the scorecard once graded.

/api/mode-builder takes a session token, or a project API key issued with the Can edit Modes scope (modes:write, granted at issue by an owner or admin). A key’s save is always a draft, private and inactive, until action: promote_draft re-validates and releases it. A key can never set the price-override flag; that confirmation stays with a person in the Builder.