Claude Skills Guide

Claude Code API Client TypeScript Guide

Building a TypeScript client for interacting with Claude Code opens up powerful automation possibilities. Whether you’re integrating Claude into your CI/CD pipeline, building a custom dashboard, or composing multiple skills programmatically, understanding the API client patterns in TypeScript will accelerate your development workflow.

Setting Up Your TypeScript Project

Before diving into API interactions, set up a TypeScript project with proper dependencies. You’ll need the Anthropic SDK and type definitions:

npm init -y
npm install @anthropic-ai/sdk typescript @types/node
npx tsc --init

Create a client configuration file that handles authentication and base settings:

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
  maxRetries: 3,
  timeout: 60000,
});

export default client;

This basic setup gives you access to the Claude Messages API, which serves as the foundation for all skill interactions.

Working with Claude Skills in TypeScript

Claude skills extend the base API with specialized prompts and tool configurations. When building a TypeScript client, you can invoke skills directly or compose multiple skills for complex workflows.

Invoking a Single Skill

The Messages API accepts a system parameter where you can inject skill content:

async function invokeSkill(skillContent: string, userMessage: string) {
  const response = await client.messages.create({
    model: 'claude-sonnet-4-20250514',
    max_tokens: 4096,
    system: skillContent,
    messages: [{ role: 'user', content: userMessage }],
  });

  return response.content[0].type === 'text' 
    ? response.content[0].text 
    : null;
}

This pattern works well for skills like the pdf skill when you need to process documents programmatically, or the tdd skill for generating test suites from your TypeScript code.

Composing Multiple Skills

For more complex workflows, chain multiple skill invocations:

async function composeWorkflow(skills: string[], input: string) {
  let currentInput = input;
  
  for (const skill of skills) {
    const result = await invokeSkill(skill, currentInput);
    currentInput = result || currentInput;
  }
  
  return currentInput;
}

This approach shines when combining the frontend-design skill for UI generation with the pdf skill for documentation, or using supermemory to retrieve context before processing.

Authentication and Environment Configuration

Production implementations require secure authentication handling. Never hardcode API keys in your source code. Instead, use environment variables with validation:

import { z } from 'zod';

const envSchema = z.object({
  ANTHROPIC_API_KEY: z.string().min(1),
  CLAUDE_MODEL: z.enum(['claude-sonnet-4-20250514', 'claude-opus-4-20250514']).default('claude-sonnet-4-20250514'),
  MAX_TOKENS: z.number().default(4096),
});

function loadConfig() {
  const result = envSchema.safeParse(process.env);
  
  if (!result.success) {
    throw new Error(`Environment validation failed: ${result.error.format()}`);
  }
  
  return result.data;
}

export const config = loadConfig();

This validation prevents runtime errors from missing configuration and provides clear error messages during development.

Handling Tool Calls and Responses

Claude skills often involve tool use. Your TypeScript client needs to handle the message deltas that include tool invocations:

interface ToolResult {
  type: 'tool_use';
  id: string;
  name: string;
  input: Record<string, unknown>;
}

async function executeWithTools(
  systemPrompt: string,
  userMessage: string,
  availableTools: any[]
) {
  const stream = await client.messages.stream({
    model: config.CLAUDE_MODEL,
    max_tokens: config.MAX_TOKENS,
    system: systemPrompt,
    messages: [{ role: 'user', content: userMessage }],
    tools: availableTools,
  });

  let fullResponse = '';
  
  for await (const chunk of stream) {
    if (chunk.type === 'content_block_delta') {
      fullResponse += chunk.delta.text;
    }
  }

  return fullResponse;
}

The mcp-builder skill provides excellent patterns for creating custom MCP servers that your TypeScript client can interact with, extending Claude’s capabilities beyond built-in tools.

Error Handling and Retry Logic

Network failures and rate limits require solid error handling. Implement exponential backoff for reliability:

async function withRetry<T>(
  fn: () => Promise<T>,
  maxRetries: number = 3
): Promise<T> {
  let lastError: Error | null = null;
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error as Error;
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
  
  throw lastError;
}

This retry logic handles transient failures gracefully, which is essential when integrating with Claude’s API in production environments.

Type-Safe Skill Definitions

Use TypeScript’s type system to create type-safe skill definitions:

interface SkillDefinition<TInput, TOutput> {
  name: string;
  systemPrompt: string;
  parseOutput: (raw: string) => TOutput;
  transformInput: (input: TInput) => string;
}

const tddSkill: SkillDefinition<string, string[]> = {
  name: 'tdd',
  systemPrompt: 'Generate unit tests following TDD principles...',
  parseOutput: (raw) => raw.split('\n').filter(line => line.includes('describe(')),
  transformInput: (code) => `Generate tests for:\n${code}`,
};

async function runTdd(input: string): Promise<string[]> {
  const prompt = tddSkill.transformInput(input);
  const raw = await invokeSkill(tddSkill.systemPrompt, prompt);
  return tddSkill.parseOutput(raw || '');
}

This pattern ensures type safety across your skill invocations and makes refactoring straightforward when skill prompts change.

Real-World Integration Example

Putting it all together, here’s a practical workflow that uses multiple skills:

async function processProjectDocumentation(projectPath: string) {
  const fs = await import('fs/promises');
  const code = await fs.readFile(projectPath, 'utf-8');
  
  // Use tdd skill to generate tests
  const tests = await invokeSkill(tddSkillPrompt, code);
  
  // Use pdf skill to generate documentation
  const docs = await invokeSkill(pdfSkillPrompt, tests);
  
  // Use supermemory to store results
  await storeInMemory('project-docs', { tests, docs });
  
  return { tests, docs };
}

This workflow demonstrates how TypeScript clients can orchestrate multiple Claude skills for comprehensive project automation.

Building a TypeScript API client for Claude Code gives you programmatic control over AI-powered workflows. The patterns covered here—authentication, skill composition, tool handling, and error recovery—provide a solid foundation for both simple integrations and complex production systems.


Built by theluckystrike — More at zovo.one