The boilerplate ships with both the Anthropic Claude Agent SDK and the OpenAI SDK pre-wired, plus a working demo screen, secure API key storage, and a streaming-response parser. You can have a working AI feature in your app in under an hour.
What's already in the box
- A fully functional AI Demo screen at
src/features/ai-demo/— pick a provider, paste your API key, send a prompt, watch it stream back. - Secure key storage via Electron's
safeStorage(macOS Keychain, Windows Credential Manager, Linux libsecret). - Server-Sent Events parser for streaming LLM responses with backpressure handling.
- A clean provider interface in
src/main/ai/so adding a third provider is one new file.
Where API keys live
Never store keys in your renderer code. The boilerplate exposes a typed hook:
import { useApiKey } from '@/renderer/hooks/useApiKey'
const { key, set, clear, isSet } = useApiKey('anthropic')
// Store
await set('sk-ant-...')
// Read (only on user action — never on render)
const k = await key()Behind the scenes, the key is encrypted with the OS keychain via safeStorage and never leaves the main process unless the user explicitly requests it.
Calling Claude
// src/main/ai/claude.ts — already in the boilerplate
import Anthropic from '@anthropic-ai/sdk'
export async function* streamClaude(prompt: string, apiKey: string) {
const client = new Anthropic({ apiKey })
const stream = await client.messages.stream({
model: 'claude-sonnet-4-5',
max_tokens: 4096,
messages: [{ role: 'user', content: prompt }],
})
for await (const event of stream) {
if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
yield event.delta.text
}
}
}In your renderer, consume the stream over IPC:
// in any React component
import { useAi } from '@/renderer/hooks/useAi'
const { stream, isStreaming } = useAi('claude')
async function ask() {
for await (const chunk of stream('Summarize this PDF in 5 bullets...')) {
setOutput((prev) => prev + chunk)
}
}Adding your own provider
Three files. That's the pattern:
src/main/ai/<provider>.ts— the SDK client + a generator that yields tokenssrc/shared/ipc/ai-channels.ts— add'ai:stream:<provider>'channel namesrc/renderer/hooks/useAi.ts— add<provider>to the discriminated union
The boilerplate uses Claude 4.5 by default
When you copy the demo code, update the model ID to whatever you're shipping. Anthropic and OpenAI both deprecate older models; pin to a version that's covered by your prompt cache strategy.
Ask your AI assistant
"I want to add a feature that summarizes the user's clipboard with Claude. Following the patterns in src/features/ai-demo/, scaffold the IPC channel, main-process handler, and React hook. Use streaming. Don't write the UI yet — I want to design that part."
Where to go from here
- All the deep technical docs live in the repo at
/docs/(read after purchase). - Stuck? Read
CLAUDE.mdonce — it gives any AI coding tool the full context to help you extend the boilerplate.