<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adam Boon</title>
    <description>The latest articles on DEV Community by Adam Boon (@adamboon1984arch).</description>
    <link>https://dev.to/adamboon1984arch</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3852801%2F9d6d467e-a05e-4d61-9956-dfff9366addf.jpeg</url>
      <title>DEV Community: Adam Boon</title>
      <link>https://dev.to/adamboon1984arch</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adamboon1984arch"/>
    <language>en</language>
    <item>
      <title>Stop rebuilding BYOK from scratch — I extracted it into a package</title>
      <dc:creator>Adam Boon</dc:creator>
      <pubDate>Tue, 31 Mar 2026 06:10:11 +0000</pubDate>
      <link>https://dev.to/adamboon1984arch/stop-rebuilding-byok-from-scratch-i-extracted-it-into-a-package-2bk2</link>
      <guid>https://dev.to/adamboon1984arch/stop-rebuilding-byok-from-scratch-i-extracted-it-into-a-package-2bk2</guid>
      <description>&lt;p&gt;Every AI SaaS project I've worked on hits the same wall.&lt;/p&gt;

&lt;p&gt;You need to let users bring their own API keys — or your infrastructure needs to route across providers with fallbacks. Either way, you end up building the same thing: key validation, provider selection, cost estimation, health checks.&lt;/p&gt;

&lt;p&gt;Then you maintain it. Then you build it again in the next project.&lt;/p&gt;

&lt;p&gt;I got tired of it, so I extracted that layer into a package.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it is
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Restormel Keys&lt;/strong&gt; is a headless BYOK and provider routing library for AI apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2c7izwi7qw3yqt6hap5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2c7izwi7qw3yqt6hap5o.png" alt=" " width="800" height="901"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add @restormel/keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createKeys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;openaiProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;anthropicProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@restormel/keys&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createKeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;routing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;defaultProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;openaiProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;anthropicProvider&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Resolves which key to use: BYOK → fallback chain → platform key&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4o&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Cost estimation before you make the call&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;estimateCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the core. Everything else builds on it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it actually handles
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgvim4qqki515oju4i32f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgvim4qqki515oju4i32f.png" alt=" " width="800" height="838"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BYOK flows&lt;/strong&gt; — users supply their own keys; you validate and store them 
however you want (the package is headless, no storage opinion)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-provider routing&lt;/strong&gt; — OpenAI, Anthropic, Google, plus 8 more 
(Mistral, Groq, Together, DeepSeek, Fireworks, Cohere, Perplexity, Azure)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fallback chains&lt;/strong&gt; — if a key fails, fall through to the next configured 
provider&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost estimation&lt;/strong&gt; — before you make a request, not after&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key validation&lt;/strong&gt; — per-provider, with async persistence hooks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policies&lt;/strong&gt; — allow/deny models, enforce budget caps, keep routing behaviour 
inspectable&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Framework support
&lt;/h2&gt;

&lt;p&gt;The headless core works anywhere. UI components (KeyManager, ModelSelector, &lt;br&gt;
CostEstimator) are available for SvelteKit today.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# SvelteKit&lt;/span&gt;
pnpm add @restormel/keys @restormel/keys-svelte

&lt;span class="c"&gt;# React / Next.js App Router&lt;/span&gt;
pnpm add @restormel/keys @restormel/keys-react @restormel/keys-elements
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Before installing the UI packages, run &lt;code&gt;npm view @restormel/keys-react version&lt;/code&gt; &lt;br&gt;
to confirm availability. The headless core always works.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The CLI
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx keys init          &lt;span class="c"&gt;# detect framework, generate config&lt;/span&gt;
npx keys add openai    &lt;span class="c"&gt;# prompt, validate, store&lt;/span&gt;
npx keys validate      &lt;span class="c"&gt;# exit 1 if invalid — good for CI&lt;/span&gt;
npx keys estimate gpt-4o-mini &lt;span class="nt"&gt;--input&lt;/span&gt; 10 &lt;span class="nt"&gt;--output&lt;/span&gt; 2
npx @restormel/doctor  &lt;span class="c"&gt;# is everything wired up correctly?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  I've been dogfooding it
&lt;/h2&gt;

&lt;p&gt;I've been running this in production through &lt;a href="https://usesophia.app" rel="noopener noreferrer"&gt;usesophia.app&lt;/a&gt; — &lt;br&gt;
worth checking out to see what a real BYOK integration looks like with this stack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdgellpuf284kj0zn11e4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdgellpuf284kj0zn11e4.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Early access
&lt;/h2&gt;

&lt;p&gt;It's free to start. First 50 Pro signups get 12 months free — that's the &lt;br&gt;
founding cohort offer while the product is in early access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;restormel.dev/keys&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Two questions I'd genuinely like your input on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is BYOK a real constraint you're dealing with, or do you absorb AI costs yourself?&lt;/li&gt;
&lt;li&gt;Is there another part of the AI product layer you keep rebuilding that should just be a package?&lt;/li&gt;
&lt;/ol&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
