BYOK compose — using your own API key end to end
Bring your own OpenAI / Anthropic / OpenRouter key, run /compose synchronously, and never let your key touch our database. Here is the data path.
What BYOK is for
Two reasons people turn it on:
- Cost control. The hosted compose flow runs against the registry's daily LLM budget. If the budget is exhausted, you hit 429s. With BYOK, you bypass the budget and use your own provider key directly.
- Privacy posture. Your provider key is held in component state for one request and dropped. The registry server forwards it to the LLM, but never stores it. If you have a strict data policy that says "no third-party keys at rest", BYOK is the path.
The shape of the request
The default /compose flow is async: enqueue a job, poll for
status, get a result. BYOK is sync: a single POST /v1/intent/byo
that holds the connection open until the LLM responds (or the user
cancels).
Why sync? Because BYOK runs are tied to a tab — closing the tab should cancel the run, free the model context, and drop your key from memory. A sync request makes that trivial:
Browser tab closes
→ AbortController fires
→ fetch() throws AbortError
→ registry route observes the abort
→ returns 499 (client closed)
→ run cleanly ends
No background worker, no zombie LLM calls.
Step 1 — get a key
Sign in to OpenAI / Anthropic / OpenRouter. Generate a fresh API key scoped to compose. Recommended: a short-lived key with a small spending cap, dedicated to this use.
We don't recommend reusing a production key. The compose flow is exploratory; a stray run could burn through your team's budget.
Step 2 — open BYOK in /compose
Click the BYO panel below the goal field. Pick provider + model. Paste the key. The form does three things to defend the key:
- The input is
type="password"so it's masked in the DOM. - The component state is dropped the moment the request resolves — whether success, failure, or abort.
- The fetch uses an AbortController; closing the tab calls
controller.abort()so the in-flight request dies before the key could be re-sent.
Step 3 — submit
Type a goal. Click "Plan with my key." The progress bar shows the phases live (classifying / planning / drafting / analyzing). Cancel at any time with the Cancel button — the registry sees the abort within milliseconds.
When the run completes:
- The drafts appear inline.
- Your key is dropped from React state.
- No row is written to
intent_jobs(sync runs don't queue). - A telemetry counter ticks up: 1 BYOK compose, by provider, no key contents.
Step 4 — sanity-check that nothing leaked
Open the network tab. Filter by your domain. You'll see exactly two requests:
POST /v1/intent/byo— your goal + your key. TLS only, server-side never logged.- The streaming SSE for status updates if your client supports them.
Search the registry's audit log for your handle. The publish event records the key was used; it does not record the key value.
Step 5 — saving the plan
If you like the drafts, click "Save plan." Saving copies the plan to
the registry's intent_plans table — without your key. Future visits
to /me/plans can resume the bundle wizard without ever needing
your key again.
The key only mattered for the one inference call that produced the drafts. Once they exist, they're plain manifests + markdown, signed by you.
Threat model — what BYOK does and doesn't protect
Protects against:
- Registry operators reading your key at rest (it's not at rest).
- Registry breach exposing keys (no keys to leak).
- Compute budget exhaustion (you're spending your own quota).
Does not protect against:
- A compromised registry server in real time. The proxy sees the key and the request body for ~5 seconds. If the registry binary is malicious, it could exfiltrate. Your defense is operating a trusted registry (or running your own).
- Your own browser. A compromised extension can read the React state. Standard browser hygiene applies.
- The LLM provider. They see the goal + your key + their inference output. That's between you and them.
When NOT to use BYOK
- For batch / cron / agent-side compose runs. The async queue is cheaper and more reliable; you don't need the privacy posture because you're not on a browser tab.
- For one-shot tests of public skills. If the registry's daily budget isn't exhausted, the hosted flow is fine.
- When you're debugging the planner. The async queue records every phase; BYOK runs don't, so debugging is harder.
For everything else — exploratory composes, privacy-conscious teams, budget guard-rails — BYOK is the right path.