spawn-llm
v0.1.0
Published
Bun-first callable wrapper for spawning LLM agents through user-installed CLIs.
Maintainers
Readme
spawn-llm
Run LLM coding agents from Node.js or Bun through the CLIs your users already have installed.
spawn-llm gives you one callable API over tools like Codex CLI, Claude Code, Gemini CLI, and opencode. It does not require provider API keys in your app; authentication stays inside each user's local CLI setup.
Features
- Unified API:
const spawn = new SpawnLLM(); await spawn({...}) - CLI-first: uses locally installed and authenticated agent CLIs
- Text streaming with
onText - TypeScript declarations included
- Works from Bun and Node.js ESM projects
- Windows npm shim support for CLIs like
opencode.cmd
Install
npm install spawn-llmOr with Bun:
bun add spawn-llmQuick Start
import { SpawnLLM } from 'spawn-llm';
const spawn = new SpawnLLM({
adapter: 'opencode'
});
const result = await spawn({
model: 'opencode/big-pickle',
instructions: 'Read this project and explain what it does.',
onText: (chunk) => process.stdout.write(chunk)
});
console.log('\n\nFinal:', result.finalMessage);Supported Adapters
| Adapter | CLI command | Aliases |
| --- | --- | --- |
| Codex CLI | codex | codex, codex-cli |
| Claude Code | claude | claude, claude-code |
| Gemini CLI | gemini | gemini, gemini-cli |
| opencode | opencode | opencode, opencode-cli |
The selected CLI must already be installed and authenticated on the user's machine.
Codex CLI
const spawn = new SpawnLLM({
adapter: 'codex'
});
const result = await spawn({
model: 'gpt-5.4',
instructions: 'Review this repository and suggest the smallest safe refactor.',
yolo: true,
onText: (chunk) => process.stdout.write(chunk)
});
console.log(result.finalMessage);yolo: true maps to Codex's real bypass flag: --dangerously-bypass-approvals-and-sandbox.
Claude Code
const spawn = new SpawnLLM({
adapter: 'claude-code'
});
const result = await spawn({
model: 'sonnet',
instructions: 'Return the top 3 risks in this project.',
permissionMode: 'dontAsk'
});
console.log(result.finalMessage);Gemini CLI
const spawn = new SpawnLLM({
adapter: 'gemini'
});
const result = await spawn({
model: 'gemini-2.5-pro',
instructions: 'Summarize this repository.',
approvalMode: 'plan'
});
console.log(result.finalMessage);For permissive mode:
await spawn({
model: 'gemini-2.5-pro',
instructions: 'Make the requested changes.',
yolo: true
});For Gemini, yolo: true maps to --approval-mode yolo.
opencode
const spawn = new SpawnLLM({
adapter: 'opencode'
});
const result = await spawn({
model: 'opencode/big-pickle',
instructions: 'Explain this package in a few sentences.',
agent: 'plan',
variant: 'high',
onText: (chunk) => process.stdout.write(chunk)
});
console.log('\n\nFinal:', result.finalMessage);You can list local opencode models with:
opencode modelsStreaming
Use onText for user-facing streaming:
await spawn({
adapter: 'codex',
model: 'gpt-5.4',
instructions: 'Explain this codebase step by step.',
onText: (chunk) => process.stdout.write(chunk)
});Use onStdout only when you want raw CLI output. Some adapters emit JSONL internally.
Passing Context
const result = await spawn({
adapter: 'codex',
model: 'gpt-5.4',
instructions: [
'Create a concise release note.',
'Return only markdown.'
],
input: {
version: '1.2.0',
changes: ['Added opencode adapter', 'Improved Windows CLI resolution']
}
});Options
adapter:codex,codex-cli,claude,claude-code,gemini,gemini-cli,opencode, oropencode-cli.model: model name passed to the selected CLI.instructionsorprompt: required prompt text.input: optional string or JSON-serializable data appended to the prompt.cwd: working directory for the CLI process.yolo: shortcut for the selected CLI's most permissive mode.sandbox: Codex sandbox mode.approvalPolicy: Codex approval policy.approvalMode: Gemini approval mode.permissionMode: Claude Code permission mode.agent: CLI-specific agent name for Claude Code or opencode.variant: opencode model variant or reasoning effort.outputFormat: output mode for CLIs that support it.args: raw extra CLI args.timeoutMs: process timeout. Defaults to 10 minutes.onText: normalized text stream callback.onStdout: raw stdout callback.onStderr: raw stderr callback.
Result
interface SpawnLLMResult {
adapter: string;
command: string | null;
args: string[];
cwd: string;
exitCode: number | null;
signal: string | null;
stdout: string;
stderr: string;
finalMessage: string;
events: unknown[];
}Most apps should read result.finalMessage.
Windows Notes
On Windows, many CLIs installed through npm expose .cmd or .ps1 shims. spawn-llm resolves common npm shims and runs the underlying JS entrypoint with the current Node executable, avoiding errors such as:
spawn opencode ENOENTIf a CLI is installed in a non-standard location, pass command manually:
const spawn = new SpawnLLM({
adapter: 'opencode',
command: 'C:\\path\\to\\opencode.cmd'
});Development
bun install
bun run typecheck
bun test
bun run buildLicense
MIT
