A JavaScript SDK for integrating with Claude Code, Anthropic's official CLI tool for Claude.
This project provides a JavaScript/TypeScript SDK that allows developers to programmatically interact with Claude Code, enabling AI-powered software engineering capabilities in their applications.
npm install claude-code-js
or with yarn:
import{ClaudeCode}from'claude-code-js';// Initialize the SDKconstclaude=newClaudeCode({apiKey: process.env.CLAUDE_API_KEY,// Optional: if already logged inmodel: 'claude-3-sonnet',// Optional: specify modelworkingDirectory: './my-project',// Optional: set working directoryverbose: false// Optional: enable verbose logging});
// Send a chat message to Claude with a promptconstresponse=awaitclaude.chat({prompt: 'Explain this error: TypeError: Cannot read property of undefined',systemPrompt: 'You are a helpful coding assistant',// OptionalappendSystemPrompt: 'Keep explanations concise'// Optional});if(response.success){console.log('Result:',response.message.result);console.log('Session ID:',response.message.session_id);console.log('Cost:',response.message.cost_usd);}else{console.error('Error:',response.error.message);}
Run Commands Through Claude
// Have Claude execute a taskconstresult=awaitclaude.runCommand('Fix the failing tests in src/utils.test.js');if(result.success){console.log('Claude completed the task');console.log('Result:',result.message.result);console.log('Duration:',result.message.duration_ms,'ms');}
Sessions for Multi-turn Conversations
// Create a new session for ongoing conversationsconstsession=claude.newSession();// Start the conversationconstfirstMessage=awaitsession.prompt({prompt: 'What is 2 + 2?',systemPrompt: 'You are expert at math. Always return a single line of text in format: equation = result'});console.log('First response:',firstMessage.result);// Continue the conversationconstsecondMessage=awaitsession.prompt({prompt: '3 + 3 = 6'});console.log('Second response:',secondMessage.result);// Ask for historyconsthistory=awaitsession.prompt({prompt: 'Send the history of all validations you have done so far'});console.log('History:',history.result);// Session tracks all messages and session IDsconsole.log('Total messages:',session.messages.length);console.log('All session IDs:',session.sessionIds);
import{executeCommand,streamCommand}from'claude-code-js';// Execute a command and get the full outputconst{ stdout, stderr, exitCode }=awaitexecuteCommand(['npm','test'],{cwd: './my-project',timeout: 30000});// Stream command output in real-timeconststream=streamCommand(['npm','run','dev'],{onStdout: (data)=>console.log('Output:',data),onStderr: (data)=>console.error('Error:',data)});// Wait for completionawaitstream;
constclaude=newClaudeCode();// Create a code review sessionconstreviewer=claude.newSession();// Start the reviewconstinitialReview=awaitreviewer.prompt({prompt: `Review this Express route for security issues: app.post('/login', (req, res) => { const { username, password } = req.body; const user = db.query('SELECT * FROM users WHERE username = "' + username + '"'); if (user && user.password === password) { res.json({ token: jwt.sign({ id: user.id }, 'secret') }); } })`,systemPrompt: 'You are a security-focused code reviewer. Identify vulnerabilities and suggest fixes.'});console.log('Initial review:',initialReview.result);// Ask for specific improvementsconstimprovements=awaitreviewer.prompt({prompt: 'Show me how to fix the SQL injection vulnerability'});console.log('Improved code:',improvements.result);
constclaude=newClaudeCode({workingDirectory: './my-app'});// Generate tests for a specific functionconstresponse=awaitclaude.chat({prompt: `Generate Jest unit tests for this function: export function calculateDiscount(price, discountPercent) { if (discountPercent < 0 || discountPercent > 100) { throw new Error('Invalid discount percentage'); } return price * (1 - discountPercent / 100); }`,systemPrompt: 'Generate comprehensive Jest tests with edge cases'});if(response.success){// Save the generated testsawaitwriteFile('./tests/calculateDiscount.test.js',response.message.result);}
Interactive Debugging Helper
constdebugSession=claude.newSession();// Start the debugging sessionawaitdebugSession.prompt({prompt: 'I have a React component that re-renders infinitely. Help me debug it.',systemPrompt: 'You are a React debugging expert. Ask clarifying questions and provide solutions.'});// Provide more contextawaitdebugSession.prompt({prompt: `Here's my component: function UserList() { const [users, setUsers] = useState([]); const fetchUsers = async () => { const data = await api.getUsers(); setUsers(data); }; fetchUsers(); return <div>{users.map(u => <div>{u.name}</div>)}</div>; }`});// Get step-by-step debugging guidanceconstsolution=awaitdebugSession.prompt({prompt: `What's causing the infinite re-render and how do I fix it?`});
Working with Multiple Sessions
constclaude=newClaudeCode();// Create independent sessions for different tasksconstcodeReviewSession=claude.newSession();constdebugSession=claude.newSession();// Start the code review sessionawaitcodeReviewSession.prompt({prompt: 'Review this code for best practices: function getData() { return fetch("/api").then(r => r.json()) }',systemPrompt: 'You are a code reviewer focused on best practices and performance'});// Start the debugging sessionawaitdebugSession.prompt({prompt: 'Help me debug this error: ReferenceError: user is not defined',systemPrompt: 'You are a debugging expert'});// Continue conversations independentlyawaitcodeReviewSession.prompt({prompt: 'How can I add error handling?'});awaitdebugSession.prompt({prompt: 'The error occurs in line 45 of auth.js'});
// Use output from one session as input to anotherconstmathSession=claude.newSession();constmathResult=awaitmathSession.prompt({prompt: 'Calculate 15 * 23',systemPrompt: 'You are a math expert. Return only the numeric result.'});constvalidationSession=claude.newSession();constvalidationResult=awaitvalidationSession.prompt({prompt: mathResult.result,systemPrompt: 'You are expert at validating math calculations.'});console.log('Validation result:',validationResult.result);
Session Forking and Reverting
Fork Sessions for Parallel Explorations
The fork() method creates a new session with the same conversation history, allowing you to explore different conversation branches without affecting the original session.
constclaude=newClaudeCode();constmainSession=claude.newSession();// Start a conversationawaitmainSession.prompt({prompt: 'Write a function to calculate factorial',systemPrompt: 'You are a helpful coding assistant'});awaitmainSession.prompt({prompt: 'Now make it recursive'});// Fork the session to explore a different approachconstiterativeSession=mainSession.fork();constrecursiveSession=mainSession.fork();// Explore iterative approach in one forkawaititerativeSession.prompt({prompt: 'Actually, show me an iterative version instead'});// Explore memoized approach in another forkawaitrecursiveSession.prompt({prompt: 'Can you add memoization to the recursive version?'});// Original session remains unchangedconsole.log('Main session messages:',mainSession.messages.length);// 2console.log('Iterative fork messages:',iterativeSession.messages.length);// 3console.log('Recursive fork messages:',recursiveSession.messages.length);// 3
The revert() method removes the most recent messages and session IDs, allowing you to "undo" conversation turns.
constsession=claude.newSession();// Build up a conversationawaitsession.prompt({prompt: 'Write a Python hello world'});awaitsession.prompt({prompt: 'Now add a loop that prints it 5 times'});awaitsession.prompt({prompt: 'Add error handling'});console.log('Messages before revert:',session.messages.length);// 3// Revert the last messagesession.revert();console.log('Messages after single revert:',session.messages.length);// 2// Revert multiple messages at oncesession.revert(2);console.log('Messages after reverting 2:',session.messages.length);// 0// Continue from the reverted stateawaitsession.prompt({prompt: 'Write a JavaScript hello world instead'});
Real-World Use Case: A/B Testing Code Solutions
constclaude=newClaudeCode();constsession=claude.newSession();// Set up the problemawaitsession.prompt({prompt: 'I need to process a large CSV file with millions of rows. What approach should I use?',systemPrompt: 'You are an expert in data processing and performance optimization'});// Fork to explore different solutionsconststreamingFork=session.fork();constchunkingFork=session.fork();constparallelFork=session.fork();// Explore streaming approachconststreamingSolution=awaitstreamingFork.prompt({prompt: 'Show me how to implement this using Node.js streams'});// Explore chunking approachconstchunkingSolution=awaitchunkingFork.prompt({prompt: 'Show me how to process this in chunks with a batch size'});// Explore parallel processingconstparallelSolution=awaitparallelFork.prompt({prompt: 'Show me how to use worker threads for parallel processing'});// Compare solutionsconsole.log('Streaming approach:',streamingSolution.result);console.log('Chunking approach:',chunkingSolution.result);console.log('Parallel approach:',parallelSolution.result);// Pick the best approach and continueawaitparallelFork.prompt({prompt: 'Add progress tracking to this implementation'});
// Update configuration on the flyclaude.setOptions({model: 'claude-3-opus',verbose: true});// Get current configurationconstoptions=claude.getOptions();console.log('Current model:',options.model);
// Get the Claude Code CLI versionconstversion=awaitclaude.version();console.log('Claude Code CLI version:',version);
try{constresponse=awaitclaude.chat({prompt: 'Refactor this function to use async/await'});if(!response.success){// Handle Claude Code specific errorsconsole.error(`Error Code: ${response.error.code}`);console.error(`Message: ${response.error.message}`);if(response.error.details){console.error('Details:',response.error.details);}}}catch(error){// Handle network or other errorsconsole.error('Unexpected error:',error);}
The SDK includes full TypeScript support with exported types:
import{ClaudeCode,ClaudeCodeOptions,ClaudeCodeResponse,ClaudeCodeError,ClaudeCodeMessage,Prompt}from'claude-code-js';// Type-safe configurationconstoptions: ClaudeCodeOptions={apiKey: process.env.CLAUDE_API_KEY,model: 'claude-3-sonnet',workingDirectory: './src',verbose: true};constclaude=newClaudeCode(options);// Type-safe promptconstprompt: Prompt={prompt: 'Generate unit tests for auth.js',systemPrompt: 'You are a test generation expert',appendSystemPrompt: 'Use Jest framework'};// Type-safe response handlingconstresponse: ClaudeCodeResponse=awaitclaude.chat(prompt);if(response.success&&response.message){constmessage: ClaudeCodeMessage=response.message;console.log('Result:',message.result);console.log('Cost in USD:',message.cost_usd);console.log('Duration:',message.duration_ms);}
constclaude=newClaudeCode({apiKey: 'your-api-key',// Optional: if already logged in via CLImodel: 'claude-3-sonnet',// Optional: model to useworkingDirectory: './path/to/project',// Optional: working directoryverbose: false// Optional: enable verbose output});
We welcome contributions! If you encounter any issues or have ideas for improvements, please don't hesitate to:
🐛 Report bugs: Open an issue describing the problem and steps to reproduce
💡 Request features: Share your ideas for new functionality
❓ Ask questions: Get help with implementation or clarification
🔧 Submit PRs: Contribute code improvements or fixes