Code Agent SDK for TypeScript
May 7, 2026 · View on GitHub
Autohand Code Agent SDK - CLI wrapper implementation for TypeScript.
Beta: this SDK is actively evolving while the Agent SDK APIs stabilize. Pin versions in production and review release notes before upgrading.
Overview
This SDK provides a TypeScript wrapper around the Autohand CLI binary, enabling programmatic access to Autohand's autonomous coding agent capabilities via JSON-RPC 2.0 protocol.
Architecture
User → TypeScript SDK (thin wrapper) → CLI Subprocess (existing binary) → Provider → HTTP
The SDK:
- Spawns the Autohand CLI as a subprocess
- Communicates via JSON-RPC 2.0 over stdin/stdout
- Provides an idiomatic TypeScript API
- Supports streaming events
Other Programming Languages (Beta)
The Agent SDK is available in multiple beta language packages. Use the same CLI-backed SDK model from another programming language:
- TypeScript - this package, with
Agent,Run, streaming, and JSON helpers. - Go - idiomatic Go package with
context.Context, typed events, and channel-based streaming. - Python - async Python package with
async forevent streams and typed Pydantic models. - Java - Java 21 records, sealed events, and virtual-thread-ready APIs.
- Swift - SwiftPM package with
Agent,Runner, async streams, tools, hooks, and permissions.
Installation
npm install @autohandai/agent-sdk
Quick Start
High-Level API
Use Agent for application code. It gives you an explicit run lifecycle while
keeping CLI subprocess and JSON-RPC details out of your app.
import { Agent } from '@autohandai/agent-sdk';
const agent = await Agent.create({
cwd: '.', // Optional: defaults to process.cwd()
instructions: 'Review code with Staff-level TypeScript judgement.',
permissionMode: 'interactive',
});
const run = await agent.send('Review this repository for release readiness');
for await (const event of run.stream()) {
if (event.type === 'message_update') {
process.stdout.write(event.delta);
}
}
const result = await run.wait();
console.log(result.text);
await agent.close();
For simple one-shot tasks:
const result = await agent.run('Summarize the API surface');
For JSON output:
type ReleaseRisk = {
summary: string;
risks: Array<{ title: string; severity: 'low' | 'medium' | 'high' }>;
};
const risk = await agent.runJson<ReleaseRisk>('Assess publish readiness', {
schemaName: 'ReleaseRisk',
schema: {
summary: 'string',
risks: [{ title: 'string', severity: 'low | medium | high' }],
},
validate: (value) => value as ReleaseRisk,
});
Low-Level API
import { AutohandSDK } from '@autohandai/agent-sdk';
const sdk = new AutohandSDK({
cwd: '.', // Optional: defaults to process.cwd()
debug: true,
});
await sdk.start();
// Send a prompt
await sdk.prompt({
message: 'Hello, Autohand!',
});
// Stream events
for await (const event of sdk.streamPrompt({
message: 'Analyze the codebase',
})) {
console.log(event);
}
await sdk.stop();
Configuration
SDK Configuration
const sdk = new AutohandSDK({
cwd: '.', // Working directory. Omit to use process.cwd()
cliPath: '/path/to/cli', // Optional: custom CLI path
debug: true, // Enable debug logging
timeout: 30000, // Request timeout in ms
});
CLI Configuration
The SDK uses the CLI's configuration file (~/.autohand/config.json). You can configure providers there:
{
"provider": "openrouter",
"openrouter": {
"apiKey": "sk-or-...",
"model": "openrouter/auto"
}
}
API Reference
AutohandSDK
Agent.create(options: AgentOptions): Promise<Agent>
Create and start a high-level agent session.
const agent = await Agent.create({
cwd: '.',
instructions: 'Prefer Bun commands and typed SDK APIs.',
});
agent.send(input, options?): Promise<Run>
Create a run without waiting for it to finish.
const run = await agent.send('Add tests for permission decisions');
for await (const event of run.stream()) {
console.log(event.type);
}
const result = await run.wait();
agent.run(input, options?): Promise<RunResult>
Run a prompt to completion.
const result = await agent.run('Summarize release risk');
console.log(result.text);
agent.runJson<T>(input, options?): Promise<T>
Ask the agent for JSON, parse the final response, and optionally validate it.
Pass schema.parse from Zod or any (value: unknown) => T validator.
const result = await agent.runJson<{ files: string[] }>('List changed files', {
schema: { files: ['string'] },
validate: (value) => value as { files: string[] },
});
run.json<T>(options?): Promise<T>
Parse a completed run result as JSON.
const run = await agent.send('Return {"ok": true}');
const data = await run.json<{ ok: boolean }>();
constructor(config: SDKConfig)
Create a new SDK instance.
start(): Promise<void>
Start the CLI subprocess.
stop(): Promise<void>
Stop the CLI subprocess.
prompt(params: PromptParams): Promise<void>
Send a prompt to the agent.
await sdk.prompt({
message: 'Add a dark mode toggle',
context: {
files: ['src/settings.ts'],
},
thinkingLevel: 'normal',
});
streamPrompt(params: PromptParams): AsyncGenerator<SDKEvent>
Send a prompt and stream events.
for await (const event of sdk.streamPrompt({ message: 'Hello' })) {
console.log(event);
}
abort(): Promise<void>
Abort the current operation.
getState(): Promise<GetStateResult>
Get the current agent state.
const state = await sdk.getState();
console.log(state.status); // 'idle' | 'processing' | 'waiting_permission'
getMessages(params?: GetMessagesParams): Promise<GetMessagesResult>
Get conversation messages.
const messages = await sdk.getMessages({ limit: 10 });
setSystemPrompt(promptOrPath: string): AutohandSDK
Replace the entire CLI system prompt before the session starts. The value can be
inline text or a file path, matching autohand --sys-prompt.
const sdk = new AutohandSDK({ cwd: '.' })
.setSystemPrompt('./SYSTEM_PROMPT.md');
appendSystemPrompt(promptOrPath: string): AutohandSDK
Append instructions to the default CLI system prompt before the session starts. This is the recommended option for most SDK integrations.
const sdk = new AutohandSDK()
.appendSystemPrompt('Always run Bun checks before summarizing release readiness.');
permissionResponse(params: PermissionResponseParams): Promise<void>
Respond to a permission request.
await sdk.permissionResponse({
requestId: 'req-123',
decision: 'allow_session',
});
Prefer the ergonomic helpers for application code:
await sdk.allowPermission('req-123', 'session');
await sdk.denyPermission('req-456', 'once');
await sdk.suggestPermissionAlternative('req-789', 'Run bun run typecheck first');
setPlanMode(enabled: boolean): Promise<void>
Enable or disable CLI-3 plan mode. Plan mode is separate from permission mode: it restricts the agent to read-only planning tools until the host disables plan mode or the plan is accepted by the CLI flow.
const sdk = new AutohandSDK({ planMode: true });
await sdk.start();
await sdk.disablePlanMode();
await sdk.enablePlanMode();
events(): AsyncGenerator<SDKEvent>
Subscribe to all events.
for await (const event of sdk.events()) {
console.log(event);
}
Event Types
The SDK emits the following events:
agent_start- Agent started a sessionagent_end- Agent ended a sessionturn_start- Turn startedturn_end- Turn endedmessage_start- Message generation startedmessage_update- Message content update (streaming)message_end- Message generation endedtool_start- Tool execution startedtool_update- Tool output update (streaming)tool_end- Tool execution endedpermission_request- Permission request from agenterror- Error occurred
Examples
See the examples/ directory for more examples:
basic-usage.ts- Basic prompt usagestreaming.ts- Streaming eventspermission-handling.ts- Handling permission requests20-sdlc-discovery-plan.ts- Read-only SDLC discovery and planning21-sdlc-gated-implementation.ts- Plan first, execute after an explicit gate22-sdlc-release-readiness.ts- Release-readiness checks with event streaming23-system-prompts.ts- Replacing or appending the CLI system prompt24-high-level-agent.ts- Recommended Agent/Run API25-structured-json.ts- JSON output with optional validation
See also SDLC workflows.
CLI Binaries
The SDK includes CLI binaries for all platforms:
autohand-macos-arm64(65MB)autohand-macos-x64(70MB)autohand-linux-arm64(101MB)autohand-linux-x64(108MB)autohand-windows-x64.exe(123MB)
The SDK automatically detects the correct binary for your platform. You can also specify a custom path:
const sdk = new AutohandSDK({
cliPath: '/path/to/custom/autohand',
});
Development
# Install dependencies
npm install
# Build
npm run build
# Watch mode
npm run dev
# Type check
npm run typecheck
# Lint
npm run lint
# Test
npm run test
Architecture Details
Transport Layer
The transport layer handles subprocess spawning and stdin/stdout communication:
- Spawns CLI with
--mode rpc - Uses line reader for JSONL protocol
- Manages process lifecycle
- Handles errors and cleanup
RPC Client
The RPC client implements JSON-RPC 2.0:
- Sends requests over stdin
- Parses responses from stdout
- Handles notifications
- Manages request/response correlation
SDK API
The SDK API provides a high-level interface:
- Auto-start/stop management
- Event streaming
- Permission handling
- State management
Comparison with Library SDK
This is a CLI wrapper implementation. The previous library SDK (@autohandai/agent-sdk-typescript) was a direct library implementation with in-process provider integration.
Key differences:
- CLI wrapper: Spawns CLI subprocess, uses JSON-RPC
- Library: Direct provider integration, in-process
Trade-offs:
- ✅ Full CLI feature set
- ✅ Consistent with CLI behavior
- ✅ Single source of truth
- ❌ Larger package size (65-120MB)
- ❌ Subprocess overhead (~50-200ms)
License
Apache License 2.0