@secemp/elwood
v0.1.2
Published
Programmatically import and instrument the locally installed Claude Code CLI via Babel AST
Maintainers
Readme
elwood
Programmatically import and instrument the locally installed Claude Code CLI via Babel AST. Drop-in replacement for @anthropic-ai/claude-agent-sdk that runs in-process -- zero subprocess spawning.
How it works
Instead of spawning claude -p as a subprocess (like the official SDK), elwood:
- Locates the installed Claude Code CLI (
cli.js) - Parses the 13MB bundle with Babel AST
- Fingerprints internal functions via evidence-based pattern matching
- Injects instrumentation hooks
- Calls
agentLoop()directly in-process
This gives you the same API as @anthropic-ai/claude-agent-sdk with lower latency and direct access to internals.
Install
npm install @secemp/elwoodRequires Claude Code to be installed:
npm install -g @anthropic-ai/claude-codeQuick start
import { query } from '@secemp/elwood';
for await (const message of query({
prompt: 'What files are in this directory?',
options: { maxTurns: 3 },
})) {
if (message.type === 'result') {
console.log(message.result);
}
}No API key needed if logged in via claude login (Pro/Max subscription).
API
query({ prompt, options })
Returns an async generator yielding messages. Options include:
model-- model to usesystemPrompt-- string or{type: 'preset', append: '...'}maxTurns-- maximum conversation turnsallowedTools-- auto-approve these toolshooks--{PreToolUse: [...], PostToolUse: [...], ...}mcpServers-- MCP server configspermissionMode--'default' | 'acceptEdits' | 'bypassPermissions'continue/resume/resumeSessionAt/forkSession-- session managementenv/stderr-- environment and output control- ...and all other official SDK options
Query control methods
const conversation = query({ prompt: '...' });
conversation.interrupt(); // soft interrupt
conversation.setModel('...'); // change model mid-conversation
conversation.setPermissionMode('acceptEdits');
await conversation.supportedModels();
await conversation.supportedCommands();
conversation.close(); // cleanuptool(name, description, schema, handler)
import { tool, createSdkMcpServer, query } from '@secemp/elwood';
const weather = tool('get_weather', 'Get weather',
{ type: 'object', properties: { city: { type: 'string' } } },
({ city }) => `72F in ${city}`
);
const server = await createSdkMcpServer({ tools: [weather] });
for await (const msg of query({
prompt: 'Weather in NYC?',
options: { mcpServers: [server] },
})) { /* ... */ }Session utilities
import { listSessions, getSessionMessages, getSessionInfo } from '@secemp/elwood';
const sessions = await listSessions();
const messages = await getSessionMessages(sessions[0].id);V2 Session API
import { unstable_v2_createSession, unstable_v2_prompt } from '@secemp/elwood';
const result = await unstable_v2_prompt('Explain recursion');Low-level AST access
import { locate, load, instrument, parseBundle } from '@secemp/elwood';
const { cliPath, version } = await locate();
const ast = parseBundle(cliPath);Auth
Works with all Claude Code auth methods:
- Claude Pro/Max subscription (
claude login) ANTHROPIC_API_KEYenvironment variable- OAuth tokens
- Bedrock/Vertex/Foundry
Examples
See the examples/ directory for 24 working examples covering queries, hooks, MCP, custom tools, sessions, and more.
License
MIT
