add-provider
Use when adding a new LLM provider to ra.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Use when adding a new LLM provider to ra.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
System design and architecture decisions. Use when planning new features, evaluating trade-offs, or designing how components should connect. Proposes 2-3 approaches and recommends one.
Smart commit workflow. Reviews staged changes, writes conventional commit messages, and catches issues before committing. Use when ready to commit work.
Quality review of completed work. Use after making changes and before claiming completion. Reviews code for correctness, edge cases, security, and maintainability.
Systematic debugging workflow. Use when diagnosing bugs, test failures, or unexpected behavior. Follows a rigorous reproduce → isolate → hypothesize → fix → verify cycle.
Systematic multi-agent research. Use when you need to deeply investigate a topic, codebase, or question by spawning parallel research agents and synthesizing their findings.
Deep code explanation. Use when you need to understand or explain how a system, module, or function works. Traces data flow, maps dependencies, and explains design decisions.
| name | add-provider |
| description | Use when adding a new LLM provider to ra. |
See src/providers/CLAUDE.md for the adapter pattern and StreamChunk contract. Use anthropic.ts as a template.
src/providers/<name>.ts — Provider class:import type { IProvider, ChatRequest, ChatResponse, StreamChunk } from './types'
export interface XProviderOptions {
apiKey: string
}
export class XProvider implements IProvider {
readonly name = 'x'
private client: SdkClient
constructor(options: XProviderOptions) {
this.client = new SdkClient({ apiKey: options.apiKey })
}
buildParams(request: ChatRequest) {
return {
model: request.model,
messages: this.mapMessages(request.messages),
...(request.tools?.length && { tools: this.mapTools(request.tools) }),
...(request.thinking && { /* provider-specific thinking config */ }),
}
}
async chat(request: ChatRequest): Promise<ChatResponse> { /* ... */ }
async *stream(request: ChatRequest): AsyncIterable<StreamChunk> {
// Must yield: text, tool_call_start, tool_call_delta*, tool_call_end, done
// done chunk MUST include usage if available
}
private mapMessages(messages: IMessage[]) { /* ra → SDK */ }
private mapTools(tools: ITool[]) { /* ra → SDK */ }
private mapResponseToMessage(response: SdkResponse): IMessage { /* SDK → ra */ }
}
src/providers/registry.ts — Add to ProviderOptionsMap, import class, add case to createProvider()
src/config/types.ts — Add to ProviderName union and providers field in RaConfig
src/config/defaults.ts — Add default options under providers
src/config/index.ts — Add env var mapping (RA_<NAME>_API_KEY)
tests/providers/<name>.test.ts — Mock the SDK client, test buildParams(), stream() chunk sequence
Verify: bun tsc → bun test → bun run ra --provider <name> --model <model> "Hello"
stream() is primary — the loop always uses streaming. chat() is secondary.stream() must yield a { type: 'done' } chunk at the end, even if the SDK doesn't emit one.buildParams() should be a separate method so tests can inspect requests without mocking the SDK....(x && { key: x }).