Documentation Index Fetch the complete documentation index at: https://docs.agentmark.co/llms.txt
Use this file to discover all available pages before exploring further.
The Claude Agent SDK adapter lets you run AgentMark prompts as agentic tasks using Anthropic’s Claude Agent SDK — tool use, budget controls, and tracing. Available for both TypeScript and Python.
Installation
npm install @agentmark-ai/claude-agent-sdk-v0-adapter @anthropic-ai/claude-agent-sdk
pip install agentmark-claude-agent-sdk-v0 agentmark-prompt-core claude-agent-sdk
Setup
Create your AgentMark client with a ClaudeAgentModelRegistry. The registry creator is a function that receives the model name and returns a ModelConfig. Use createDefault() for a pass-through registry, or register models explicitly if you need per-model options like maxThinkingTokens: import { createAgentMarkClient , ClaudeAgentModelRegistry } from "@agentmark-ai/claude-agent-sdk-v0-adapter" ;
// Option 1: pass-through registry
const modelRegistry = ClaudeAgentModelRegistry . createDefault ();
// Option 2: explicit registration with per-model config
const modelRegistry = new ClaudeAgentModelRegistry ()
. registerModels ([ "claude-sonnet-4-20250514" ], ( name ) => ({ model: name }))
. registerModels ([ "claude-opus-4-20250514" ], ( name ) => ({
model: name ,
maxThinkingTokens: 10000 ,
}));
export const client = createAgentMarkClient ({
loader ,
modelRegistry ,
});
The Python adapter does not ship a create_default() / .createDefault() — register models explicitly. Use ModelConfig for per-model options: from pathlib import Path
from dotenv import load_dotenv
from agentmark.prompt_core import FileLoader
from agentmark_claude_agent_sdk_v0 import (
create_claude_agent_client,
ClaudeAgentModelRegistry,
ClaudeAgentAdapterOptions,
ModelConfig,
)
load_dotenv()
model_registry = ClaudeAgentModelRegistry()
model_registry.register_models(
[ "claude-sonnet-4-20250514" ],
lambda name , _ : ModelConfig( model = name),
)
model_registry.register_models(
[ "claude-opus-4-20250514" ],
lambda name , _ : ModelConfig( model = name, max_thinking_tokens = 10000 ),
)
loader = FileLoader( str (Path( __file__ ).parent / "dist" / "agentmark" ))
client = create_claude_agent_client(
model_registry = model_registry,
loader = loader,
)
Running prompts
The adapter returns { query: { prompt, options }, messages, telemetry }. Pass adapted.query directly to query() from @anthropic-ai/claude-agent-sdk:
import { client } from "./agentmark.client" ;
import { query } from "@anthropic-ai/claude-agent-sdk" ;
const prompt = await client . loadTextPrompt ( "task.prompt.mdx" );
const adapted = await prompt . format ({
props: { task: "Analyze the auth module and suggest improvements" },
});
for await ( const message of query ( adapted . query )) {
console . log ( message );
}
Use traced_query — run_text_prompt / run_object_prompt are Pydantic AI symbols and are not exported by the Claude adapter: import asyncio
from agentmark_claude_agent_sdk_v0 import traced_query
from agentmark_client import client
async def main ():
prompt = await client.load_text_prompt( "code-reviewer.prompt.mdx" )
adapted = await prompt.format( props = {
"task" : "Analyze the auth module and suggest improvements"
})
async for message in traced_query(adapted):
print (message)
asyncio.run(main())
Adapter options
Adapter options are configured at client construction time (via createAgentMarkClient), not inside prompt.format(). prompt.format() silently ignores them:
export const client = createAgentMarkClient ({
loader ,
modelRegistry ,
adapterOptions: {
permissionMode: "bypassPermissions" ,
maxTurns: 10 ,
cwd: "/path/to/project" ,
maxBudgetUsd: 5.00 ,
allowedTools: [ "Read" , "Write" , "Bash" ],
disallowedTools: [ "WebFetch" ],
systemPromptPreset: false ,
onWarning : ( warning ) => {
console . warn ( "Agent warning:" , warning );
},
},
});
from agentmark_claude_agent_sdk_v0 import (
create_claude_agent_client,
ClaudeAgentAdapterOptions,
)
client = create_claude_agent_client(
model_registry = model_registry,
loader = loader,
adapter_options = ClaudeAgentAdapterOptions(
permission_mode = "bypassPermissions" ,
max_turns = 10 ,
cwd = "/path/to/project" ,
max_budget_usd = 5.00 ,
allowed_tools = [ "Read" , "Write" , "Bash" ],
disallowed_tools = [ "WebFetch" ],
system_prompt_preset = False ,
on_warning = lambda w : print ( f "Warning: { w } " ),
),
)
Option TypeScript Python Type / values Permission mode permissionModepermission_mode'default' | 'acceptEdits' | 'bypassPermissions' | 'plan'Max turns maxTurnsmax_turnsnumberWorking directory cwdcwdstringBudget limit maxBudgetUsdmax_budget_usdnumber (USD)Allowed tools allowedToolsallowed_toolsstring[] — whitelistDisallowed tools disallowedToolsdisallowed_toolsstring[] — blacklistSystem prompt preset systemPromptPresetsystem_prompt_presetboolean (use Claude Code’s built-in)Warning handler onWarningon_warning(message: string) => void
Object generation
For structured output, use object prompts:
import { client } from "./agentmark.client" ;
import { query } from "@anthropic-ai/claude-agent-sdk" ;
const prompt = await client . loadObjectPrompt ( "extract.prompt.mdx" );
const adapted = await prompt . format ({
props: { text: "This product is amazing!" },
});
for await ( const message of query ( adapted . query )) {
if ( message . type === "result" && message . subtype === "success" ) {
console . log ( message . result );
}
}
from agentmark_claude_agent_sdk_v0 import traced_query
from agentmark_client import client
prompt = await client.load_object_prompt( "sentiment.prompt.mdx" )
adapted = await prompt.format( props = { "text" : "This product is amazing!" })
async for message in traced_query(adapted):
if message.type == "result" :
print (message.result)
Tools
The Claude Agent SDK adapter handles tools differently from the AI SDK adapter . Instead of registering custom tool executors, you list tool names in your prompt frontmatter. The adapter passes these names through as allowedTools to the Claude Agent SDK.
Tools can be any of the SDK’s built-in tools (Read, Write, Bash, etc.) or tools provided by MCP servers. Configure MCP servers on the client:
import { createAgentMarkClient , ClaudeAgentModelRegistry } from "@agentmark-ai/claude-agent-sdk-v0-adapter" ;
export const client = createAgentMarkClient ({
loader ,
modelRegistry ,
mcpServers: {
weather: { url: "https://weather-mcp.example.com/sse" },
},
});
The TypeScript field is mcpServers (camelCase). The Python adapter uses mcp_servers (snake_case). client = create_claude_agent_client(
model_registry = model_registry,
mcp_servers = { "weather" : { "url" : "https://weather-mcp.example.com/sse" }},
loader = loader,
)
Then reference tools by name in your prompts:
---
name : task
text_config :
model_name : claude-sonnet-4-20250514
tools :
- weather
---
< System > You are a helpful assistant with access to weather data. </ System >
< User > { props . task } </ User >
Evals
Register evaluation functions for scoring prompt outputs during experiments. Score schemas are defined separately in agentmark.json — eval functions are connected to scores by name.
import type { EvalFunction } from "@agentmark-ai/prompt-core" ;
const evals : Record < string , EvalFunction > = {
exact_match : ({ output , expectedOutput }) => ({
passed: output === expectedOutput ,
score: output === expectedOutput ? 1 : 0 ,
}),
};
export const client = createAgentMarkClient ({
loader ,
modelRegistry ,
evals ,
});
from agentmark.prompt_core import EvalParams, EvalResult
def exact_match ( params : EvalParams) -> EvalResult:
match = str (params[ "output" ]).strip() == str (params.get( "expectedOutput" , "" )).strip()
return { "passed" : match, "score" : 1.0 if match else 0.0 }
evals = {
"exact_match" : exact_match,
}
client = create_claude_agent_client(
model_registry = model_registry,
loader = loader,
evals = evals,
)
Reference evals in your prompt frontmatter:
---
test_settings :
dataset : ./datasets/test.jsonl
evals :
- exact_match
---
Learn more about evaluations
Tracing
Wrap query with withTracing to emit OpenTelemetry spans. Pass adapted.query and adapted.telemetry in an object: import { client } from "./agentmark.client" ;
import { withTracing } from "@agentmark-ai/claude-agent-sdk-v0-adapter" ;
import { query } from "@anthropic-ai/claude-agent-sdk" ;
const prompt = await client . loadTextPrompt ( "task.prompt.mdx" );
const adapted = await prompt . format ({
props: { task: "..." },
telemetry: { isEnabled: true },
});
const result = await withTracing ( query , {
query: adapted . query ,
telemetry: adapted . telemetry ,
});
console . log ( "Trace ID:" , result . traceId );
for await ( const message of result ) {
console . log ( message );
}
traced_query automatically emits OpenTelemetry spans when the adapter’s telemetry is enabled on prompt.format():from agentmark_claude_agent_sdk_v0 import traced_query
adapted = await prompt.format(
props = { "task" : "..." },
telemetry = { "isEnabled" : True },
)
async for message in traced_query(adapted):
print (message)
Learn more in Tracing setup .
Getting started (Python)
Scaffold a Python project with the Claude Agent SDK adapter:
npm create agentmark@latest my-app
# Select "Python" when prompted for language
# Select "Claude Agent SDK" as the adapter
Run the local dev server:
Limitations
No image generation — use the AI SDK adapter for experimental_generateImage.
No speech generation — use the AI SDK adapter for experimental_generateSpeech.
Messages stream as the agent runs via query() / traced_query(), but the final aggregated result is only available after all turns complete.
Next steps
Prompts Learn about prompt syntax
Tools and agents Configure tools for your agents
Observability Monitor your agents in production
Other integrations Explore other AI frameworks
Have Questions? We’re here to help! Choose the best way to reach us: