363 lines
11 KiB
Markdown
363 lines
11 KiB
Markdown
# Claude Agent SDK Validation Checklist
|
|
|
|
This checklist helps validate SDK applications against official patterns and best practices from the claude-agent-sdk skill documentation.
|
|
|
|
## Quick Validation
|
|
|
|
Use this checklist when:
|
|
|
|
- Creating new SDK applications
|
|
- Reviewing SDK code
|
|
- Debugging SDK issues
|
|
- Ensuring alignment with best practices
|
|
|
|
---
|
|
|
|
## 1. Imports & Dependencies
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **Async runtime import**
|
|
- Uses `import anyio` (official SDK examples use anyio)
|
|
- Comment reflects official preference: `# Official SDK examples use anyio`
|
|
- **Reference:** Official examples consistently use anyio
|
|
|
|
- [ ] **Claude SDK imports are accurate**
|
|
- `ClaudeAgentOptions` for configuration
|
|
- `ClaudeSDKClient` for continuous conversations OR `query` for one-shot tasks
|
|
- `AgentDefinition` if using programmatic agents
|
|
- Message types: `AssistantMessage`, `ResultMessage`, `TextBlock`
|
|
- Permission types if using callbacks: `PermissionResultAllow`, `PermissionResultDeny`
|
|
- **Reference:** `references/api-reference.md`
|
|
|
|
- [ ] **UV script headers (if applicable)**
|
|
- Uses `#!/usr/bin/env -S uv run --script --quiet`
|
|
- Has PEP 723 dependencies block with `claude-agent-sdk>=0.1.6`
|
|
- **Reference:** `assets/sdk-template.py` lines 1-7
|
|
|
|
---
|
|
|
|
## 2. Async Runtime
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **Runtime execution is correct**
|
|
- Uses `anyio.run(main)` (official SDK examples use anyio.run())
|
|
- Comment reflects official preference: `# Official SDK examples use anyio.run()`
|
|
- **Reference:** Official examples consistently use anyio.run()
|
|
|
|
- [ ] **Async/await patterns are correct**
|
|
- Functions marked as `async def`
|
|
- Uses `await` for SDK calls
|
|
- Uses `async for` for message streaming
|
|
- Uses `async with` for ClaudeSDKClient context manager
|
|
- **Reference:** `references/best-practices.md` lines 82-94
|
|
|
|
---
|
|
|
|
## 3. Choosing query() vs ClaudeSDKClient
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **Correct approach for use case**
|
|
- `query()`: One-shot tasks, no conversation memory
|
|
- `ClaudeSDKClient`: Multi-turn conversations, context retention
|
|
- **Reference:** SKILL.md lines 29-44
|
|
|
|
- [ ] **Hooks/Custom tools only with ClaudeSDKClient**
|
|
- NOT using hooks with `query()` (not supported)
|
|
- NOT using custom tools with `query()` (not supported)
|
|
- **Reference:** SKILL.md line 45 (important warning)
|
|
|
|
---
|
|
|
|
## 4. Orchestrator Configuration
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **System prompt is set correctly**
|
|
- Uses `system_prompt={"type": "preset", "preset": "claude_code"}` for orchestrators
|
|
(official examples use dict format)
|
|
- OR uses `system_prompt="claude_code"` (string shorthand, equivalent but less explicit)
|
|
- Custom prompts only for non-orchestrators
|
|
- **Reference:** Official examples use dict format, SKILL.md lines 226-242,
|
|
`references/system-prompts.md`
|
|
|
|
- [ ] **Task tool is included**
|
|
- `allowed_tools` includes `"Task"` for orchestrators
|
|
- Orchestrators cannot delegate without Task tool
|
|
- **Reference:** SKILL.md line 39, `references/best-practices.md` lines 72-80
|
|
|
|
- [ ] **Agent definitions are programmatic**
|
|
- Agents defined in `agents={}` parameter (preferred)
|
|
- Clear `description` (when to use agent)
|
|
- Specific `prompt` (agent instructions)
|
|
- Minimal `tools` list (principle of least privilege)
|
|
- **Reference:** SKILL.md lines 195-217, `references/agent-patterns.md`
|
|
|
|
---
|
|
|
|
## 5. Agent Definitions
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **Agent definition structure is correct**
|
|
|
|
```python
|
|
AgentDefinition(
|
|
description="...", # When to use this agent
|
|
prompt="...", # Agent instructions
|
|
tools=[...], # Minimal tool set
|
|
model="sonnet" # or "opus", "haiku", "inherit"
|
|
)
|
|
```
|
|
|
|
- **Reference:** SKILL.md lines 195-217
|
|
|
|
- [ ] **Agent names match references**
|
|
- Names in `agents={}` match Task tool usage
|
|
- No naming mismatches between definition and invocation
|
|
- **Reference:** `references/best-practices.md` lines 43-52
|
|
|
|
- [ ] **Tools are restricted to minimum needed**
|
|
- Read-only agents: `["Read", "Grep", "Glob"]`
|
|
- Code modifiers: `["Read", "Edit", "Bash"]`
|
|
- No excessive tool permissions
|
|
- **Reference:** SKILL.md lines 248-256, `references/best-practices.md` lines 54-71
|
|
|
|
---
|
|
|
|
## 6. Permission Control
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **Permission strategy is appropriate**
|
|
- Simple use case → `permission_mode` only
|
|
- Complex logic → `can_use_tool` callback
|
|
- **Reference:** `references/tool-permissions.md` lines 13-114
|
|
|
|
- [ ] **Permission mode is valid**
|
|
- One of: `"acceptEdits"`, `"rejectEdits"`, `"plan"`, `"bypassPermissions"`, `"default"`
|
|
- Appropriate for use case (e.g., CI/CD uses `"acceptEdits"`)
|
|
- **Reference:** `references/tool-permissions.md` lines 64-70
|
|
|
|
- [ ] **Permission callback (if used) is correct**
|
|
- Signature: `async def(tool_name, input_data, context) -> PermissionResultAllow | PermissionResultDeny`
|
|
- Returns early for unmatched tools
|
|
- Uses `.get()` for safe input_data access
|
|
- Clear denial messages
|
|
- **Reference:** `references/tool-permissions.md` lines 120-344, `examples/tool_permission_callback.py`
|
|
|
|
---
|
|
|
|
## 7. Hooks (if used)
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **Hooks ONLY used with ClaudeSDKClient**
|
|
- NOT using hooks with `query()` function
|
|
- **Reference:** SKILL.md line 45 (critical warning)
|
|
|
|
- [ ] **Hook types are supported**
|
|
- Using ONLY: `PreToolUse`, `PostToolUse`, `UserPromptSubmit`, `Stop`, `SubagentStop`, `PreCompact`
|
|
- NOT using unsupported: `SessionStart`, `SessionEnd`, `Notification`
|
|
- **Reference:** `references/hooks-guide.md` line 14 (important warning)
|
|
|
|
- [ ] **Hook signature is correct**
|
|
- `async def(input_data, tool_use_id, context) -> HookJSONOutput`
|
|
- Returns empty `{}` when hook doesn't apply
|
|
- Uses `HookMatcher` for tool filtering
|
|
- **Reference:** `references/hooks-guide.md` lines 46-68, `examples/hooks.py`
|
|
|
|
- [ ] **Hook output structure is valid**
|
|
- Includes `hookEventName` in `hookSpecificOutput`
|
|
- PreToolUse: includes `permissionDecision` ("allow" or "deny")
|
|
- Includes clear `reason` and `systemMessage` fields
|
|
- **Reference:** `references/hooks-guide.md` lines 70-144
|
|
|
|
---
|
|
|
|
## 8. ClaudeSDKClient Usage
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **Context manager pattern is used**
|
|
|
|
```python
|
|
async with ClaudeSDKClient(options=options) as client:
|
|
await client.query(...)
|
|
async for message in client.receive_response():
|
|
...
|
|
```
|
|
|
|
- **Reference:** SKILL.md lines 88-124
|
|
|
|
- [ ] **Query → receive_response flow**
|
|
- Calls `await client.query(prompt)` first
|
|
- Then iterates `async for message in client.receive_response()`
|
|
- Does NOT interleave queries and receives incorrectly
|
|
- **Reference:** `examples/streaming_mode.py`
|
|
|
|
- [ ] **Interrupts (if used) are correct**
|
|
- Uses `await client.interrupt()` to stop execution
|
|
- Only available with ClaudeSDKClient (not query())
|
|
- **Reference:** SKILL.md lines 139-162
|
|
|
|
---
|
|
|
|
## 9. Message Handling
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **Message types are checked correctly**
|
|
|
|
```python
|
|
if isinstance(message, AssistantMessage):
|
|
for block in message.content:
|
|
if isinstance(block, TextBlock):
|
|
print(block.text)
|
|
elif isinstance(message, ResultMessage):
|
|
# Handle completion
|
|
```
|
|
|
|
- **Reference:** SKILL.md lines 77-91, `examples/streaming_mode.py`
|
|
|
|
- [ ] **TextBlock extraction is correct**
|
|
- Iterates through `message.content`
|
|
- Checks `isinstance(block, TextBlock)` before accessing `.text`
|
|
- **Reference:** `references/best-practices.md` lines 95-113
|
|
|
|
- [ ] **ResultMessage handling**
|
|
- Checks for `message.duration_ms`, `message.total_cost_usd`
|
|
- Uses optional access (fields may be None)
|
|
- **Reference:** `assets/sdk-template.py` lines 86-93
|
|
|
|
---
|
|
|
|
## 10. Error Handling
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **API key validation**
|
|
- Checks `os.getenv("ANTHROPIC_API_KEY")` before SDK calls
|
|
- Provides clear error message if missing
|
|
- **Reference:** `assets/sdk-template.py` lines 58-63
|
|
|
|
- [ ] **Safe dictionary access**
|
|
- Uses `.get()` for input_data, tool_response fields
|
|
- Handles missing/None values gracefully
|
|
- **Reference:** `references/tool-permissions.md` lines 297-344
|
|
|
|
- [ ] **Async exception handling**
|
|
- Try/except blocks for critical sections
|
|
- Proper cleanup in exception cases
|
|
- **Reference:** `references/best-practices.md`
|
|
|
|
---
|
|
|
|
## 11. Settings & Configuration
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **setting_sources is configured (if needed)**
|
|
- Default behavior: NO settings loaded (isolated environment)
|
|
- Explicitly set to load: `["user"]`, `["project"]`, `["local"]`, or combinations like `["user", "project"]`
|
|
- Understands isolation vs loading tradeoff
|
|
- **Reference:** `examples/setting_sources.py` (official example shows user, project, local options)
|
|
|
|
- [ ] **Model selection is appropriate**
|
|
- Orchestrator: `"claude-sonnet-4-5"` (simplified, official examples prefer this)
|
|
or `"claude-sonnet-4-5-20250929"` (dated version)
|
|
- Subagents: `"sonnet"`, `"opus"`, `"haiku"`, or `"inherit"`
|
|
- **Reference:** Official examples use `claude-sonnet-4-5`, SKILL.md line 51,
|
|
`references/agent-patterns.md`
|
|
|
|
- [ ] **Budget limits (if needed)**
|
|
- Uses `max_budget_usd` for cost control
|
|
- Appropriate for CI/CD and automated workflows
|
|
- **Reference:** `examples/max_budget_usd.py`
|
|
|
|
---
|
|
|
|
## 12. Best Practices Compliance
|
|
|
|
### Required Checks
|
|
|
|
- [ ] **Follows DRY principle**
|
|
- Options extracted to function (e.g., `get_sdk_options()`)
|
|
- Reusable patterns not duplicated
|
|
- **Reference:** `assets/sdk-template.py` lines 33-55
|
|
|
|
- [ ] **Clear comments and documentation**
|
|
- Docstrings for functions
|
|
- Inline comments for complex logic
|
|
- Usage notes in module docstring
|
|
- **Reference:** `assets/sdk-template.py` lines 8-17
|
|
|
|
- [ ] **Type hints are used**
|
|
- Function return types specified
|
|
- Parameter types for clarity
|
|
- **Reference:** `assets/sdk-template.py` line 36
|
|
|
|
- [ ] **No anti-patterns**
|
|
- Not using agents for simple tasks (use query() instead)
|
|
- Not giving excessive tool permissions
|
|
- Not bypassing permissions without reason
|
|
- **Reference:** `references/best-practices.md`, skill SKILL.md
|
|
|
|
---
|
|
|
|
## Validation Summary Template
|
|
|
|
After reviewing, fill out this summary:
|
|
|
|
### ✅ Passed Checks
|
|
|
|
- [ ] Imports & Dependencies
|
|
- [ ] Async Runtime
|
|
- [ ] Orchestrator Configuration
|
|
- [ ] Agent Definitions
|
|
- [ ] Permission Control
|
|
- [ ] Message Handling
|
|
- [ ] Best Practices
|
|
|
|
### ❌ Issues Found
|
|
|
|
- Issue 1: [Description]
|
|
- Issue 2: [Description]
|
|
|
|
### 🔧 Fixes Required
|
|
|
|
1. [Specific fix with line reference]
|
|
2. [Specific fix with line reference]
|
|
|
|
### 📊 Overall Assessment
|
|
|
|
- **Accuracy:** [%]
|
|
- **Alignment with docs:** [High/Medium/Low]
|
|
- **Production ready:** [Yes/No]
|
|
|
|
---
|
|
|
|
## Quick Reference Links
|
|
|
|
**Core Documentation:**
|
|
|
|
- Main skill: `SKILL.md`
|
|
- API reference: `references/api-reference.md`
|
|
- Best practices: `references/best-practices.md`
|
|
|
|
**Pattern Guides:**
|
|
|
|
- Agent patterns: `references/agent-patterns.md`
|
|
- Hooks: `references/hooks-guide.md`
|
|
- Permissions: `references/tool-permissions.md`
|
|
- System prompts: `references/system-prompts.md`
|
|
- Subagents: `references/subagents.md`
|
|
|
|
**Examples:**
|
|
|
|
- Quick start: `examples/quick_start.py`
|
|
- Template: `assets/sdk-template.py`
|
|
- Complete examples: `examples/*.py`
|