Amp SDK
The Amp SDK allows you to programmatically use the Amp agent in your TypeScript or Python programs.
Why use the Amp SDK?
The Amp SDK offers the following functionality:
- Stream Inputs: Send messages one-by-one to the Amp agent
- Stream Outputs: Receive structured JSON responses (system, assistant, result) while the agent runs
- Multi-turn Conversations: Maintain back-and-forth interactions across multiple inference calls
- Thread Continuity: Continue an existing thread (latest or by ID) to build stateful agent workflows
- Programmatic Settings: Configure working directories, settings, and tools without user prompts — ideal for automation
- MCP Integration: specify which MCP servers are available for a given session
- Custom Skills: Define and use custom agent skills to extend Amp’s functionality
What can you build?
Here are some examples of what you can build with the Amp SDK:
Development Tools
- Code Review Agent: Automated pull request analysis and feedback
- Documentation Generator: Create and maintain project documentation
- Test Automation: Generate and execute test suites
- Migration Assistant: Help upgrade codebases and refactor legacy code
Workflow Automation
- CI/CD Integration: Smart build and deployment pipelines
- Issue Triage: Automatically categorize and prioritize bug reports
- Code Quality Monitoring: Continuous analysis of code health metrics
- Release Management: Automated changelog generation and version bumping
Quick Start
Installation
# Install the Amp SDK using npm
npm install @ampcode/sdk
# or yarn
yarn add @ampcode/sdk
# Install or upgrade the Amp CLI used by the SDK (optional if a compatible version is already installed)
npx -y @ampcode/sdk installFor SDK users who need to use Amp before Amp Neo, install the legacy release @ampcode/sdk@0.1.0-20260528044221-ge0e19fa:
npm install @ampcode/sdk@0.1.0-20260528044221-ge0e19faFor TypeScript SDK users, Amp CLI must be at least the version pinned by the installed SDK release. If your organization already installs Amp CLI through Homebrew, Artifactory, or another internal channel, you can keep using it as long as its version is new enough.
Once installed, add your access token to the environment. You can access your access token in Security Settings.
export AMP_API_KEY=sgamp_your_access_token_here If you already have the Amp CLI installed locally, you can log in using the following command amp login.
Run Your First Amp Command
Now that you have the SDK installed and your access token set up, you can start using Amp with the execute() function:
import { execute } from '@ampcode/sdk'
// Simple execution - get the final result
for await (const message of execute({ prompt: 'What files are in this directory?' })) {
if (message.type === 'result' && !message.is_error) {
console.log('Result:', message.result)
break
}
}The execute() function only requires that you provide a prompt to get started. The SDK streams messages as the agent works, letting you handle responses and integrate them directly into your application.
Core Concepts
Message Streaming
The SDK streams different types of messages as your agent executes:
for await (const message of execute({ prompt: 'Run tests' })) {
if (message.type === 'system') {
// Session info, available tools, MCP servers
console.log('Available tools:', message.tools)
} else if (message.type === 'assistant') {
// AI responses and tool usage
console.log('Assistant is working...')
} else if (message.type === 'result') {
console.log(message.is_error ? `Failed: ${message.error}` : `Done: ${message.result}`)
}
}Simple Result Extraction
When you just need the final result without handling streaming:
async function getResult(prompt: string): Promise<string> {
for await (const message of execute({ prompt, options: {} })) {
if (message.type === 'result') {
if (message.is_error) {
throw new Error(message.error)
}
return message.result
}
}
throw new Error('No result received')
}
// Usage
try {
const result = await getResult('List all TypeScript files in this project')
console.log('Found files:', result)
} catch (error) {
console.error('Failed:', error instanceof Error ? error.message : String(error))
}Thread Continuity
Continue conversations across multiple interactions:
// Continue the most recent conversation
for await (const message of execute({
prompt: 'What was the last error you found?',
options: { continue: true },
})) {
if (message.type === 'result' && !message.is_error) {
console.log(message.result)
}
}
// Continue a specific thread by ID
for await (const message of execute({
prompt: 'Can you update that code we discussed?',
options: { continue: 'T-abc123-def456' },
})) {
if (message.type === 'result' && !message.is_error) {
console.log(message.result)
}
}Common Configuration
Working Directory
Specify where Amp should run:
for await (const message of execute({
prompt: 'Refactor the auth module',
options: { cwd: './my-project' },
})) {
// Process messages...
}Enable Debug Logging
See what’s happening under the hood:
for await (const message of execute({
prompt: 'Analyze this project',
options: {
logLevel: 'debug', // Shows CLI command in console
logFile: './amp-debug.log', // Optional: write logs to file
},
})) {
// Process messages
}Agent Mode
Select which agent mode to use. The mode controls the model, system prompt, and tool selection:
for await (const message of execute({
prompt: 'Quickly fix this typo',
options: {
mode: 'low', // Use low mode for faster responses
},
})) {
// Process messages
}Available modes:
low: Fast, low-cost mode for small, well-defined tasksmedium(default): Balances quality, speed, and cost for most taskshigh: Deep reasoning for difficult tasks that can tolerate more time and costultra: For the hardest open-ended tasks, when maximum capability matters more than speed or cost
Reasoning Effort
Set model reasoning effort for supported modes:
for await (const message of execute({
prompt: 'Think carefully and explain your plan before coding.',
options: {
mode: 'medium',
effort: 'high',
},
})) {
if (message.type === 'result' && !message.is_error) {
console.log(message.result)
break
}
}Available effort levels:
noneminimallowmediumhighxhighmax
Thread Labels
Add labels to threads created by execute():
for await (const message of execute({
prompt: 'Summarize this repo',
options: {
labels: ['sdk', 'summary'],
},
})) {
if (message.type === 'result' && !message.is_error) {
console.log(message.result)
break
}
}Thread Titles
Set the title when you create a thread. You cannot use title when continuing a thread.
for await (const message of execute({
prompt: 'Review pull request 42',
options: {
executor: 'orb',
title: 'Review acme/widgets#42',
},
})) {
if (message.type === 'result' && !message.is_error) {
console.log(message.result)
break
}
}Thread Visibility
Control who can see threads created by execute():
for await (const message of execute({
prompt: 'Analyze this private codebase',
options: {
visibility: 'private', // Visible only to you (and workspace admins if you're in a workspace)
},
})) {
if (message.type === 'result' && !message.is_error) {
console.log(message.result)
break
}
}Available visibility levels:
workspace(default): Visible to all workspace membersprivate: Visible only to you (and workspace admins if you’re in a workspace)unlisted: Visible to anyone with the linkgroup: Visible to members of your user group (Enterprise)
Tool Permissions
Use a custom plugin to control tool use. Workspace admins can distribute it as a global workspace plugin.
Advanced Usage
Interactive Progress Tracking
For building user interfaces that show real-time progress:
async function executeWithProgress(prompt: string) {
console.log('Starting task...')
for await (const message of execute({ prompt })) {
if (message.type === 'system' && message.subtype === 'init') {
console.log('Tools available:', message.tools.join(', '))
} else if (message.type === 'assistant') {
// Show tool usage or assistant responses
for (const content of message.message.content) {
if (content.type === 'tool_use') {
console.log(`Using ${content.name}...`)
} else if (content.type === 'text') {
console.log('Assistant:', content.text.slice(0, 100) + '...')
}
}
} else if (message.type === 'result') {
if (message.is_error) {
console.log('Failed:', message.error)
} else {
console.log('Completed successfully!')
console.log(message.result)
}
}
}
}Cancellation and Timeouts
Handle long-running operations gracefully:
async function executeWithTimeout(prompt: string, timeoutMs = 30000) {
const signal = AbortSignal.timeout(timeoutMs)
try {
for await (const message of execute({
prompt,
signal,
options: {},
})) {
if (message.type === 'result') {
if (message.is_error) {
throw new Error(message.error)
}
return message.result
}
}
} catch (error) {
if (signal.aborted) {
throw new Error(`Operation timed out after ${timeoutMs}ms`)
}
throw error
}
}MCP Integration
Extend Amp’s capabilities with custom tools and data sources:
import { execute, type MCPConfig } from '@ampcode/sdk'
const mcpConfig: MCPConfig = {
playwright: {
command: 'npx',
args: ['-y', '@playwright/mcp@latest', '--headless'],
env: { NODE_ENV: 'production' },
},
database: {
command: 'node',
args: ['./custom-mcp-server.js'],
// ${VAR} placeholders are expanded from Amp's environment at server startup
env: { DB_CONNECTION_STRING: '${DATABASE_URL}' },
},
}
for await (const message of execute({
prompt: 'Test the login flow on staging environment',
options: { mcpConfig },
})) {
if (message.type === 'system') {
console.log(
'MCP Servers:',
message.mcp_servers.map((s) => `${s.name}: ${s.status}`),
)
}
// Handle other messages...
}To learn more about extending Amp with MCP servers, see MCP.
Multi-turn Conversations
Build streaming conversations using async generators:
import { execute, createUserMessage } from '@ampcode/sdk'
async function* generateMessages() {
yield createUserMessage('Start analyzing the codebase')
// Wait for some condition or user input
await new Promise((resolve) => setTimeout(resolve, 1000))
yield createUserMessage('Now focus on the authentication module')
}
for await (const message of execute({
prompt: generateMessages(),
})) {
if (message.type === 'result' && !message.is_error) {
console.log(message.result)
}
}Settings File Configuration
Configure Amp’s behavior with a settings file, like the settings.json. You can provide Amp with a custom settings file you have saved in your project:
import { execute } from '@ampcode/sdk'
// Use a custom settings file
for await (const message of execute({
prompt: 'Deploy the application',
options: {
settingsFile: './settings.json',
logLevel: 'debug',
},
})) {
// Handle messages...
}Example settings.json:
{
"amp.mcpServers": {
"playwright": {
"command": "npx",
"args": ["-y", "@playwright/mcp@latest", "--headless", "--isolated"]
}
},
"amp.tools.disable": ["web_search", "mcp__playwright__browser_resize"]
} To find all available settings, see Configuration.
Custom Skills
Load custom skills from a specified directory:
for await (const message of execute({
prompt: 'Use my custom deployment skill',
options: {
skills: './my-skills', // Path to custom skills directory
},
})) {
// Process messages
}To learn more about creating custom skills, see Skills.