Fluent, chainable TypeScript SDK: configure models, enable tools, stream events, then fetch text, JSON, run details or token stats in one call via .asText() or .allowTools('Read', 'Write'). Multi-level logging plus live onMessage/onToolUse callbacks give deep, CLI-compatible observability.
# Add to your Claude Code skills
git clone https://github.com/instantlyeasy/claude-code-sdk-tsUnofficial TypeScript SDK for Claude Code - the powerful CLI tool for interacting with Claude.
β¨ What's New in v0.3.3:
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:
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β οΈ Important: API keys are NOT automatically loaded from 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 problemsLoad 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:
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.mess
No comments yet. Be the first to share your thoughts!