Unofficial TypeScript SDK for Claude Code - the powerful CLI tool for interacting with Claude.
β¨ What's New in v0.3.3:
- π¬ Interactive streaming session with working visual typewriter effects
- π‘οΈ Advanced error handling with retry strategies and typed errors
- π Token streaming analysis with honest documentation about current behavior
- π§ Production-ready examples that actually work as advertised
Note: For the classic async generator API, see Classic API Documentation.
npm install @instantlyeasy/claude-code-sdk-ts
# or
yarn add @instantlyeasy/claude-code-sdk-ts
# or
pnpm add @instantlyeasy/claude-code-sdk-ts
Latest Version: v0.3.3
with enhanced features and working visual streaming!
Prerequisites:
- Node.js 18 or later
- Claude Code CLI installed (
npm install -g @anthropic-ai/claude-code
)
import { claude } from '@instantlyeasy/claude-code-sdk-ts';
// Simple query
const response = await claude()
.query('Say "Hello World!"')
.asText();
console.log(response); // "Hello World!"
This SDK delegates all authentication to the Claude CLI:
# One-time setup - login with your Claude account
claude login
The SDK does not handle authentication directly. If you see authentication errors, authenticate using the Claude CLI first.
Chain methods for clean, readable code:
const result = await claude()
.withModel('sonnet') // Choose model
.allowTools('Read', 'Write') // Configure permissions
.skipPermissions() // Auto-accept edits
.inDirectory('/path/to/project') // Set working directory
.query('Refactor this code') // Your prompt
.asText(); // Get response as text
Extract exactly what you need:
// Get plain text
const text = await claude()
.query('Explain this concept')
.asText();
// Parse JSON response
const data = await claude()
.query('Return a JSON array of files')
.asJSON<string[]>();
// Get the final result
const result = await claude()
.query('Complete this task')
.asResult();
// Analyze tool usage
const tools = await claude()
.allowTools('Read', 'Grep')
.query('Find all TODO comments')
.asToolExecutions();
for (const execution of tools) {
console.log(`${execution.tool}: ${execution.isError ? 'Failed' : 'Success'}`);
}
Fine-grained control over Claude's capabilities:
// Allow specific tools
await claude()
.allowTools('Read', 'Grep', 'LS')
.query('Analyze this codebase')
.asText();
// Deny dangerous tools
await claude()
.denyTools('Bash', 'Write')
.query('Review this code')
.asText();
// Read-only mode (no tools)
await claude()
.allowTools() // Empty = deny all
.query('Explain this architecture')
.asText();
Maintain conversation context across queries:
const session = claude()
.withModel('sonnet')
.skipPermissions();
// First query
const response1 = await session
.query('Pick a random number between 1 and 100')
.asText();
// Continue with context
const sessionId = await session.query('').getSessionId();
const response2 = await session
.withSessionId(sessionId)
.query('What number did you pick?')
.asText();
// Claude remembers the number!
Cancel long-running operations:
const controller = new AbortController();
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
try {
const response = await claude()
.withSignal(controller.signal)
.query('Long running task')
.asText();
} catch (error) {
if (error instanceof AbortError) {
console.log('Query was cancelled');
}
}
Built-in logging with multiple implementations:
import { ConsoleLogger, LogLevel } from '@instantlyeasy/claude-code-sdk-ts';
const logger = new ConsoleLogger(LogLevel.DEBUG);
const response = await claude()
.withLogger(logger)
.query('Debug this issue')
.asText();
// Also available: JSONLogger, MultiLogger, NullLogger
React to events during execution:
await claude()
.onMessage(msg => console.log('Message:', msg.type))
.onAssistant(msg => console.log('Claude:', msg))
.onToolUse(tool => console.log(`Using ${tool.name}...`))
.query('Perform analysis')
.stream(async (message) => {
// Handle streaming messages
});
The SDK automatically loads safe configuration from environment:
DEBUG
- Enable debug mode (values:true
,1
,yes
,on
)VERBOSE
- Enable verbose outputLOG_LEVEL
- Set log level (0-4)NODE_ENV
- Node environment
ANTHROPIC_API_KEY
for safety. This prevents accidental billing charges. See Environment Variables Documentation.
Enhanced error handling with categories and resolution hints:
import { isEnhancedError, hasResolution } from '@instantlyeasy/claude-code-sdk-ts';
try {
await claude().query('Task').asText();
} catch (error) {
if (isEnhancedError(error)) {
console.error(`${error.category} error: ${error.message}`);
if (hasResolution(error)) {
console.error('Try:', error.resolution);
}
}
}
Error categories include:
network
- Connection issuesauthentication
- Auth problemspermission
- Access deniedtimeout
- Operation timeoutsvalidation
- Invalid inputcli
- Claude CLI issuesconfiguration
- Config problems
Load settings and define reusable roles from YAML or JSON:
// Load configuration with roles
await claude()
.withConfigFile('./config/claude.yaml')
.withRole('developer', {
language: 'TypeScript',
framework: 'React'
})
.query('Generate component')
.asText();
Roles provide reusable configurations with:
- Model preferences
- Tool permissions
- Custom prompts with template variables
- Context settings (temperature, max tokens)
- Inheritance support
Example YAML config with roles:
version: "1.0"
globalSettings:
model: opus
timeout: 60000
# Define reusable roles
roles:
developer:
model: sonnet
tools:
allowed: [Read, Write, Edit]
denied: [Delete]
prompts:
prefix: "You are an expert ${language} developer using ${framework}."
senior-developer:
extends: developer # Inherit from developer role
model: opus
permissions:
mode: acceptEdits
tools:
allowed: [TodoRead, TodoWrite] # Additional tools
// Using roles with template variables
const response = await claude()
.withRolesFile('./roles.yaml')
.withRole('senior-developer', {
language: 'TypeScript',
framework: 'Next.js',
specialty: 'performance optimization'
})
.query('Optimize this React component')
.asText();
See Roles Documentation for complete details.
const parser = await claude()
.query('Complex task')
.getParser();
const usage = await parser.getUsage();
console.log('Tokens:', usage.totalTokens);
console.log('Cost: $', usage.totalCost);
await claude()
.query('Tell me a story')
.stream(async (message) => {
if (message.type === 'assistant') {
// Stream complete messages (not individual tokens)
console.log(message.content[0].text);
}
});
const response = await claude()
.withModel('claude-3-opus-20240229')
.withTimeout(30000)
.query('Complex analysis')
.asText();
Create typewriter effects and real-time response display:
import { claude, createTokenStream } from '@instantlyeasy/claude-code-sdk-ts';
// Collect response for controlled display
const messageGenerator = claude()
.withModel('sonnet')
.queryRaw('Write a story about AI');
const tokenStream = createTokenStream(messageGenerator);
const allTokens = [];
for await (const chunk of tokenStream.tokens()) {
allTokens.push(chunk.token);
}
// Display with typewriter effect
const fullText = allTokens.join('');
for (const char of fullText) {
process.stdout.write(char);
await new Promise(resolve => setTimeout(resolve, 30));
}
Handle specific error types with smart retry logic:
import { claude, detectErrorType, withRetry } from '@instantlyeasy/claude-code-sdk-ts';
try {
const result = await withRetry(
async () => claude().query('Complex task').asText(),
{
maxAttempts: 3,
strategy: 'exponential',
shouldRetry: (error) => {
const errorType = detectErrorType(error.message);
return ['network_error', 'timeout_error'].includes(errorType);
}
}
);
} catch (error) {
const errorType = detectErrorType(error.message);
console.log(`Failed with error type: ${errorType}`);
}
NEW! Complete chat interface with visual streaming:
# Try the interactive streaming example
node examples/fluent-api/new-features/interactive-streaming.js
Features working character-by-character display, conversation history, speed control, and model switching!
Comprehensive examples are available in the examples directory:
- fluent-api-demo.js - Complete fluent API showcase
- sessions.js - Session management patterns
- yaml-config-demo.js - Configuration examples
Advanced Features (new-features directory)
- interactive-streaming.js - π¬ Interactive chat with visual streaming
- token-streaming.js - Working typewriter effects
- error-handling.js - Advanced error patterns
- retry-strategies.js - Multiple retry strategies
- File Operations - Reading, writing, and analyzing code
- Web Research - Using Claude's web capabilities
- Interactive Sessions - Building conversational interfaces
The SDK maintains full backward compatibility. The classic query()
function still works:
import { query } from '@instantlyeasy/claude-code-sdk-ts';
for await (const message of query('Hello')) {
// Classic async generator API
}
However, we recommend the fluent API for new projects. See Migration Guide.
Creates a new query builder:
claude()
.withModel(model: string)
.allowTools(...tools: ToolName[])
.denyTools(...tools: ToolName[])
.skipPermissions()
.withTimeout(ms: number)
.inDirectory(path: string)
.withSessionId(id: string)
.withSignal(signal: AbortSignal)
.withLogger(logger: Logger)
.withConfigFile(path: string)
.withRole(name: string, vars?: Record<string, string>)
.onMessage(handler: (msg: Message) => void)
.onAssistant(handler: (msg: AssistantMessage) => void)
.onToolUse(handler: (tool: ToolUseBlock) => void)
.query(prompt: string): ResponseParser
asText()
- Extract plain textasJSON<T>()
- Parse JSON responseasResult()
- Get final result messageasToolExecutions()
- Get tool execution detailsfindToolResults(name)
- Find specific tool resultsgetUsage()
- Get token usage statsgetSessionId()
- Get session IDstream(callback)
- Stream messages
See TypeScript definitions for complete type information.
See CHANGELOG.md for version history.
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
MIT Β© Daniel King & Claude