Migrating Pi To Pydantic AI
PydanticOfficialPublished by Pydantic
- Skill
- Workflow
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured methodology for porting TypeScript-based Pi coding agents to Python. It emphasizes preserving observable behavior rather than replicating the original API, guiding developers to decompose complex Pi extensions into modular Pydantic AI capabilities, application-level services, and focused Harness components. The process focuses on tracing existing execution paths, mapping responsibilities to appropriate architectural seams, and verifying parity through rigorous contract testing.
What it does
- Provides a step-by-step process for tracing and characterizing existing Pi agent behavior.
- Offers a decision framework for mapping Pi extensions to Pydantic AI capabilities or application logic.
- Defines strategies for handling complex Pi features like session management, compaction, and tool guardrails.
- Includes guidance on separating agent-loop logic from host-level infrastructure like CLI, TUI, and RPC.
- Establishes a verification process using contract ledgers and language-neutral fixtures.
- Outlines high-risk gates for managing trusted host context and security boundaries.
When to use it
- When migrating an existing TypeScript Pi coding-agent application to a Python-based Pydantic AI architecture.
- When refactoring Pi extensions into reusable Pydantic AI capabilities.
- When you need to maintain parity with existing agent workflows while adopting the Pydantic AI ecosystem.
- When you need to audit and split mixed-responsibility extensions into distinct agent and application components.
Advantages
- Ensures architectural alignment with Pydantic AI best practices.
- Reduces technical debt by decoupling agent behavior from host-specific implementation details.
- Provides a clear path for verifying migration success through contract-based testing.
- Promotes a modular design by separating agent capabilities from application infrastructure.
Usage examples
- “How do I migrate a Pi extension that handles both tool registration and terminal UI rendering?”
- The skill instructs you to split the extension: move the tool registration logic to a Pydantic AI capability and retain the terminal UI rendering within your application's interface layer.
- “What is the recommended approach for handling existing Pi session JSONL files during migration?”
- The skill advises evaluating whether to perform a data conversion, implement a compatibility reader, or treat the migration as a fresh start, while testing the chosen path against your specific requirements.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/pydantic/migrating-pi-to-pydantic-ai/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip migrating-pi-to-pydantic-ai.zip -d .agents/skills
Documentation by Pydantic
Migrate Pi to Pydantic AI
Preserve observable behavior, not Pi's TypeScript API. Migrate the smallest complete caller path and keep product/host infrastructure in the application.
Trace the source before choosing a target
Read repository instructions,
package.json, Pi settings, tests, extension/package manifests, and runtime entrypoints. Record the installed Pi, Pydantic AI, and Harness versions.Trace one real request from the Pi CLI, RPC boundary, or
createAgentSession().prompt()through resource discovery, system instructions, tools, extensions, model requests, messages, compaction/retry, events, session entries, UI/RPC output, and side effects. Establish a focused baseline or characterization test.Inventory every active extension factory and package resource. For each
pi.on(...),registerTool,registerCommand, provider registration, renderer/UI contribution, skill, prompt, and persisted entry, record its firing point, trusted inputs, mutations, output, state owner, and caller-visible effect.Separate these contracts when present:
model messages, append-only session entries/tree branches, compaction summaries, and extension state;
model-chosen tool input, trusted host context, project trust, approval, authorization, and OS isolation;
token deltas, tool lifecycle, Pi extension events, capability events, RPC events, and terminal rendering;
agent-loop behavior, CLI/TUI host behavior, provider transport, package distribution, and external side effects.
Record each observed contract, its owner, semantic difference, and executable proof. An installed but inactive Pi package feature is not migration scope.
Read Research and concept mapping for the detected features. Read Verification and cutover before implementation.
Treat extensions as capability candidates
A Pi extension is the closest source concept to a Pydantic AI capability, but it is broader. An extension can combine agent behavior with terminal UI, commands, provider registration, resource discovery, and host lifecycle. Port responsibilities, not the extension file:
Map reusable model-facing behavior—tools, instructions, model settings, history/event processing, guardrails, and agent-loop hooks—to an existing Core or Harness capability when its lifecycle matches.
Bundle related instructions and tools in core
Capability; subclassAbstractCapabilityonly for reusable behavior that needs lifecycle hooks, adaptive models/settings, native tools, or typed capability events.Keep CLI commands, flags, keyboard shortcuts, TUI renderers/dialogs, session selection, project trust, package installation, and provider credential setup in the Python application or interface adapter. They are not agent capabilities merely because a Pi extension owns them.
Split mixed extensions at that seam. A permission extension may become a
ToolGuardrailor approval capability plus an application-owned approver UI; a coding package may becomeCoderplus host configuration; a provider extension remains a model/provider integration.Preserve order only where evidence shows it matters. Pi handler load order and Pydantic AI capability/hook ordering are different contracts.
Choose the smallest target
Core: use
pydantic_ai.Agentfor the agent loop, typed dependencies, tools/toolsets, outputs, normalized messages, capabilities/hooks, streaming, approvals, usage limits, instrumentation, MCP, and provider/model integration.Harness: use
Coderfor Pi's ordinary coding tools only when its exact composition fits. Add focused capabilities such asFileSystem,Shell,Skills,Planning,SubAgents, guardrails, compaction, tool-output limits, or step persistence only for observed behavior.Application/interface: retain or replace CLI/TUI/RPC, auth, project trust, settings, provider login/catalogs, session browsing, package management, deployment, and transport deliberately.
Graph: use plain async Python or
pydantic_graphfor deterministic workflows; do not encode them in prompts or subagents.Gap: name behavior with no supported public seam, explain its impact, and test a bounded adapter. Do not clone Pi's extension bus or JSONL format just to claim parity.
The normal embedded migration is one reusable Agent, Coder or a smaller capability composition, application services in typed dependencies, an application-owned message/session store, and a thin adapter at the existing RPC or UI boundary.
Apply high-risk gates
ctx, project trust, credentials, session managers, and service handles are trusted host context. Put equivalents in typed dependencies or application services, never model-chosen tool arguments.Pi session JSONL is an append-only branching host log containing more than model context.
result.all_messages()preserves model history, not tree navigation, labels, extension entries, compaction records, model changes, queues, or abandoned branches. Choose and test conversion, a compatibility store, or an accepted fresh start.Pi compaction, context interception, steering/follow-up queues, retries, and branch summaries have specific timing. Select matching core/Harness seams independently and test ordering; generic message history or summarization is not automatic parity.
Map
tool_callpermission gates by effect. Use guardrails for validation/block/redaction and deferred tools for an action that must await approval. Keep identity, authorization, UI, audit, persistence, and idempotency in the application.Pi extensions run arbitrary TypeScript with host permissions. A Pydantic AI capability also runs application code; neither is a sandbox. Use an OS/container/cloud isolation boundary for untrusted commands or code.
Harness
Skillsloads configuredSKILL.mdinstructions on demand but does not reproduce Pi's discovery roots, resource files, scripts, reload, package installation, or behavioral frontmatter. Preserve those separately when observed.Use
SubAgentsonly for model-directed isolated tasks. Keep deterministic orchestration and Pi subprocess/tmux/package-specific semantics in application code.Map dynamic tool activation to core
ToolSearchor on-demand capabilities only after testing load timing, schemas, prompt/cache changes, and provider fallback behavior.Pydantic AI run events and capability events do not reproduce Pi's extension event bus, RPC protocol, or TUI render lifecycle. Adapt only stable fields consumers use.
Pi provider extensions and payload hooks may alter authentication, catalogs, wire payloads, headers, and streaming. Implement them at the Pydantic AI model/provider or application transport layer and run provider contract tests; do not hide them in a generic capability.
Implement and prove one vertical slice
Preserve the supported CLI, RPC, SDK, job, or UI boundary and replace only agent-owned internals.
Start with core plus the smallest coding capabilities. Add broader Harness behavior only after a traced contract requires it.
For each source extension, document the split: capability behavior, application/interface behavior, retained integration, and gap. Test each side through its real boundary.
Use language-neutral fixtures for RPC/events and persisted records. Test tool arguments/results, errors, event order, session continuation, UI decisions, and side effects. Use deterministic models offline; add focused recorded/live provider tests only for provider behavior.
Remove Pi packages, settings, Node runtime, or extension adapters only after no retained path needs them.
Explain consequential semantic changes before implementing them: state the Pi behavior, target behavior, caller impact, recommended choice, and remaining risk.
Completion
Apply the completion criterion in Verification and cutover. Label fake, recording, live-provider, terminal, restart, and sandbox evidence accurately.
Files
- ATTRIBUTION.mdAdded by AutoGineer871 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md8.3 KiB
- agents/openai.yaml350 B
- references/RESEARCH-AND-MAPPING.md12.1 KiB
- references/VERIFICATION-AND-CUTOVER.md7.1 KiB
references/RESEARCH-AND-MAPPING.md
Research and concept mapping
Use this reference conditionally after tracing the source path. It is a decision guide, not a requirement to reproduce the whole Pi host.
Primary documentation
Inspect installed versions before migrating because Pi, Pydantic AI, and Harness continue to evolve.
Pi: README, extensions, SDK, sessions, compaction, and skills.
Pydantic AI: agents, capabilities, custom capabilities, hooks, message history, and deferred tools.
Pydantic AI Harness: overview, Coder, skills, guardrails, subagents, and step persistence.
Pi is TypeScript and Pydantic AI is Python. Capture existing RPC, event, provider, and persisted-record boundaries with language-neutral fixtures and preserve field names with explicit adapters where required.
Extension-to-capability decision table
| Pi extension responsibility | Target owner and likely seam | What must be proved |
|---|---|---|
registerTool() with instructions and related policy | Core: typed function, Tool, toolset, or declarative Capability; Harness: existing focused capability when semantics match | Tool name/schema, guidance, validation, progress/result/error shape, cancellation, parallelism, output limits, and effects. |
| Reusable extension behavior spanning tools, instructions, and hooks | Core: custom AbstractCapability, optionally composed from smaller capabilities | Run binding, hook ordering, emitted typed capability events, state lifetime, errors, and composition with sibling capabilities. |
before_agent_start system-prompt injection | Core: static/dynamic instructions or a custom capability hook; Harness: SystemReminders for matching cache-safe reinjection | Exact firing frequency, trusted data interpolation, cache impact, and whether injected content persists in history. |
context message rewriting or custom compaction | Core: ProcessHistory; Core/Harness: a matching compaction strategy; Application: persisted summary/branch policy | Which messages are removed/mutated, summary boundary, retries, token thresholds, restore behavior, and visibility to callers. |
tool_call mutation/blocking | Core: tool preparation or toolset wrapper for schema/args; Harness: ToolGuardrail; Core: deferred approval for protected effects | Pre-validation vs post-validation timing, handler order, mutation revalidation, block reason, termination, authorization, and side effects. |
tool_result modification | Core: toolset wrapper or custom capability around the tool lifecycle; Harness: tool guardrail/output-limit capability where matching | Result content/details/error/usage, order, retries, persistence, stream events, and terminal behavior. |
| Model/message/tool lifecycle listeners | Core: Hooks, ProcessEventStream, @on_event, or capability events; Application: observability/event adapter | Event set and order, sync/async timing, listener errors, stream activation, cancellation, and public serialization. |
registerCommand, shortcuts, flags, dialogs, widgets, renderers, editor/footer/theme changes | Application/interface host, such as a custom CLI, web UI, ACP host, or retained Pi frontend | Command routing, input/output, keyboard behavior, mode fallbacks, accessibility, cancellation, and terminal snapshots where contractual. |
appendEntry, labels, session name, branch/tree navigation | Application: session/log/navigation model; Core: normalized messages only; Harness: StepPersistence only for matching run continuation | Append-only/tree behavior, stable IDs, branches, labels, abandoned history, extension data, restart, and migration of existing JSONL. |
sendMessage, sendUserMessage, steering, follow-up queues | Core: explicit run messages, RunContext.enqueue() from in-run tools/capabilities, or AgentRun.enqueue() from external drivers where lifecycle matches; Application: queue/session control | Delivery point, trigger behavior, expansion, concurrent input, retries/compaction interaction, order, and cancellation. |
registerProvider, model catalog/auth, payload/header hooks, custom streaming | Core/model integration or Application transport, not a generic capability by default | Credential precedence, refresh, model selection, request/response wire fixtures, usage, errors, abort, tool calls, and streaming. |
| Resource discovery and reload | Application: configuration/discovery/reload; Harness: construct selected capability/Skills instances per run/process | Search roots, precedence, trust, snapshots vs hot reload, diagnostics, and behavior for removed/changed resources. |
Pi package manifest and pi install | Distribution/Application: Python package exposing capabilities plus optional host adapters | Installed assets, dependency/extras boundary, enable/disable configuration, trust, version pin/update behavior, and wheel contents. |
| Project trust | Application security policy | Which files/code/settings load before and after trust, persistence of decisions, non-interactive behavior, and confirmation that trust is not a sandbox. |
| Shared extension event bus | Application event bus for host coordination; Core capability events only for typed agent-run coordination | Names, payloads, scope, listener order/errors, restart behavior, and whether events enter model/UI streams. |
Agent and runtime ownership map
| Observed Pi behavior | Target owner and likely seam | Focused proof |
|---|---|---|
createAgentSession().prompt() and final assistant message | Core: reusable Agent.run(); Application: result adapter | Assert public input/output/error, messages, usage/cost, tool effects, and model selection. |
| Pi's default read/write/edit/bash coding loop | Harness: Coder only when Coder's exact six-tool composition and unrestricted host shell match the required behavior; otherwise compose FileSystem, Shell, RepoContext, context controls, and custom tools | Compare exact tool schemas, edit semantics, cwd, ignores/protected paths, command allowlisting or rejection, truncation, process lifetime, environment, and cancellation. |
Pi AgentSession event subscription | Core: run_stream_events(), iter(), agent/capability/custom events; Application: event adapter | Golden-test only consumed event types/fields, order, reconstruction, usage, terminal detection, errors, and cancellation. |
| Pi session messages | Core: serialized ModelMessage history; Application: session ownership/store | Continue from real persisted records in a fresh process and test incomplete tool calls and cross-session isolation. |
| JSONL session tree, fork/clone/switch, compaction/branch entries, model/thinking changes | Application: explicit session format and navigation; Harness StepPersistence: only when agent run resume/fork semantics fit | Test every consumed record type, branch restoration, compaction context, stable cursors, crash recovery, and old-record migration. |
| Automatic retry and overflow compaction | Core/provider retry settings plus Core/Harness compaction and application loop policy | Assert triggering error classes, delay/limits, cancellation, failed-message handling, retry count, and context after compaction. |
Skills and /skill:name | Harness: Skills for configured SKILL.md instructions; Application: command/discovery layer and resources/scripts | Assert explicit library roots, selected catalog, instruction loading, missing resources, reload behavior, trust, and behavioral frontmatter differences. |
Dynamic tool loading via setActiveTools() | Core: ToolSearch, deferred Capability, or per-step tool preparation | Assert initial catalog, selection, next-request availability, removals, provider-native/fallback protocol, and prompt-cache effects. |
| Plan-mode extension | Harness: Planning when the model-owned plan lifecycle fits; Application: command/widget; otherwise custom capability/state | Assert plan ownership, updates, reminders, persistence, user edits, UI, and behavior across compaction/restart. |
| Subagent extension or spawned Pi process | Harness: SubAgents for model-directed isolated delegation; Application: subprocess orchestration when process/session semantics matter | Assert task input, tools/capabilities, history isolation, model choice, result/events, budgets, cancellation, errors, and recursion. |
| Permission/protected-path extension | Harness: guardrail and/or Core: approval; Application: trusted policy and approver UI | Exercise allow/block/approve/deny, symlink/path cases, identity, audit, and exactly-once protected effect. |
| Sandbox or SSH extension | Harness: FileSystem, Shell, or ModalSandbox; Application: selected remote/sandbox backend | Exercise filesystem/shell operations, cwd, network, credentials, timeouts, cleanup, and real containment against escapes. |
| Pi RPC or JSON mode | Application: preserve protocol with a Python adapter or intentionally adopt a Pydantic AI UI protocol | Run the same language-neutral request/event fixtures, including errors, mid-run input, abort, command listing, and session operations. |
| Pi TUI | Application/interface: retain Pi temporarily, build a host, use clai, ACP, web chat, or another adapter according to observed needs | Test only user-facing behavior in scope; capability parity does not prove terminal UI parity. |
| Pi skills/prompts/extensions/packages as one installable package | Python distribution: capabilities, skill assets, and host integration can ship together but remain separate runtime owners | Inspect wheel, import selected capabilities, discover skill assets explicitly, and test host startup without dev dependencies. |
| Telemetry and extension logging | Core: instrumentation/OpenTelemetry; optional Logfire; Application: existing backend and logs | Assert correlation, content/privacy, required spans/events, nested usage, retention, dashboards, and alerts before switching. |
Common plugin ports
Custom tool extension: start with a typed tool. Use a declarative
Capabilityonly when the tool and its instructions should travel together; subclass only if hooks or events are also required.Permission gate: separate policy evaluation, approval pause, and approver UI. Usually this is a guardrail or tool wrapper plus core deferred approval plus an application interface—not one monolithic capability.
Plan mode: use Harness
Planningfor model-owned plans, while slash commands and widgets remain interface code.Subagent package: use Harness
SubAgentsonly when Pi's subprocess/session behavior is not itself contractual.Coding/sandbox package: compare
Coderfirst, then compose smaller filesystem/shell/repo-context capabilities. Add a real sandbox independently when untrusted execution is in scope.Provider package: implement the model/provider transport and keep login/catalog UI in the host; do not route provider payload rewriting through an agent capability unless it is genuinely per-run policy.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Pydantic
- Publisher
- Pydantic (Official)
- Source
- pydantic/skills · skills/migrating-pi-to-pydantic-ai · commit 98f591c
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Also distributed in
- pydantic/skills
AutoGineer is not affiliated with or endorsed by Pydantic or Pydantic.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download migrating-pi-to-pydantic-ai.zip