Skip to content

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 Skills capability materializes skill files into a real sandbox filesystem. This only works inside the beta SandboxAgent layer.

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/, and scripts/ are not read or executed, and behavioral frontmatter fields (hooks, tools, shell, model, ...) are accepted but not implemented (a UserWarning is emitted).
  • No auto-discovery. Skills does 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 MCP capability; 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:

  1. Does the harness depend on executing skill scripts or assets in a real filesystem?
  2. Yes → OpenAI Agents SDK (SandboxAgent + sandbox Skills), accepting the beta sandbox layer as the dependency.
  3. No → continue.
  4. Do you need AGENTS.md/CLAUDE.md auto-loading and fine-grained hooks?
  5. Yes → Pydantic AI (Repo Context + Hooks + Skills capabilities), which preserves both with no sandbox.
  6. 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/