Skip to content

feat: add claude-agent-sdk single-agent and multi-agent patterns with READMEs#45

Merged
kaleko merged 12 commits intoawslabs:mainfrom
iprivit:main
Mar 11, 2026
Merged

feat: add claude-agent-sdk single-agent and multi-agent patterns with READMEs#45
kaleko merged 12 commits intoawslabs:mainfrom
iprivit:main

Conversation

@iprivit
Copy link
Contributor

@iprivit iprivit commented Mar 3, 2026

Summary

  • Two new claude-agent-sdk agent patterns alongside strands and langgraph:
    • claude-agent-sdk-single-agent: Standalone agent with Code Interpreter via in-process MCP server, Gateway integration, session management via claude_session_id, and secure JWT-based user identity extraction
    • claude-agent-sdk-multi-agent: Extends the single-agent pattern with subagent delegation — includes a code-analyst subagent for Task-based delegation via the Task tool
  • Dedicated frontend SSE parser shared by both claude-agent-sdk patterns
  • CDK updates: CLAUDE_CODE_USE_BEDROCK env var for both patterns and validation preventing zip deployment (requires Node.js + claude-code CLI)
  • Security hardening: STACK_NAME format validation, payload field validation, graceful gateway failure handling
  • Server-side session map for claude-agent-sdk conversation memory — maps runtimeSessionId to claude_session_id on the backend, no frontend round-trip needed
  • Built-in tool lockdown: Disables claude-code built-in tools (Bash, Write, Read, Edit, NotebookEdit, WebFetch, Glob, Grep, EnterWorktree, Skill, TodoWrite, CronCreate, CronDelete, CronList) via disallowed_tools so the agent operates exclusively through Code Interpreter and Gateway MCP tools. Documentation explains how to re-enable individual tools.
  • Pinned dependency versions: claude-agent-sdk==0.1.48 and @anthropic-ai/claude-code@2.1.73 for reproducible builds
  • READMEs for all patterns (strands, langgraph, claude-agent-sdk-single-agent, claude-agent-sdk-multi-agent) documenting features, architecture, streaming events, tool configuration, memory, security, and deployment

Changed files

Single-agent pattern (patterns/claude-agent-sdk-single-agent/):

  • agent.py — main entrypoint with ClaudeSDKClient, RequestContext security, Code Interpreter MCP, Gateway, server-side session map, disallowed_tools configuration
  • code_int_mcp/ — in-process MCP server wrapping AgentCore Code Interpreter API (server, client, models)
  • Dockerfile — Python 3.11 + Node.js + @anthropic-ai/claude-code@2.1.73
  • requirements.txtclaude-agent-sdk==0.1.48, bedrock-agentcore, pydantic, PyJWT, etc.
  • README.md — full pattern documentation including built-in tool configuration

Multi-agent pattern (patterns/claude-agent-sdk-multi-agent/):

  • Same as single-agent, plus:
  • agents/subagents.pycode-analyst subagent definition via AgentDefinition
  • agent.py — adds Task tool and subagent orchestration to the single-agent base
  • README.md — full pattern documentation including subagent usage and built-in tool configuration

Frontend:

  • parsers/claude-agent-sdk.ts — dedicated parser for data, current_tool_use, claude_session_id events
  • types.ts — added "claude-agent-sdk-single-agent" and "claude-agent-sdk-multi-agent" to AgentPattern union
  • client.ts — registered both patterns with the shared parser

Shared utilities:

  • patterns/utils/auth.py — added get_gateway_access_token() with @requires_access_token decorator

Infrastructure:

  • backend-stack.ts — conditional CLAUDE_CODE_USE_BEDROCK=1 env var + zip deployment validation for both patterns

Documentation:

  • patterns/strands-single-agent/README.md
  • patterns/langgraph-single-agent/README.md

- **Gateway auth**: OAuth2 client credentials flow via Cognito for machine-to-machine authentication
- **Gateway resilience**: If Gateway is unavailable, the agent continues without Gateway tools

## Differences from Strands / LangGraph Patterns
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the differences, but my main question is why there are differences? For example why didn't we make the claude-sdk example use AgentCore Memory, single agent, and why we need an in-process MCP server for this? Would be useful to explain why the differences in the docs/code

# Claude Agent SDK dependencies
claude-agent-sdk
bedrock-agentcore
bedrock-agentcore-starter-toolkit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting dependency... definitely needed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to make this claude-agent-sdk-single-agent instead of having multiple agents, so it is more apples to apples with the existing patterns? Then we can include a readme or commented code showing how to extend it to multiple agents?

@github-actions
Copy link

github-actions bot commented Mar 11, 2026

Latest scan for commit: e80f5ae | Updated: 2026-03-11 19:28:22 UTC

Security Scan Results

Scan Metadata

  • Project: ASH
  • Scan executed: 2026-03-11T19:28:06+00:00
  • ASH version: 3.2.2

Summary

Scanner Results

The table below shows findings by scanner, with status based on severity thresholds and dependencies:

Column Explanations:

Severity Levels (S/C/H/M/L/I):

  • Suppressed (S): Security findings that have been explicitly suppressed/ignored and don't affect the scanner's pass/fail status
  • Critical (C): The most severe security vulnerabilities requiring immediate remediation (e.g., SQL injection, remote code execution)
  • High (H): Serious security vulnerabilities that should be addressed promptly (e.g., authentication bypasses, privilege escalation)
  • Medium (M): Moderate security risks that should be addressed in normal development cycles (e.g., weak encryption, input validation issues)
  • Low (L): Minor security concerns with limited impact (e.g., information disclosure, weak recommendations)
  • Info (I): Informational findings for awareness with minimal security risk (e.g., code quality suggestions, best practice recommendations)

Other Columns:

  • Time: Duration taken by each scanner to complete its analysis
  • Action: Total number of actionable findings at or above the configured severity threshold that require attention

Scanner Results:

  • PASSED: Scanner found no security issues at or above the configured severity threshold - code is clean for this scanner
  • FAILED: Scanner found security vulnerabilities at or above the threshold that require attention and remediation
  • MISSING: Scanner could not run because required dependencies/tools are not installed or available
  • SKIPPED: Scanner was intentionally disabled or excluded from this scan
  • ERROR: Scanner encountered an execution error and could not complete successfully

Severity Thresholds (Thresh Column):

  • CRITICAL: Only Critical severity findings cause scanner to fail
  • HIGH: High and Critical severity findings cause scanner to fail
  • MEDIUM (MED): Medium, High, and Critical severity findings cause scanner to fail
  • LOW: Low, Medium, High, and Critical severity findings cause scanner to fail
  • ALL: Any finding of any severity level causes scanner to fail

Threshold Source: Values in parentheses indicate where the threshold is configured:

  • (g) = global: Set in the global_settings section of ASH configuration
  • (c) = config: Set in the individual scanner configuration section
  • (s) = scanner: Default threshold built into the scanner itself

Statistics calculation:

  • All statistics are calculated from the final aggregated SARIF report
  • Suppressed findings are counted separately and do not contribute to actionable findings
  • Scanner status is determined by comparing actionable findings to the threshold
Scanner S C H M L I Time Action Result Thresh
bandit 0 0 0 0 0 0 865ms 0 PASSED MED (g)
cdk-nag 0 0 0 0 0 0 30.9s 0 PASSED MED (g)
cfn-nag 0 0 0 0 0 0 9ms 0 PASSED MED (g)
checkov 0 0 0 0 0 0 4.6s 0 PASSED MED (g)
detect-secrets 0 0 0 0 0 0 828ms 0 PASSED MED (g)
grype 0 0 0 0 0 0 52.4s 0 PASSED MED (g)
npm-audit 0 0 0 0 0 0 165ms 0 PASSED MED (g)
opengrep 0 9 0 0 0 0 29.0s 9 FAILED MED (g)
semgrep 0 9 0 0 0 0 11.3s 9 FAILED MED (g)
syft 0 0 0 0 0 0 2.0s 0 PASSED MED (g)

Detailed Findings

Show 18 actionable findings

Finding 1: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: semgrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:126

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const patternDir = path.join(repoRoot, "patterns", pattern)

Finding 2: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: semgrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:154

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const content = fs.readFileSync(path.join(patternDir, file))

Finding 3: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: semgrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:154

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const content = fs.readFileSync(path.join(patternDir, file))

Finding 4: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: semgrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:168

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const requirementsPath = path.join(patternDir, "requirements.txt")

Finding 5: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: semgrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:998

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const fullPath = path.join(dirPath, entry.name)

Finding 6: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: semgrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:998

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const fullPath = path.join(dirPath, entry.name)

Finding 7: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: semgrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:999

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const relativePath = path.join(prefix, entry.name)

Finding 8: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: semgrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:999

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const relativePath = path.join(prefix, entry.name)

Finding 9: python.jwt.security.unverified-jwt-decode.unverified-jwt-decode

  • Severity: HIGH
  • Scanner: semgrep
  • Rule ID: python.jwt.security.unverified-jwt-decode.unverified-jwt-decode
  • Location: patterns/utils/auth.py:65

Description:
Detected JWT token decoded with 'verify=False'. This bypasses any integrity checks for the token which means the token could be tampered with by malicious actors. Ensure that the JWT token is verified.

Code Snippet:

options={"verify_signature": False},

Finding 10: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: opengrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:126

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const patternDir = path.join(repoRoot, "patterns", pattern)

Finding 11: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: opengrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:154

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const content = fs.readFileSync(path.join(patternDir, file))

Finding 12: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: opengrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:154

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const content = fs.readFileSync(path.join(patternDir, file))

Finding 13: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: opengrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:168

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const requirementsPath = path.join(patternDir, "requirements.txt")

Finding 14: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: opengrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:998

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const fullPath = path.join(dirPath, entry.name)

Finding 15: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: opengrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:998

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const fullPath = path.join(dirPath, entry.name)

Finding 16: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: opengrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:999

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const relativePath = path.join(prefix, entry.name)

Finding 17: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal

  • Severity: HIGH
  • Scanner: opengrep
  • Rule ID: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
  • Location: infra-cdk/lib/backend-stack.ts:999

Description:
Detected possible user input going into a path.join or path.resolve function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

Code Snippet:

const relativePath = path.join(prefix, entry.name)

Finding 18: python.jwt.security.unverified-jwt-decode.unverified-jwt-decode

  • Severity: HIGH
  • Scanner: opengrep
  • Rule ID: python.jwt.security.unverified-jwt-decode.unverified-jwt-decode
  • Location: patterns/utils/auth.py:65

Description:
Detected JWT token decoded with 'verify=False'. This bypasses any integrity checks for the token which means the token could be tampered with by malicious actors. Ensure that the JWT token is verified.

Code Snippet:

options={"verify_signature": False},

Report generated by Automated Security Helper (ASH) at 2026-03-11T19:28:00+00:00

@iprivit iprivit changed the title feat: add claude-agent-sdk pattern and pattern READMEs feat: add claude-agent-sdk single-agent and multi-agent patterns with READMEs Mar 11, 2026
@github-actions github-actions bot added the tests label Mar 11, 2026
iprivit added 5 commits March 11, 2026 09:46
Add a minimal claude-agent-sdk pattern alongside strands and langgraph,
featuring Code Interpreter via in-process MCP server, a code-analyst
subagent for Task-based delegation, Gateway integration, and a dedicated
frontend SSE parser. CDK backend-stack updated with CLAUDE_CODE_USE_BEDROCK
env var and zip deployment validation.
- Validate STACK_NAME format to prevent SSM parameter path injection
- Validate required payload fields (prompt, runtimeSessionId) with proper error response
- Wrap gateway URL retrieval in try/except to avoid crashes when gateway is unavailable
Covers features, architecture, file structure, tools, streaming events,
session management, subagent usage, deployment, security, and comparison
with strands/langgraph patterns.
Cover features, architecture, file structure, tools, streaming events,
memory integration, security, deployment, and dependencies for both
patterns.
…tterns

Separates the claude-agent-sdk pattern into two distinct patterns:
- claude-agent-sdk-single-agent: standalone agent with Code Interpreter and Gateway tools
- claude-agent-sdk-multi-agent: adds subagent delegation via Task tool + code-analyst subagent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all of the changes in this file can be reverted in lieu of latest force-push to main to fix frontend bugs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all of the changes in this file can be reverted in lieu of latest force-push to main to fix frontend bugs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all of the changes in this file can be reverted in lieu of latest force-push to main to fix frontend bugs. I believe the exact same fix was already pushed.

iprivit added 2 commits March 11, 2026 09:50
…rrors

- Add get_gateway_access_token() using @requires_access_token decorator
  to utils/auth.py, fixing ImportError on agent startup
- ChatMessage.tsx: prefix unused sessionId param with underscore
- config.test.ts: add TSConfig interface and cast parseJSONC results
- property-auth-routing.test.tsx: cast mock user objects to User type
…mory

Instead of round-tripping claude_session_id through the frontend,
maintain an in-memory runtimeSessionId -> claude_session_id mapping
on the backend. Both are lost on container restart, so in-memory
storage is sufficient. No frontend changes required.
iprivit added 4 commits March 11, 2026 10:03
Upstream excluded src/test from tsc (e609a28), making these fixes
unnecessary. Reverting to match upstream.
Disable Bash, Write, Read, Edit, NotebookEdit, WebFetch, Glob, Grep,
EnterWorktree, and Skill via disallowed_tools in ClaudeAgentOptions.
The agent now operates exclusively through Code Interpreter MCP tools
and Gateway tools. Added documentation explaining the configuration
and how to re-enable tools.
@kaleko kaleko merged commit 5d3b541 into awslabs:main Mar 11, 2026
3 of 5 checks passed
kaleko added a commit that referenced this pull request Mar 12, 2026
…E_USE_BEDROCK env var

- Add precondition to prevent zip deployment with claude-agent-sdk patterns
- Add conditional CLAUDE_CODE_USE_BEDROCK=1 environment variable
- Add is_claude_agent_sdk local flag

Mirrors CDK backend-stack.ts changes from PR #45.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants