Migrating an Agent-CLI Harness to Pydantic AI or OpenAI Agents SDK
Research date: Aug 4, 2026. Every factual claim is cited inline to an official source (GitHub READMEs or official docs). This article answers one question: if you already run an interactive agent-CLI harness — skills, hooks, AGENTS.md — and you want to move it into a Python agent framework, which SDK should you pick, Pydantic AI or OpenAI Agents SDK? Companion note: shareable-agent-harness.md documents the four CLI harnesses and why skills/hooks/context files are not a portable ABI.
TL;DR
For migrating an existing agent-CLI harness, the deciding factor is how much of the harness must physically execute files in a workspace:
- Choose Pydantic AI when the harness is instruction-shaped — SKILL.md instruction loading, AGENTS.md/CLAUDE.md auto-loading, and fine-grained lifecycle hooks — because all three are first-class capabilities that work on any model with no sandbox runtime. This is the lower-friction, more faithful migration of a typical CLI harness.
- Choose OpenAI Agents SDK when the harness must execute — skills with bundled scripts/resources, or an isolated filesystem workspace — because its sandbox
Skillscapability materializes skill files into a real sandbox filesystem. This only works inside the betaSandboxAgentlayer.
Neither SDK implements the CLI-native hook contracts (Claude Code JSON/command hooks, Gemini CLI JSON stdin/stdout hooks, OpenCode plugin hooks). A thin adapter remains either way, exactly as the companion note concludes for cross-CLI sharing.
1. What you are migrating
An interactive agent-CLI harness (Claude Code, Codex CLI, OpenCode, Gemini CLI) consists of artifacts the CLI reads to steer the agent:
| Artifact | What it is | Examples of where it lives |
|---|---|---|
| Skills | SKILL.md packages: name, description, Markdown instructions, optional bundled references/, assets/, scripts/ |
.claude/skills/, .agents/skills/, .opencode/skills/, Gemini CLI extensions |
| Hooks | Deterministic event callbacks (session start/end, before/after tool, compaction) with client-specific contracts | Claude Code JSON/command hooks, Gemini CLI JSON-over-stdio, OpenCode plugins |
| Context files | Standing repository instructions read at session start | AGENTS.md, CLAUDE.md |
| Tools / MCP | Function tools and MCP servers the agent can call | MCP server configs |
The migration question is: for each artifact, what does the target SDK consume as-is, what must be rewritten, and what is lost? The per-artifact mapping below is the whole analysis.
2. AGENTS.md / repository context
Pydantic AI — native, closest to a drop-in. The Repo Context capability in pydantic-ai-harness "auto-loads repo context — CLAUDE.md/AGENTS.md and repository structure — so the agent starts a run already oriented in the project." (https://pydantic.dev/docs/ai/harness/) Your existing AGENTS.md/CLAUDE.md files keep working as-is; the framework injects them automatically.
OpenAI Agents SDK — none native, bring your own. The runtime does not read AGENTS.md. To preserve the behavior you must (a) stage the repo into the sandbox via a Manifest entry (GitRepo or LocalDir) and (b) restate standing rules in the agent's instructions (appended after the SDK sandbox base prompt) or replace the base prompt via base_instructions. (https://openai.github.io/openai-agents-python/sandbox/guide/)
Migration cost: Pydantic AI — near zero, keep the files. OpenAI — a rewrite of the rules into Python instructions, plus a Manifest for the workspace.
3. Skills (SKILL.md)
Both read the portable Agent Skills SKILL.md format; the difference is depth.
Pydantic AI — Skills capability, instructions only. Add pydantic-ai-harness[skills], point Skills('.agents/skills') at your existing skill library. At construction it scans immediate child directories, validates each SKILL.md, and creates one deferred capability per skill: the model sees name + description, then calls load_capability for the body. include/exclude filter the catalog. (https://pydantic.dev/docs/ai/harness/skills/)
Two migration caveats:
- Bundled files are not loaded.
references/,assets/, andscripts/are not read or executed, and behavioral frontmatter fields (hooks,tools,shell,model, ...) are accepted but not implemented (aUserWarningis emitted). - No auto-discovery.
Skillsdoes not search.agents,.claude, or your home directory — you must pass each library path explicitly.
OpenAI Agents SDK — sandbox Skills capability, filesystem-grounded. On SandboxAgent (beta), Skills "indexes and materializes skills into the sandbox for you" — skill files physically land in the workspace at skills_path (default .agents). Sources: lazy_from=LocalDirLazySkillSource(...) (large local dirs, model loads on demand), from_=LocalDir(...) (stage up front), or from_=GitRepo(repo=..., ref=...). Because files exist in the sandbox, bundled scripts/ and assets/ are usable by the filesystem and shell capabilities. (https://openai.github.io/openai-agents-python/sandbox/guide/)
Migration cost:
| Skills aspect | Pydantic AI | OpenAI Agents SDK |
|---|---|---|
| SKILL.md instructions | Reused as-is (deferred capability) | Reused as-is (materialized into sandbox) |
| Bundled scripts/assets | Lost — not loaded | Available in the sandbox workspace |
| Behavioral fields (hooks/tools/shell) | Ignored (warning) | N/A — skills are files, not interpreted |
| Runtime requirement | None (any model, no sandbox) | SandboxAgent + a sandbox client (beta) |
If your skills are pure instruction packages, Pydantic AI is the faithful migration. If your skills embed scripts your agents must run, only the OpenAI sandbox approach preserves them.
4. Hooks
Pydantic AI — a full lifecycle event bus. The Hooks capability registers callbacks via @hooks.on.<event> decorators (or constructor kwargs), with per-hook timeout, tool-name filtering on tool hooks, middleware-style wrap_* hooks, and raise-to-propagate / return-to-recover error hooks. (https://ai.pydantic.dev/hooks)
The CLI hook events map onto Pydantic events:
| CLI harness hook | Pydantic AI event |
|---|---|
| Session start / before prompt | before_run |
| Session end | after_run |
| Before / after tool | before_tool_execute / after_tool_execute |
| Tool argument validation | before_tool_validate / after_tool_validate |
| Context compaction | Compaction capability (harness) or prepare_tools |
| Streamed output | run_event_stream / per-event event |
OpenAI Agents SDK — a minimal observer API. Subclass RunHooks (run-wide, set on the runner) or AgentHooks (per-agent, set via agent.hooks) and override on_llm_start/on_llm_end, on_agent_start/on_agent_end, on_handoff, on_tool_start/on_tool_end. (https://openai.github.io/openai-agents-python/ref/lifecycle/)
Migration cost: Both require writing an adapter from your CLI's hook contract (Claude JSON/command hooks, Gemini JSON-over-stdio, OpenCode plugin hooks) to the SDK's Python callbacks — that contract is not portable, per the companion note. But Pydantic AI gives you the granularity to express most CLI behaviors (validation, middleware, retry/failure semantics, tool filtering) without fighting the API; OpenAI's hooks are sufficient for observability-style interception only.
5. What is not in scope / secondary considerations
These matter for the migration decision but are not the deciding factors for the harness question:
- Tools and MCP: both consume function tools and MCP servers (Pydantic
MCPcapability; OpenAI MCP server tools). Portable, no major cost. - Memory / sessions: OpenAI has ready-made session backends (SQLAlchemy, SQLite, Redis, MongoDB, encrypted). Pydantic offers comparable building blocks via harness capabilities (
Step Persistence,Memory) that you assemble. - Model support: if the harness must stay provider-agnostic (as the CLIs are), Pydantic AI's native multi-provider support is a real advantage over OpenAI's adapter-based third-party models. (https://ai.pydantic.dev/models/overview)
- Type safety: Pydantic AI's
Agent[Deps, Output]generics carry types through the run; OpenAI's tool schemas are Pydantic-based but the agent is not generic in the same way.
6. Decision
Answer in order:
- Does the harness depend on executing skill scripts or assets in a real filesystem?
- Yes → OpenAI Agents SDK (
SandboxAgent+ sandboxSkills), accepting the beta sandbox layer as the dependency. - No → continue.
- Do you need AGENTS.md/CLAUDE.md auto-loading and fine-grained hooks?
- Yes → Pydantic AI (
Repo Context+Hooks+Skillscapabilities), which preserves both with no sandbox. - Tie-breakers: provider-agnostic models and richer hook control favor Pydantic AI; pre-built session backends, an OpenAI-first stack, and workspace isolation favor OpenAI Agents SDK.
Either way, budget for a hook adapter: neither SDK speaks Claude Code, Gemini CLI, or OpenCode hook contracts, so that shim is the one piece of the harness that always needs rewriting.
References
- Pydantic AI GitHub: https://github.com/pydantic/pydantic-ai
- Pydantic AI Documentation: https://ai.pydantic.dev
- Pydantic AI Hooks: https://ai.pydantic.dev/hooks
- Pydantic AI Harness (Repo Context, Skills, and other capabilities): https://pydantic.dev/docs/ai/harness/
- Pydantic AI Harness — Skills: https://pydantic.dev/docs/ai/harness/skills/
- Pydantic AI Agent Specs: https://ai.pydantic.dev/agent-spec
- OpenAI Agents SDK GitHub: https://github.com/openai/openai-agents-python
- OpenAI Agents SDK Documentation: https://openai.github.io/openai-agents-python/
- OpenAI Agents SDK Lifecycle (hooks): https://openai.github.io/openai-agents-python/ref/lifecycle/
- OpenAI Agents SDK Sandbox agents: https://openai.github.io/openai-agents-python/sandbox_agents/
- OpenAI Agents SDK Sandbox concepts (skills): https://openai.github.io/openai-agents-python/sandbox/guide/
- Companion note — shareable harness: https://lagindicator.com/dev-tools/shareable-agent-harness/