Skip to content

fix: route keys by their variable, never by their shape - #13

Merged
FrancoisChastel merged 1 commit into
mainfrom
fix/route-by-variable
Oct 3, 2026
Merged

FrancoisChastel merged 1 commit into
mainfrom
fix/route-by-variable

Conversation

@FrancoisChastel

@FrancoisChastel FrancoisChastel commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Why

TypeSafe issues apikey_... keys as well as ts_... ones, and key shapes can change at any time. Until now jev-code routed a key to a host by its prefix, whichever variable held it, so an apikey_ key in TYPESAFE_API_KEY was treated as "unknown prefix" and a key shaped like another host's was silently rerouted. Routing by shape is a guess, and guesses about credentials are the wrong default.

What changes

  • The variable decides the host. TYPESAFE_API_KEY goes to TypeSafe, OPENROUTER_API_KEY to OpenRouter, AI_GATEWAY_API_KEY to Vercel AI Gateway, OPENAI_API_KEY to OpenAI (still opt-in), whatever the key looks like.
  • Prefixes are hints only. doctor says "TYPESAFE_API_KEY looks like an OpenRouter key (sk-or-…) but is sent to TypeSafe, as set" and tells you where to move it. apikey_ is now a recognised TypeSafe shape.
  • The TypeSafe SDK convention is kept. TYPESAFE_API_KEY is the generic variable the official SDK reads, so it follows TYPESAFE_BASE_URL and JEV_CODE_PROVIDER to OpenRouter or Vercel the way the SDK does (their setup guides set exactly that pair). It never follows to OpenAI (different wire) or Ollama.
  • Host-specific variables never travel. OPENROUTER_API_KEY with JEV_CODE_PROVIDER=typesafe or a base URL on another known host is refused before any request, with the fix named. A proxy base URL still needs JEV_CODE_PROVIDER for a host-specific key.
  • With JEV_CODE_PROVIDER=ollama, a stale TYPESAFE_BASE_URL on another known host is now refused (found by the security review; before, it carried Ollama's key and the payload there).
  • setup asks which host a pasted key is for ([1] TypeSafe [2] OpenRouter [3] Vercel AI Gateway [4] OpenAI Decisions API, number or name, Enter for the default). The default is the JEV_CODE_PROVIDER host, else the prefix hint, else TypeSafe. New readLine helper next to readSecret.

Behaviour changes to note

Environment 0.4.0 This PR
TYPESAFE_API_KEY=apikey_… TypeSafe (treated as unknown prefix) TypeSafe, no note
TYPESAFE_API_KEY=sk-or-… OpenRouter TypeSafe, with a "looks like" hint
TYPESAFE_API_KEY=ts_… + TYPESAFE_BASE_URL=https://openrouter.ai/api refused OpenRouter (SDK convention), with a hint
TYPESAFE_API_KEY=sk-proj-… + JEV_CODE_PROVIDER=openai OpenAI refused: export OPENAI_API_KEY
OPENROUTER_API_KEY=… + JEV_CODE_PROVIDER=typesafe refused refused (clearer message)

Test plan

  • npm run check (lint, typecheck, skill validation, 145 tests at 96% lines, build, MCP smoke)
  • doctor run against nine env combinations; messages reviewed by hand
  • Interactive setup opencode driven through a pseudo-terminal: hidden key prompt, visible host question answered with 2, key written to OPENROUTER_API_KEY
  • Code, security, and TypeScript reviews; findings fixed (EOF handling and carry-over in the prompts, the Ollama base URL guard, hint wording)
  • README, SECURITY.md, .env.example, harness guides, CLI help, and skill reference updated; no prefix routing claims remain

TypeSafe issues apikey_ keys as well as ts_ ones, and key shapes can
change, so a key's prefix no longer decides where it is sent. The
variable a key sits in decides its host; a key that looks like another
host's only earns a hint in doctor. TYPESAFE_API_KEY keeps following
TYPESAFE_BASE_URL and JEV_CODE_PROVIDER to OpenRouter and Vercel the way
the TypeSafe SDK does; host-specific variables never travel, and the
generic key never follows to OpenAI or Ollama.

setup now asks which host a pasted key is for, defaulting to the
JEV_CODE_PROVIDER host, else the prefix hint, else TypeSafe. The prompts
settle when input ends and hand text after a newline to the next prompt.
With JEV_CODE_PROVIDER=ollama, a stale TYPESAFE_BASE_URL on another
known host is refused instead of carrying Ollama's key there.
@FrancoisChastel
FrancoisChastel merged commit 6076b6d into main Oct 3, 2026
4 checks passed
@FrancoisChastel
FrancoisChastel deleted the fix/route-by-variable branch October 3, 2026 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant