Claude / OpenAI SDK patterns
SDK Patterns: Where Identity, Config, and Knowledge Live
Section titled “SDK Patterns: Where Identity, Config, and Knowledge Live”Research date: 2026-05-11 Scope: Production-grade agent SDKs — how they recommend laying out persona, runtime config, shared knowledge, and folder structure for fleets of named agents.
Frameworks studied:
- Anthropic Claude Agent SDK (Python + TypeScript)
- Claude Code (CLAUDE.md hierarchy, subagents, plugins)
- Agent Skills open standard (SKILL.md spec)
- OpenAI Assistants API + successor Responses API / Prompts
- OpenAI Agents SDK (Python, code-defined)
For each: concrete answers to the six design questions, then a comparison table, ranked patterns worth stealing, and antipatterns flagged in the docs.
1. Claude Code — CLAUDE.md hierarchy, subagents, skills
Section titled “1. Claude Code — CLAUDE.md hierarchy, subagents, skills”This is the closest analog to a fleet of named persistent agents sharing a common ethos. It’s the only one that explicitly ships file-on-disk identity plus an import/cascade system.
1.1 Where identity/persona lives
Section titled “1.1 Where identity/persona lives”A persistent agent’s identity is a Markdown file with YAML frontmatter, not a programmatic object.
For subagents (the canonical “named persona” pattern in Claude Code):
.claude/agents/<agent-name>.md # project scope~/.claude/agents/<agent-name>.md # user scope (all projects)Example file (https://code.claude.com/docs/en/sub-agents#write-subagent-files):
---name: code-reviewerdescription: Reviews code for quality and best practicestools: Read, Glob, Grepmodel: sonnet---
You are a code reviewer. When invoked, analyze the code and providespecific, actionable feedback on quality, security, and best practices.The Markdown body is the system prompt. The frontmatter is the runtime config. They live in one file because the docs treat the body and the config as a single unit of agent identity:
“The body becomes the system prompt that guides the subagent’s behavior. Subagents receive only this system prompt (plus basic environment details like working directory), not the full Claude Code system prompt.” — code.claude.com/docs/en/sub-agents
When the agent is the main session (not a subagent), identity lives in CLAUDE.md, which is additive context rather than a replacement system prompt:
“CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself.” — code.claude.com/docs/en/memory
Hierarchy precedence (https://code.claude.com/docs/en/memory#choose-where-to-put-claude-md-files):
| Scope | Path | Loaded |
|---|---|---|
| Managed policy | /Library/Application Support/ClaudeCode/CLAUDE.md (macOS), /etc/claude-code/CLAUDE.md, C:\Program Files\ClaudeCode\CLAUDE.md | All sessions on machine |
| Project | ./CLAUDE.md or ./.claude/CLAUDE.md | Project sessions |
| User | ~/.claude/CLAUDE.md | All your sessions |
| Local | ./CLAUDE.local.md (gitignored) | Just you, this project |
Subagent identity precedence (sub-agents doc, “Choose the subagent scope”):
1 (highest) Managed settings2 --agents CLI flag (session only, JSON)3 .claude/agents/ (project)4 ~/.claude/agents/ (user)5 (lowest) Plugin's agents/ directory1.2 Where runtime config lives
Section titled “1.2 Where runtime config lives”Runtime config (model, tools, hooks, MCP servers, permissions, memory scope) lives in the same file as the persona, in the YAML frontmatter.
Full subagent frontmatter spec (https://code.claude.com/docs/en/sub-agents#supported-frontmatter-fields):
---name: code-reviewer # required, lowercase + hyphensdescription: ... # required, when to delegatetools: Read, Grep, Glob # allowlistdisallowedTools: Write, Edit # denylistmodel: sonnet | opus | haiku | claude-opus-4-7 | inheritpermissionMode: default|acceptEdits|auto|dontAsk|bypassPermissions|planmaxTurns: 10skills: [api-conventions, error-handling-patterns] # preloadedmcpServers: - playwright: type: stdio command: npx args: ["-y", "@playwright/mcp@latest"] - github # reference to already-configured serverhooks: PreToolUse: - matcher: "Bash" hooks: - type: command command: "./scripts/validate.sh"memory: user | project | local # enables ~/.claude/agent-memory/<name>/background: falseeffort: low|medium|high|xhigh|maxisolation: worktree # spawn in temp git worktreecolor: blueinitialPrompt: "Auto-submitted as first turn"---Settings that are environment-wide (not per-agent) live separately in
settings.json files. Precedence is the standard Claude Code layered model:
managed > user > project > local. From
https://code.claude.com/docs/en/memory#manage-claude-md-for-large-teams,
settings handle “technical enforcement” while CLAUDE.md handles “behavioral
guidance”:
| Concern | Lives in |
|---|---|
| Block tools / commands / file paths | settings.json permissions.deny |
| Sandbox isolation | settings.json sandbox.enabled |
| Env vars and API routing | settings.json env |
| Behavioral instructions for Claude | CLAUDE.md |
| Code style and quality guidelines | CLAUDE.md |
1.3 Same file or separated?
Section titled “1.3 Same file or separated?”For named subagents: same file. Frontmatter (config) + body (persona)
are atomic. The docs don’t split them, and the /agents interactive UI
treats them as one editable unit.
For the main session / persistent agent identity: split. CLAUDE.md
carries persona-ish content (rules, conventions, project memory), while
settings.json carries runtime enforcement (permissions, sandbox, hooks,
env). The docs draw a hard line:
“Settings rules are enforced by the client regardless of what Claude decides to do. CLAUDE.md instructions shape Claude’s behavior but are not a hard enforcement layer.” — code.claude.com/docs/en/memory
Reasoning given: “behavioral guidance” is interpretive (loaded as a user message), while “technical enforcement” must be deterministic (loaded by the harness, not the model). Splitting them prevents an agent from talking itself out of a hard rule.
1.4 Composition / shared ethos
Section titled “1.4 Composition / shared ethos”Claude Code has explicit support for shared-doctrine-plus-specialization via two mechanisms:
Mechanism A — @path imports inside CLAUDE.md
(https://code.claude.com/docs/en/memory#import-additional-files):
“CLAUDE.md files can import additional files using
@path/to/importsyntax. Imported files are expanded and loaded into context at launch alongside the CLAUDE.md that references them. Both relative and absolute paths are allowed. Relative paths resolve relative to the file containing the import, not the working directory. Imported files can recursively import other files, with a maximum depth of five hops.”
Example pattern:
# Per-agent CLAUDE.md@~/.claude/docs/fleet-ethos.md@~/.claude/docs/fleet-source-order.md@./persona.md
## Agent-specific overrides...This is exactly how Wes’s fleet already composes ethos + persona, and the docs sanction it.
Mechanism B — directory cascade (https://code.claude.com/docs/en/memory#how-claude-md-files-load):
“Claude Code reads CLAUDE.md files by walking up the directory tree from your current working directory, checking each directory along the way for
CLAUDE.mdandCLAUDE.local.mdfiles. … All discovered files are concatenated into context rather than overriding each other. Across the directory tree, content is ordered from the filesystem root down to your working directory.”
Order: root-most → cwd-most → CLAUDE.local.md last. Concatenation, not
override. So a fleet-wide CLAUDE.md at ~/.claude/CLAUDE.md gets
concatenated with <project>/.claude/CLAUDE.md and <project>/CLAUDE.md
automatically — no explicit imports needed if the path tree is right.
Subagents can preload skills via the skills: frontmatter field
(https://code.claude.com/docs/en/sub-agents#preload-skills-into-subagents):
“The full content of each listed skill is injected into the subagent’s context at startup.”
This is “explicit inheritance” — the subagent declares which shared knowledge packets it wants at boot, by name.
.claude/rules/ is a third compositional layer for path-scoped
instructions:
your-project/├── .claude/│ ├── CLAUDE.md│ └── rules/│ ├── code-style.md│ ├── testing.md # frontmatter: paths: ["**/*.test.ts"]│ └── security.mdRules with no paths: frontmatter load always; rules with paths: load
only when Claude reads matching files. Same priority as .claude/CLAUDE.md.
Source: https://code.claude.com/docs/en/memory#organize-rules-with-claude/rules/.
1.5 Shared knowledge vs agent-local state
Section titled “1.5 Shared knowledge vs agent-local state”Claude Code has three distinct storage tiers with explicit boundaries:
| Tier | Location | What it’s for | Survives |
|---|---|---|---|
| Project memory | <repo>/CLAUDE.md, .claude/rules/*.md | Team-shared standards | Git |
| User memory | ~/.claude/CLAUDE.md, ~/.claude/rules/*.md | Personal prefs across projects | Just user |
| Auto memory (per-project) | ~/.claude/projects/<project>/memory/MEMORY.md | Claude-written learnings, repo-scoped | Local only |
| Subagent memory | ~/.claude/agent-memory/<name>/ (user), .claude/agent-memory/<name>/ (project), .claude/agent-memory-local/<name>/ (local) | Agent’s own accumulated knowledge | Per scope |
| Session transcript | ~/.claude/projects/<project>/<sessionId>/subagents/agent-<agentId>.jsonl | Subagent conversation history | 30 days default |
Quote on the boundary (https://code.claude.com/docs/en/sub-agents#enable-persistent-memory):
“
projectis the recommended default scope. It makes subagent knowledge shareable via version control. Useuserwhen the subagent’s knowledge is broadly applicable across projects, orlocalwhen the knowledge should not be checked into version control.”
MEMORY.md is treated as an index — first 200 lines / 25KB load at
session start, topic files load on demand. Topic files (debugging.md,
api-conventions.md, etc.) are read by the agent when needed using
standard file tools. There’s no separate vector store or RAG layer in the
default architecture — it’s just filesystem + structured loading rules.
1.6 Recommended folder structure
Section titled “1.6 Recommended folder structure”Synthesized from the docs:
<project-root>/├── CLAUDE.md # project context (alt: .claude/CLAUDE.md)├── CLAUDE.local.md # gitignored personal overrides├── .claude/│ ├── CLAUDE.md # alternative location for project memory│ ├── settings.json # technical enforcement (committed)│ ├── settings.local.json # local overrides (gitignored)│ ├── agents/│ │ ├── code-reviewer.md # named subagent│ │ ├── debugger.md│ │ └── researcher.md│ ├── skills/│ │ ├── deploy/│ │ │ ├── SKILL.md # always required│ │ │ ├── scripts/│ │ │ └── references/│ │ └── pdf-processing/│ │ └── SKILL.md│ ├── commands/ # legacy; merged into skills│ ├── rules/│ │ ├── code-style.md│ │ ├── testing.md # frontmatter: paths: ["**/*.test.ts"]│ │ └── security.md│ ├── hooks/│ ├── agent-memory/ # project-scope, committed│ │ └── code-reviewer/│ │ └── MEMORY.md│ └── agent-memory-local/ # local-only, gitignored└── .mcp.json # MCP server configs
~/.claude/ # user-level scope├── CLAUDE.md├── settings.json├── agents/├── skills/├── rules/├── output-styles/├── projects/<project>/memory/ # auto memory per repo│ ├── MEMORY.md│ ├── debugging.md│ └── api-conventions.md├── agent-memory/<agent-name>/ # user-scope subagent memory└── plugins/
<plugin>/├── .claude-plugin/│ └── plugin.json # ONLY plugin.json here├── skills/<name>/SKILL.md├── agents/├── commands/ # legacy flat .md files├── hooks/hooks.json├── monitors/monitors.json├── .mcp.json├── .lsp.json├── bin/└── settings.jsonSource: https://code.claude.com/docs/en/plugins. Explicit warning:
“Common mistake: Don’t put
commands/,agents/,skills/, orhooks/inside the.claude-plugin/directory. Onlyplugin.jsongoes inside.claude-plugin/. All other directories must be at the plugin root level.”
2. Anthropic Claude Agent SDK (Python + TypeScript)
Section titled “2. Anthropic Claude Agent SDK (Python + TypeScript)”The SDK is “Claude Code as a library.” It does not invent its own layout — it reads Claude Code’s filesystem conventions. Same files, same hierarchy, but you can also pass config programmatically.
Source: https://code.claude.com/docs/en/agent-sdk/overview
2.1 Where identity/persona lives
Section titled “2.1 Where identity/persona lives”Two paths:
Filesystem (preferred for persistent agents):
Same as Claude Code — CLAUDE.md, .claude/agents/*.md, .claude/skills/*/SKILL.md.
“The SDK also supports Claude Code’s filesystem-based configuration. With default options the SDK loads these from
.claude/in your working directory and~/.claude/. To restrict which sources load, setsetting_sources(Python) orsettingSources(TypeScript) in your options.”
Mapping table (verbatim from the overview):
| Feature | Location |
|---|---|
| Skills | .claude/skills/*/SKILL.md |
| Slash commands | .claude/commands/*.md |
| Memory | CLAUDE.md or .claude/CLAUDE.md |
| Plugins | Programmatic via plugins option |
Programmatic (for ephemeral / per-call agents):
# from code.claude.com/docs/en/agent-sdk/overviewagents={ "code-reviewer": AgentDefinition( description="Expert code reviewer for quality and security reviews.", prompt="Analyze code quality and suggest improvements.", tools=["Read", "Glob", "Grep"], )}AgentDefinition takes a prompt (the persona body), description, and
tools. Identical shape to the on-disk frontmatter + body, just in code.
2.2 Where runtime config lives
Section titled “2.2 Where runtime config lives”ClaudeAgentOptions (Python) / options object (TypeScript) carries the
runtime config:
ClaudeAgentOptions( cwd="/path/to/project", setting_sources=["user", "project"], # which filesystem layers to load skills="all", # or ["pdf", "docx"] or [] allowed_tools=["Read", "Write", "Bash"], disallowed_tools=..., permission_mode="acceptEdits", hooks={"PostToolUse": [HookMatcher(matcher="Edit|Write", hooks=[...])]}, mcp_servers={"playwright": {"command": "npx", "args": [...]}}, system_prompt={"type": "preset", "preset": "claude_code", "append": "..."}, resume=session_id, agents={...},)For persistent named agents on disk, runtime config lives in the agent file’s frontmatter (same as Claude Code). For programmatic spawns, it lives in code.
2.3 Same file or separated?
Section titled “2.3 Same file or separated?”For filesystem agents: same file (frontmatter + body). For programmatic agents: passed inline as code; no file required.
The SDK explicitly does not provide a programmatic API for skills:
“Unlike subagents (which can be defined programmatically), Skills must be created as filesystem artifacts. The SDK does not provide a programmatic API for registering Skills.” — code.claude.com/docs/en/agent-sdk/skills
2.4 Composition / shared ethos
Section titled “2.4 Composition / shared ethos”Three composition mechanisms via system_prompt
(https://code.claude.com/docs/en/agent-sdk/modifying-system-prompts):
# 1. Minimal default (no preset) — SDK uses tiny system promptClaudeAgentOptions()
# 2. Claude Code preset (full system prompt + tools + env context)ClaudeAgentOptions( system_prompt={"type": "preset", "preset": "claude_code"})
# 3. Preset + append (preserves built-ins, adds custom)ClaudeAgentOptions( system_prompt={ "type": "preset", "preset": "claude_code", "append": "Always include detailed docstrings." })
# 4. Full custom string (replaces everything)ClaudeAgentOptions(system_prompt="You are a Python specialist...")Plus the on-disk @-imports and CLAUDE.md cascade still work when
setting_sources includes project and user.
Cache-friendly fleet pattern: excludeDynamicSections: true makes the
preset static (moves cwd/git/date into the first user message) so a fleet
of agents in different directories can share a cached system prompt:
ClaudeAgentOptions( system_prompt={ "type": "preset", "preset": "claude_code", "append": "You operate Acme's internal triage workflow...", "exclude_dynamic_sections": True, })Tradeoff named in the docs: “Instructions in the user message carry marginally less weight than the same text in the system prompt.”
2.5 Shared knowledge vs agent-local state
Section titled “2.5 Shared knowledge vs agent-local state”Filesystem-driven, same tiers as Claude Code (Section 1.5). The SDK also exposes session state explicitly:
“Session state: JSONL on your filesystem” (per the Agent SDK vs Managed Agents comparison).
Sessions can be resumed by ID:
ClaudeAgentOptions(resume=session_id)2.6 Recommended folder structure
Section titled “2.6 Recommended folder structure”Identical to Claude Code (Section 1.6). The SDK is the same harness with a programmatic entry point.
3. Agent Skills (open standard — agentskills.io)
Section titled “3. Agent Skills (open standard — agentskills.io)”Skills are the atomic unit of shared capability — a portable folder of instructions + assets that any compatible agent can load.
Source: https://agentskills.io/specification
3.1 Identity / runtime config / shared knowledge / folder
Section titled “3.1 Identity / runtime config / shared knowledge / folder”Skills don’t have a “persona” — they’re capabilities, not agents. But the SKILL.md frontmatter answers the same design questions for capability packaging:
my-skill/├── SKILL.md # Required: metadata + instructions├── scripts/ # Optional: executable code├── references/ # Optional: documentation├── assets/ # Optional: templates, resources└── ...SKILL.md frontmatter spec (verbatim from agentskills.io/specification):
| Field | Required | Constraints |
|---|---|---|
name | Yes | Max 64 chars; lowercase + hyphens only; no leading/trailing/consecutive hyphens; must match parent directory name |
description | Yes | Max 1024 chars; what it does + when to use |
license | No | License name or bundled file ref |
compatibility | No | Max 500 chars; environment requirements |
metadata | No | Arbitrary key-value mapping |
allowed-tools | No | Space-separated pre-approved tools (experimental) |
The body is freeform Markdown. Recommended sections: step-by-step instructions, examples, common edge cases.
Progressive disclosure is the load model (verbatim):
“1. Metadata (~100 tokens): The name and description fields are loaded at startup for all skills 2. Instructions (< 5000 tokens recommended): The full SKILL.md body is loaded when the skill is activated 3. Resources (as needed): Files (e.g. those in scripts/, references/, or assets/) are loaded only when required
Keep your main SKILL.md under 500 lines. Move detailed reference material to separate files.”
This is the same three-tier “preview → activate → expand” pattern used by Claude Code skills internally.
Adoption: 30+ clients listed at agentskills.io including Claude Code, Claude.ai, Gemini CLI, Cursor, OpenAI Codex, GitHub Copilot, VS Code, Goose, OpenHands, Letta, Roo Code, Mistral Vibe. Originally developed by Anthropic, now an open standard.
4. OpenAI Assistants API (deprecated) / Responses API + Prompts
Section titled “4. OpenAI Assistants API (deprecated) / Responses API + Prompts”Important status: The Assistants API is deprecated, shutdown August 26, 2026, after feature parity with the Responses API. Don’t build new integrations on it. Source: https://developers.openai.com/api/docs/assistants/migration
I report both because the design tradeoffs are still instructive.
4.1 Where identity/persona lives
Section titled “4.1 Where identity/persona lives”Assistants API (legacy): persona lives in a server-stored object created via API. Not a file. Schema:
{ "name": "...", "instructions": "...", // up to 256,000 chars — the persona/system prompt "tools": [...], "model": "gpt-4o", "tool_resources": {...}, // file_search, code_interpreter resources "metadata": {...}}Source: search result via developers.openai.com (legacy schema).
Persistence model is database-as-source-of-truth: the assistant lives in OpenAI’s backend, identified by an opaque ID. No filesystem convention.
Responses API + Prompts (current):
“Prompts can only be created in the dashboard, where you can version them as you develop your product. Using prompts, every Responses or Realtime session you start inherits a consistent contract because prompts encapsulate tool schemas and structured output expectations.”
Persona is now a versioned dashboard artifact, referenced by stable ID at runtime. Still not a file in your repo — it’s in OpenAI’s dashboard.
4.2 Where runtime config lives
Section titled “4.2 Where runtime config lives”Same object. Tools, model, tool_resources, and instructions are all fields on the assistant (or prompt). Nothing is split across files.
4.3 Same file or separated?
Section titled “4.3 Same file or separated?”There is no file. Everything is one server-side object. The migration guide explicitly frames this as the problem they’re solving:
“Assistants bundled configuration into API objects, while Responses API separates concerns.”
Post-migration: prompts handle the “behavioral profile”; conversations handle the streamed message/tool-call state; application code handles orchestration. Three concerns, three places — but none of those places are files in your repo.
4.4 Composition / shared ethos
Section titled “4.4 Composition / shared ethos”No native @-import or inheritance. The 256k-char instruction field is flat text. If you want shared ethos across many assistants, you concatenate it yourself in code or in the dashboard.
The Responses API improves this slightly with versioned prompts that can be referenced by ID — so you can have one “shared ethos prompt” and other specialist prompts in the dashboard — but the composition is still done at the application layer, not declaratively.
4.5 Shared knowledge vs agent-local state
Section titled “4.5 Shared knowledge vs agent-local state”- Shared knowledge:
tool_resources.file_searchattaches files to a vector store; the assistant retrieves on demand. This is the canonical RAG path. Files live in OpenAI’s storage, not your repo. - Per-thread state: Conversations/threads store messages and tool calls server-side, retrievable by ID.
- Local state: Nothing. Your application owns any local cache.
4.6 Recommended folder structure
Section titled “4.6 Recommended folder structure”The docs don’t recommend one. There is no “OpenAI Assistant project layout” guide — assistants are server-side objects, so the layout is whatever your application code wants. The Assistants API deep-dive page treats this as a code-organization-is-your-problem matter.
5. OpenAI Agents SDK (Python)
Section titled “5. OpenAI Agents SDK (Python)”Source: https://openai.github.io/openai-agents-python/
5.1 Where identity/persona lives
Section titled “5.1 Where identity/persona lives”In code, as a Python object. No filesystem convention.
from agents import Agent, function_tool
@function_tooldef get_weather(city: str) -> str: return f"The weather in {city} is sunny"
agent = Agent( name="Weather Assistant", instructions="Help with weather queries", model="gpt-4", tools=[get_weather])Agent parameters (from the Agents page):
| Parameter | Required | Purpose |
|---|---|---|
name | Yes | Human-readable identifier |
instructions | Yes | System prompt (string or callable) |
model | No | Which LLM to use |
tools | No | Capabilities the agent can invoke |
handoffs | No | Specialist agents to delegate to |
output_type | No | Structured output format |
model_settings | No | Temperature, etc. |
input_guardrails / output_guardrails | No | Validation checks |
instructions can be a callable, not just a string:
def dynamic_instructions(context, agent) -> str: return f"The user's name is {context.context.name}..."
agent = Agent(instructions=dynamic_instructions)This is the only framework studied where the persona is allowed to be a function of runtime context.
5.2 Where runtime config lives
Section titled “5.2 Where runtime config lives”Same Python object. Everything is constructor args. No frontmatter, no config files.
5.3 Same file or separated?
Section titled “5.3 Same file or separated?”There is no file. Identity and config are one Python object, instantiated in code.
5.4 Composition / shared ethos
Section titled “5.4 Composition / shared ethos”No declarative composition. Two patterns recommended in the docs:
- Agents as Tools: A manager agent calls specialist agents via
Agent.as_tool(). - Handoffs: A triage agent routes to specialists who become active.
“Use built-in language features to orchestrate and chain agents, rather than needing to learn new abstractions.”
Translation: there is no inheritance system. If you want shared ethos,
you compose Python strings, share a Python module of common instruction
text, or wrap Agent(...) calls in a factory function. The SDK is
explicitly Python-first, no DSL.
5.5 Shared knowledge vs agent-local state
Section titled “5.5 Shared knowledge vs agent-local state”- Context: A typed object passed to
Runner.run(), threaded through every agent, tool, and handoff. Dependency injection pattern. Agents are generic on context type:Agent[UserContext](...). - Sessions: “A persistent memory layer for maintaining working context within an agent loop.”
No filesystem layer. State is whatever your Python objects hold.
5.6 Recommended folder structure
Section titled “5.6 Recommended folder structure”The docs do not specify one. From WebFetch summary:
“The OpenAI Agents SDK does not specify a recommended file/folder layout. The documentation focuses on functional capabilities rather than project structure conventions. The framework prioritizes flexibility over prescriptive architecture, allowing developers to organize code according to their specific needs.”
This is a deliberate non-decision. It cuts both ways: full freedom for the developer, zero guidance on how to scale to 18 agents.
6. Comparison Table — Framework × Design Question
Section titled “6. Comparison Table — Framework × Design Question”| Question | Claude Code | Claude Agent SDK | Agent Skills (open) | OpenAI Assistants | OpenAI Agents SDK |
|---|---|---|---|---|---|
| Persona lives in | .md file body (subagent) or CLAUDE.md (main session) | Same file as Claude Code, OR AgentDefinition.prompt in code | N/A (skills are capabilities, not personas) | instructions field on server-stored object | instructions param on Agent(...) Python object |
| Runtime config lives in | YAML frontmatter (same file) + settings.json (separate, for enforcement) | Frontmatter for file agents; ClaudeAgentOptions(...) for programmatic | SKILL.md frontmatter | Same server-stored object | Same Agent(...) constructor |
| Same file or split? | Persona + config: same file. Enforcement settings: separate file | Same file for filesystem agents; one object for code agents | Same file (frontmatter + body) | Single object, no files | Single Python object |
| Composition | @path imports (max 5 hops) + directory cascade (concatenate root→cwd) + skills: preload + .claude/rules/ | Same filesystem mechanisms + system_prompt.append + presets | None (skill = atomic unit) | None native; concatenate in app code | None native; Python factory functions |
| Shared knowledge vs agent-local | 5 tiers: project CLAUDE.md (git), user CLAUDE.md (machine), auto-memory (per-repo, local), subagent memory (user/project/local scopes), session jsonl | Same 5 tiers | Skill body + references/ + assets/ | Vector store via tool_resources.file_search; threads for state | Typed context object, Sessions for working memory |
| Folder structure | .claude/{agents,skills,rules,commands,hooks,agent-memory}/ + CLAUDE.md + .mcp.json + settings.json | Same as Claude Code | <skill-name>/{SKILL.md, scripts/, references/, assets/} | Not specified | Not specified |
| Identity precedence | managed > CLI flag > project > user > plugin | Same | N/A | N/A | N/A |
| Discoverability | Walk dir tree; load CLAUDE.md/rules at start; skills load metadata at start, body on activation | Same | Two-stage progressive disclosure | Server lists assistants by ID | Imports list in Python |
7. Patterns Worth Stealing (ranked)
Section titled “7. Patterns Worth Stealing (ranked)”#1 — Co-locate persona + runtime config in one file, separate enforcement settings
Section titled “#1 — Co-locate persona + runtime config in one file, separate enforcement settings”Why: Both Claude Code (for subagents) and Agent Skills do this. Frontmatter holds machine-readable config; body holds human-readable persona/ instructions. One file = one identity, atomically version-controlled, editable as a single unit. Enforcement settings (deny rules, sandbox, hooks) live separately because they must be deterministic and outside the model’s ability to argue with.
Concrete: <name>.md with YAML frontmatter for model/tools/hooks/memory
and Markdown body for persona/system prompt. settings.json next to it
for permissions/env.
#2 — @path imports with cascade (root → cwd) for shared ethos
Section titled “#2 — @path imports with cascade (root → cwd) for shared ethos”Why: Claude Code’s only declarative inheritance mechanism, and the one
already in production use here. Max 5 hops, relative-to-file, supports
~/. Combined with the directory walk (root-most loads first,
concatenated), this lets a fleet doctrine file at ~/.claude/docs/fleet- ethos.md be @-imported by every agent’s CLAUDE.md.
Antidote to: per-agent copy-pasted ethos that goes stale unevenly.
#3 — Progressive-disclosure skill packaging (SKILL.md + references/)
Section titled “#3 — Progressive-disclosure skill packaging (SKILL.md + references/)”Why: Industry standard now (Anthropic + 30+ adopters). Forces you to write a tight description (~100 tokens) that loads at start, a medium-length body (<5000 tokens) that loads on activation, and detailed references that load on demand. Keeps context budget small per agent while still allowing deep specialization. Naming convention enforces folder-name-equals-skill-name discipline.
#4 — Tiered memory: shared (project) / personal (user) / scratch (local)
Section titled “#4 — Tiered memory: shared (project) / personal (user) / scratch (local)”Why: Claude Code’s three-scope memory (project / user / local) maps
cleanly to “team canon, personal across projects, sandbox notes.” Each
scope has explicit git semantics: project is committed, user is per-
machine, local is gitignored. The same trichotomy applies to subagent
memory and rules.
#5 — Agent definitions discoverable by walking the filesystem
Section titled “#5 — Agent definitions discoverable by walking the filesystem”Why: No registry, no database, no central manifest. The agent harness
walks ~/.claude/agents/ and .claude/agents/, reads frontmatter, and
that’s the catalog. New agent = drop a file. Deprecated agent = delete
the file. Beats every database-of-assistants pattern for ops simplicity,
especially across 5 machines where sync is filesystem-based anyway.
#6 — Frontmatter paths: globs for path-scoped instructions
Section titled “#6 — Frontmatter paths: globs for path-scoped instructions”Why: .claude/rules/*.md with paths: ["src/api/**/*.ts"] means the
rule only enters context when relevant files are being read. Prevents
the “every CLAUDE.md gets fatter forever” failure mode. Direct analog:
specialty workers loading their domain pack only when invoked.
#7 — excludeDynamicSections: true for cross-machine cache reuse
Section titled “#7 — excludeDynamicSections: true for cross-machine cache reuse”Why: Specifically called out for fleet patterns — if you have many
agents that share an append block but run from different cwds, this
hoists per-session context (cwd, git, date) into the first user message
so the system prompt stays identical across machines. Real cost savings
on prompt cache hits. The tradeoff (slightly less authoritative env
context) is documented.
#8 — Callable instructions (OpenAI Agents SDK)
Section titled “#8 — Callable instructions (OpenAI Agents SDK)”Why: Only framework where instructions can be a function of context.
Useful for personalization or for switching tone based on who’s calling.
Stealable as a pattern even if your harness is filesystem-based: a tiny
templating layer over CLAUDE.md before injection.
8. Antipatterns observed
Section titled “8. Antipatterns observed”From Claude Code docs
Section titled “From Claude Code docs”- Don’t put
commands/,agents/,skills/,hooks/inside.claude-plugin/. Onlyplugin.jsongoes there. Source: https://code.claude.com/docs/en/plugins#plugin-structure-overview. - Don’t oversize CLAUDE.md. “Target under 200 lines per CLAUDE.md file. Longer files consume more context and reduce adherence.” Auto-memory has the same 200-line/25KB cap on MEMORY.md.
- Don’t expect imports to reduce context. “Splitting into
@pathimports helps organization but does not reduce context, since imported files load at launch.” - Don’t put long multi-step procedures in CLAUDE.md. “If an entry is a multi-step procedure or only matters for one part of the codebase, move it to a skill or a path-scoped rule instead.”
- Don’t expect contradictions to resolve. “If two rules contradict each other, Claude may pick one arbitrarily.” Implicit: declare a canonical doctrine file and prune contradictions.
- Don’t mistake CLAUDE.md for enforcement. “CLAUDE.md content is
delivered as a user message after the system prompt, not as part of
the system prompt itself. Claude reads it and tries to follow it, but
there’s no guarantee of strict compliance.” Use hooks or
permissionsfor hard rules. - Don’t put
--add-dirdirectories’ CLAUDE.md and agents/ in the load path by default. Skills are an explicit exception; subagents, commands, and output styles are not loaded from added dirs.
From Agent Skills spec
Section titled “From Agent Skills spec”- Don’t deeply nest references. “Keep file references one level deep from SKILL.md. Avoid deeply nested reference chains.”
- Don’t write vague descriptions. Spec gives a “poor example:
description: Helps with PDFs.” The good version includes specific keywords (PDFs, forms, document extraction) so the matcher can find it. - Skill name must match parent directory name. Hard validation rule.
From Agent SDK
Section titled “From Agent SDK”- Default minimal preset omits Claude Code’s behavioral guidelines.
If you want the full Claude Code system prompt (tool style, response
tone, safety), you must opt in:
system_prompt={"type": "preset", "preset": "claude_code"}. Easy to forget. - Custom string
system_promptloses default tools and safety instructions. “Built-in safety: Must be added.” setting_sources=[]disables filesystem loading entirely. Skills, CLAUDE.md, output styles all vanish. Recurring gotcha called out in the skills doc.- Subagents cannot spawn other subagents. No nested delegation. Workaround: chain subagents from the main conversation, or use skills.
From OpenAI Assistants / Responses API
Section titled “From OpenAI Assistants / Responses API”- The Assistants API itself is now an antipattern. Shut down 2026-08-26. Don’t start new builds on it.
- No native composition/inheritance. A flat 256k-char instructions field across many assistants creates copy-paste drift; the migration guide acknowledges this as motivation for the Prompts approach.
- Server-stored personas can’t be diffed in git. The migration guide explicitly cites “portability and versioning” as the new design goal because the old one didn’t have it.
From OpenAI Agents SDK
Section titled “From OpenAI Agents SDK”- No prescribed folder layout. This is a non-decision that punts the hard problem (organizing many agents) to the developer. For a fleet of 18 agents across 5 machines, this means inventing your own structure.
- No declarative shared-ethos mechanism. Composition is “use Python features” — fine for code, weaker for declarative team-shared rules. Every agent’s instructions string is independent text.
9. One-paragraph summary per framework
Section titled “9. One-paragraph summary per framework”- Claude Code: Identity and runtime config in one
.mdfile with YAML frontmatter; enforcement in separatesettings.json. Shared ethos via@pathimports (max 5 hops) and directory-walk cascade (root→cwd, concatenate). Three memory tiers (project/user/local). Subagents preload skills by name. Plugins package the same primitives for distribution. Filesystem is the database. - Claude Agent SDK: Same conventions as Claude Code (it’s the same
harness as a library), plus programmatic
AgentDefinitionfor ephemeral agents andsystem_prompt={preset, append, exclude_dynamic_ sections}for cache-friendly fleets.setting_sourcesdecides which filesystem layers load. - Agent Skills (open standard): Atomic capability folder with
required
SKILL.md(YAML frontmatter + Markdown), optionalscripts/,references/,assets/. Three-tier progressive disclosure (metadata → body → resources). 30+ vendor adoptees. Name must match parent directory. - OpenAI Assistants API: Deprecated; sunset 2026-08-26. Single server-stored object holds name, instructions, tools, model. No filesystem, no inheritance, no declarative composition. Replaced by Responses API + Prompts, which separates the behavioral profile from conversation state and orchestration.
- OpenAI Agents SDK: Python-first; agent is a constructor call
(
Agent(name, instructions, model, tools, handoffs, ...)); no prescribed folder layout; composition via Agents-as-Tools or Handoffs patterns at the code level;instructionscan be a callable (dynamic, context-aware persona).
10. Citations
Section titled “10. Citations”- Claude Agent SDK overview: https://code.claude.com/docs/en/agent-sdk/overview
- Modifying system prompts: https://code.claude.com/docs/en/agent-sdk/modifying-system-prompts
- Agent SDK skills: https://code.claude.com/docs/en/agent-sdk/skills
- Claude Code subagents: https://code.claude.com/docs/en/sub-agents
- Claude Code memory (CLAUDE.md): https://code.claude.com/docs/en/memory
- Claude Code skills: https://code.claude.com/docs/en/skills
- Claude Code plugins: https://code.claude.com/docs/en/plugins
- Agent Skills overview: https://agentskills.io/
- Agent Skills specification: https://agentskills.io/specification
- OpenAI Assistants migration guide: https://developers.openai.com/api/docs/assistants/migration
- OpenAI Assistants deep-dive: https://platform.openai.com/docs/assistants/deep-dive
- OpenAI Agents SDK (Python): https://openai.github.io/openai-agents-python/
- OpenAI Agents SDK — Agents page: https://openai.github.io/openai-agents-python/agents/
- OpenAI Agents SDK — Multi-agent: https://openai.github.io/openai-agents-python/multi_agent/
- Anthropic claude-agent-sdk-demos (example agents): https://github.com/anthropics/claude-agent-sdk-demos