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.
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.
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
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.
npm install @autohandai/agent-sdkUse 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,
});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();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
});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"
}
}Create and start a high-level agent session.
const agent = await Agent.create({
cwd: '.',
instructions: 'Prefer Bun commands and typed SDK APIs.',
});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();Run a prompt to completion.
const result = await agent.run('Summarize release risk');
console.log(result.text);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[] },
});Parse a completed run result as JSON.
const run = await agent.send('Return {"ok": true}');
const data = await run.json<{ ok: boolean }>();Create a new SDK instance.
Start the CLI subprocess.
Stop the CLI subprocess.
Send a prompt to the agent.
await sdk.prompt({
message: 'Add a dark mode toggle',
context: {
files: ['src/settings.ts'],
},
thinkingLevel: 'normal',
});Send a prompt and stream events.
for await (const event of sdk.streamPrompt({ message: 'Hello' })) {
console.log(event);
}Abort the current operation.
Get the current agent state.
const state = await sdk.getState();
console.log(state.status); // 'idle' | 'processing' | 'waiting_permission'Get conversation messages.
const messages = await sdk.getMessages({ limit: 10 });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');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.');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');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();Subscribe to all events.
for await (const event of sdk.events()) {
console.log(event);
}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
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.
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',
});# 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 testThe 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
The RPC client implements JSON-RPC 2.0:
- Sends requests over stdin
- Parses responses from stdout
- Handles notifications
- Manages request/response correlation
The SDK API provides a high-level interface:
- Auto-start/stop management
- Event streaming
- Permission handling
- State management
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)
Apache License 2.0