Claude Component
The <Claude> component is the core of Smithers. It executes Claude via Claude Code CLI with full tool access, database logging, and structured output support.
Basic Usage
import { Claude } from "smithers-orchestrator" ;
< Claude
model = "sonnet"
maxTurns = { 10 }
onFinished = { ( result ) => console . log ( result . output ) }
>
Analyze this codebase and suggest improvements.
</ Claude >
Props
Model Configuration
model
'opus' | 'sonnet' | 'haiku'
default: "sonnet"
The Claude model to use. < Claude model = "opus" > Complex reasoning task </ Claude >
< Claude model = "sonnet" > Standard task </ Claude >
< Claude model = "haiku" > Quick, simple task </ Claude >
Maximum number of agentic turns (tool use cycles). < Claude maxTurns = { 5 } > Limited iteration task </ Claude >
Maximum tokens for the response. Reserved for future implementation. Currently has no effect.
Timeout in milliseconds. < Claude timeout = { 60000 } > Task with 1 minute timeout </ Claude >
System Prompt
Custom system prompt for Claude. < Claude systemPrompt = "You are a security expert. Focus on vulnerabilities." >
Review this code.
</ Claude >
Custom tools to provide to Claude. Experimental. Custom tool support is functional but API may change. Use allowedTools/disallowedTools for built-in tools, or the <Sqlite> component for database access.
< Claude
tools = { [
{
name: "query_database" ,
description: "Query the PostgreSQL database" ,
inputSchema: {
type: "object" ,
properties: {
query: { type: "string" , description: "SQL query" },
},
required: [ "query" ],
},
execute : async ( input ) => {
const result = await db . query ( input . query );
return JSON . stringify ( result );
},
},
] }
>
Query the database for statistics.
</ Claude >
Restrict Claude to only these built-in tools. < Claude allowedTools = { [ "Read" , "Glob" , "Grep" ] } >
Research only - no edits.
</ Claude >
Prevent Claude from using these tools. < Claude disallowedTools = { [ "Bash" ] } >
No shell commands.
</ Claude >
permissionMode
'default' | 'acceptEdits' | 'plan'
Permission handling mode. < Claude permissionMode = "acceptEdits" >
Auto-accept file edits.
</ Claude >
Structured Output
Zod schema for structured output validation. const ResultSchema = z . object ({
summary: z . string (),
issues: z . array ( z . string ()),
});
< Claude schema = { ResultSchema } >
Return structured analysis.
</ Claude >
validate
(result: AgentResult) => boolean | Promise<boolean>
Custom validation function. Receives the full AgentResult including output, structured, tokensUsed, etc. < Claude
schema = { AnalysisSchema }
validate = { ( result ) => result . structured ?. issues . length > 0 }
>
Must find at least one issue.
</ Claude >
Retry if validation fails.
Maximum retries for the outer error retry loop.
Maximum retries for structured output schema validation. When Claude returns
output that fails Zod schema validation, it will retry up to this many times. < Claude schema = { UserSchema } schemaRetries = { 3 } >
Return user data in the expected format.
</ Claude >
Callbacks
onFinished
(result: AgentResult) => void
Called when execution completes. < Claude onFinished = { ( result ) => {
console . log ( result . output );
console . log ( result . structured ); // If schema provided
console . log ( result . tokensUsed );
} } >
Task
</ Claude >
Called on execution error. < Claude onError = { ( err ) => console . error ( err ) } >
Risky task
</ Claude >
onProgress
(message: string) => void
Called with progress updates.
onStreamPart
(part: SmithersStreamPart) => void
Called with typed stream events when experimental streaming is enabled.
onToolCall
(tool: string, input: any) => void
Called when Claude uses a tool.
Stop Conditions
Conditions that can stop execution early. < Claude
stopConditions = { [
{ type: "token_limit" , value: 10000 },
{ type: "pattern" , value: /DONE/ i },
] }
>
Task with stop conditions
</ Claude >
Session Management
Continue from the previous conversation in the same execution context.
Resume a specific session by ID.
Output Configuration
outputFormat
'text' | 'json' | 'stream-json'
default: "text"
Output format for Claude CLI responses.
text: Plain text output (default)
json: Structured JSON output
stream-json: Streaming JSON output (required for typed streaming)
Path to MCP (Model Context Protocol) configuration file. < Claude mcpConfig = "./mcp-config.json" >
Use the configured MCP tools.
</ Claude >
Tail Log Display
Number of tail log entries to display during execution.
Number of lines to show per tail log entry.
Streaming
experimentalTypedStreaming
Enable typed V3 stream parts for Claude CLI output. When enabled and no
explicit outputFormat is provided, stream-json is used automatically.
Write legacy raw text logs alongside NDJSON stream logs.
Record stream events to the database when reporting is enabled.
Reporting
Enable database reporting for this agent. When enabled, agent execution
is logged to the database for observability.
AgentResult Type
interface AgentResult < T = any > {
output : string ; // Raw text output
structured ?: T ; // Validated structured output
tokensUsed : {
input : number ;
output : number ;
};
turnsUsed : number ;
stopReason : 'completed' | 'stop_condition' | 'error' | 'cancelled' ;
durationMs : number ;
exitCode ?: number ;
sessionId ?: string ;
}
Structured Output with Zod
Get typed, validated responses:
import { z } from 'zod' ;
const AnalysisSchema = z . object ({
summary: z . string (),
issues: z . array ( z . object ({
severity: z . enum ([ 'low' , 'medium' , 'high' , 'critical' ]),
file: z . string (),
description: z . string (),
})),
recommendations: z . array ( z . string ()),
});
< Claude
model = "sonnet"
schema = { AnalysisSchema }
maxRetries = { 2 }
onFinished = { ( result ) => {
// result.structured is typed as z.infer<typeof AnalysisSchema>
for ( const issue of result . structured . issues ) {
console . log ( `[ ${ issue . severity } ] ${ issue . file } : ${ issue . description } ` );
}
} }
>
Analyze this codebase for security issues.
Return a structured analysis.
</ Claude >
Control what Claude can do:
// Research only - no modifications
< Claude allowedTools = { [ "Read" , "Glob" , "Grep" ] } >
Find all files that import the auth module.
</ Claude >
// Full edit access
< Claude
allowedTools = { [ "Read" , "Edit" , "Write" , "Bash" ] }
permissionMode = "acceptEdits"
>
Implement the feature.
</ Claude >
// No shell access
< Claude disallowedTools = { [ "Bash" ] } >
Analyze the code (no commands).
</ Claude >
Conditional Rendering
Use state to control when Claude runs:
function ConditionalClaude () {
const { db , reactiveDb } = useSmithers ();
const phase = useQueryValue < string >(
reactiveDb ,
"SELECT value FROM state WHERE key = 'phase'"
) ?? "research" ;
const setPhase = ( p : string ) => db . state . set ( 'phase' , p );
return (
< SmithersProvider db = { db } executionId = { executionId } maxIterations = { 5 } >
< If condition = { phase === "research" } >
< Claude
allowedTools = { [ "Read" , "Glob" ] }
onFinished = { () => setPhase ( "implement" ) }
>
Research the codebase.
</ Claude >
</ If >
< If condition = { phase === "implement" } >
< Claude
allowedTools = { [ "Edit" , "Write" ] }
onFinished = { () => setPhase ( "done" ) }
>
Implement the solution.
</ Claude >
</ If >
</ SmithersProvider >
);
}
Nested Prompt Components
Compose prompts with child components:
< Claude model = "sonnet" >
< Sqlite path = "./data.db" >
Database contains users and orders tables.
</ Sqlite >
Find the top 10 customers by order value.
Export results to a CSV file.
</ Claude >
Error Handling
function ResilientClaude () {
const { db , reactiveDb } = useSmithers ();
const attempts = useQueryValue < number >(
reactiveDb ,
"SELECT value FROM state WHERE key = 'attempts'"
) ?? 0 ;
const error = useQueryValue < string | null >(
reactiveDb ,
"SELECT value FROM state WHERE key = 'error'"
) ?? null ;
return (
< SmithersProvider db = { db } executionId = { executionId } maxIterations = { 3 } >
< If condition = { error !== null && attempts < 3 } >
< Claude
onFinished = { () => db . state . set ( 'error' , null ) }
onError = { ( err ) => {
db . state . set ( 'error' , err . message );
db . state . set ( 'attempts' , attempts + 1 );
} }
>
Previous attempt failed: { error }
Try a different approach.
</ Claude >
</ If >
< If condition = { error === null } >
< Claude
onFinished = { ( r ) => console . log ( "Success:" , r . output ) }
onError = { ( err ) => db . state . set ( 'error' , err . message ) }
>
Complete the task.
</ Claude >
</ If >
</ SmithersProvider >
);
}
Best Practices
Always set maxTurns for agentic tasks
Prevent runaway iterations: < Claude maxTurns = { 10 } > ... </ Claude >
Use allowedTools to restrict access
Use schemas for predictable output
Validate responses with Zod: < Claude schema = { MySchema } maxRetries = { 2 } >