Skip to content

Spec: v1 Python pi harness (core + TUI + coding CLI) #18

Description

@maozhen520

Parent

  • Handoff: #17
  • Map (decisions index): #1
  • Glossary: CONTEXT.md
  • Build order reminder: docs/agents/implementation-handoff.md

Problem Statement

Developers want a daily-driver interactive coding agent in Python that matches the semantics and extension model of earendil-works/pi, without depending on the TypeScript runtime or chasing full API/session-file parity. Today this repo has settled decisions and research notes but no runnable packages: no thin LLM adapter, no agent runtime, no TUI, and no piy CLI.

Solution

Ship a uv monorepo with four installable packages — pi_llm, pi_agent, pi_tui, pi_coding_agent — that together deliver:

  1. A thin LiteLLM-backed LLM adapter (OpenAI Chat Completions contract only).
  2. An agent runtime with a public loop + stateful Agent SDK surface.
  3. Built-in coding tools (read / write / edit / bash) and v1 extension discovery (skills, prompt templates, settings, trust, context files).
  4. Own-format session persistence with resume/branch/fork and compaction.
  5. A Textual interactive CLI (piy) wired from runtime events to widgets.

Behavior aligns with upstream where decisions say so; public APIs are idiomatic Python. Orchestrator/chat, themes/packages marketplace, print/JSON/RPC modes, OAuth, and built-in sandbox stay out of v1.

User Stories

  1. As a Python developer, I want a uv workspace with four packages and CI (ruff + typecheck + pytest), so that I can develop and merge package work safely.
  2. As an embedder, I want pi_llm to call models via LiteLLM acompletion with modern tools / tool_choice, so that I do not maintain a provider matrix.
  3. As a TUI user, I want streamed assistant tokens for UI updates, so that responses feel live.
  4. As the agent runtime, I want tool calls assembled fully before execution, so that tools run against complete arguments.
  5. As an operator, I want capability probes and OpenAI-mapped errors from pi_llm, so that unsupported features and auth failures are actionable.
  6. As a user, I want credentials resolved env-first then optional ~/.pi/agent/auth.json, so that CI and local setups both work.
  7. As an interactive piy user, I want a prompt-and-save path for missing keys, so that first-run setup does not require editing files by hand.
  8. As an SDK user, I want a pure agent loop I can drive myself, so that I can embed turn mechanics without the stateful facade.
  9. As an SDK user, I want a stateful Agent with prompt / continue / steer / follow_up, so that I can run multi-turn sessions from Python.
  10. As an SDK user, I want awaited subscribe as the event settlement barrier, so that my handler finishes before the runtime advances.
  11. As a subscriber, I want the full agent/turn/message/tool event set in a fixed order, so that UIs can update incrementally and deterministically.
  12. As an SDK user, I want AgentMessage in the transcript and LLM Message only at stream time, so that UI/custom roles never leak unprojected into the model.
  13. As an SDK user, I want transform_context / convert_to_llm hooks, so that I can reshape context before the model call.
  14. As an SDK user, I want to inject the stream function from pi_llm, so that the runtime stays provider-agnostic.
  15. As a tool author, I want before/after tool hooks under parallel or sequential batching, so that I can gate or observe tool execution.
  16. As a coding-agent user, I want built-in read with line windowing and truncation, so that large files do not blow the context.
  17. As a coding-agent user, I want built-in write for whole-file writes, so that create/overwrite is simple and reliable.
  18. As a coding-agent user, I want built-in edit with exact multi-replace edits[] and optional per-edit replace_all, so that surgical edits are deterministic.
  19. As a coding-agent user, I want edit to be all-or-nothing with uniqueness/non-overlap checks against the original file, so that partial/ambiguous edits fail closed.
  20. As a coding-agent user, I want edit and write to share a per-realpath queue, so that concurrent file mutations serialize safely.
  21. As a coding-agent user, I want soft guidance that the model read before edit, so that edits are grounded without hard-enforcing a protocol.
  22. As a coding-agent user, I want built-in bash with session cwd, optional timeout, and output truncation, so that shell work stays usable and bounded.
  23. As a coding-agent user, I want tool errors that are actionable for the model/UI without Python tracebacks, so that the agent can recover.
  24. As a coding-agent user, I want host process permissions (no built-in sandbox), so that v1 matches the upstream security stance.
  25. As a user, I want Skills discovered from ~/.pi/agent, trusted .pi, ~/.agents/skills, and ancestor .agents/skills, so that shared and project skills both appear.
  26. As a user, I want Skills as SKILL.md + YAML frontmatter directories listed in a catalog and readable on demand, so that prompts stay small until needed.
  27. As a user, I want Prompt Templates as non-recursive prompts/*.md expanded via /name with upstream-style placeholders, so that slash commands work familiarly.
  28. As a user, I want settings nested-merge from ~/.pi/agent/settings.json and .pi/settings.json, so that project overrides are predictable.
  29. As a user, I want v1 settings keys skills / prompts / defaultProjectTrust / enableSkillCommands (plus compaction reserve/keepRecent as decided), so that discovery and compaction are configurable.
  30. As a user, I want project trust gated via ~/.pi/agent/trust.json, so that untrusted project resources are not loaded silently.
  31. As an interactive user, I want to be asked about trust; as a non-interactive user, I want project resources skipped unless already trusted or --approve, so that automation stays safe by default.
  32. As a user, I want AGENTS.md / CLAUDE.md (and peers) walked from ancestors into <project_context>, so that the model sees repo guidance.
  33. As a user, I want sessions stored as own JSONL (header version + message tree) under ~/.pi/agent/sessions/<cwd-encoded>/, so that work is resumable per project.
  34. As a user, I want Session to own the file/branch pointer and Agent to own the live transcript, so that persistence and runtime stay cleanly separated.
  35. As a user, I want resume / list / branch / fork, so that I can continue or diverge conversations.
  36. As a user, I want auto compaction near the context window and manual /compact [instructions], so that long sessions keep working.
  37. As a user, I want compaction written as a JSONL compaction entry without rewriting away history, so that the file tree remains auditable.
  38. As a model consumer after compaction, I want summary + recent tail only, so that the prompt fits the window.
  39. As a TUI user, I want a scrollable transcript, streaming assistant text, tool-call display, and a multiline editor, so that interactive coding feels complete for v1.
  40. As a TUI user, I want widgets updated from agent runtime events (not raw LiteLLM streams), so that UI stays consistent with SDK semantics.
  41. As a package consumer, I want reusable Textual widgets/layouts in pi_tui and wiring/piy in pi_coding_agent, so that UI pieces stay reusable.
  42. As a CI maintainer, I want pytest with recorded LLM chunk fixtures and no required live LLM, so that merges do not depend on external APIs.
  43. As a CI maintainer, I want light Textual pilot tests, so that basic UI wiring regresses loudly without pixel goldens.
  44. As a developer, I want design alignment with upstream semantics without TypeScript API or session interchange, so that the Python API can stay idiomatic.

Implementation Decisions

  • Packages / layout: packages/pi_llm, packages/pi_agent, packages/pi_tui, packages/pi_coding_agent (src layout) in a uv workspace; CLI entrypoint piy from pi_coding_agent.
  • pi_llm: Depend only on LiteLLM’s OpenAI Chat Completions path (acompletion, modern tools/tool_choice). Stream for UI; assemble-then-execute for tools; capability probes; map errors to an OpenAI-shaped surface. No Proxy/Router/functions=/add_function_to_prompt. Credentials: env first, then optional ~/.pi/agent/auth.json. Resolution lives in pi_llm; interactive prompt-and-save UX lives in piy (not inside pi_llm).
  • pi_agent public surface: Dual export — pure agent loop + stateful Agent. Agent owns transcript/tools/queues; methods prompt / continue / steer / follow_up; no concurrent prompt. Awaited ordered subscribe is the settlement barrier. Full agent/turn/message/tool event sequence as researched upstream. AgentMessage vs LLM Message with projection only at stream time via transform_contextconvert_to_llm. Tool contract includes before/after hooks and parallel|sequential batching. Stream function injected from pi_llm.
  • Built-in tools (implemented in coding-agent, registered on Agent):
    • read: line window + truncation.
    • write: whole-file write.
    • edit: exact multi-replace edits[], optional per-edit replace_all; relative to original file; unique/non-overlapping; all-or-nothing; shares per-realpath queue with write; soft read-before-edit guidance; diff/patch may appear in details, not as the primary edit API.
    • bash: session cwd, optional timeout, output truncation, no sandbox; host permissions.
    • Errors: actionable messages; do not stuff Python tracebacks into model-facing tool results.
  • Extension surface (v1): registrable tools + Skills + Prompt Templates + settings/trust/context files. Themes and shareable Packages deferred.
  • Discovery roots: ~/.pi/agent/ and project .pi/ (project side behind trust); Skills also ~/.agents/skills/ and ancestor .agents/skills/; settings path arrays + CLI add/disable.
  • Skills / prompts on disk: Agent Skills-style directories (SKILL.md + YAML frontmatter); prompts non-recursive *.md, filename = /name, upstream-style placeholders.
  • Settings: nested merge of ~/.pi/agent/settings.json overlaid by .pi/settings.json. v1 recognized keys include skills, prompts, defaultProjectTrust, enableSkillCommands, plus compaction-related reserve/keepRecent overrides as decided.
  • Project trust: decisions in ~/.pi/agent/trust.json; interactive prompt; non-interactive default deny unless trusted or --approve.
  • Context files: per-directory prefer AGENTS.md else CLAUDE.md (and settled peers); ancestor walk → <project_context> in system prompt.
  • Session: own JSONL (version header + message tree) under ~/.pi/agent/sessions/<cwd-encoded>/. Session owns file + branch pointer; Agent owns transcript; coding-agent wires persistence. Capabilities: resume/list/branch/fork. No upstream session interchange.
  • Compaction: auto when approximate contextTokens > contextWindow - reserveTokens; keepRecentTokens for retained tail; manual /compact [instructions]; append compaction entry (do not rewrite away history); model context = summary + kept recent messages; branch summarization deferred.
  • pi_tui: Textual widgets/layouts for transcript, streaming assistant, tool display, editor. Event-driven incremental updates. No custom differential rendering engine; no themes in v1.
  • piy wiring: in pi_coding_agent; maps runtime events → widgets; owns auth prompt-and-save and trust prompts.
  • Suggested build order (from handoff): scaffold → pi_llmpi_agent → built-in tools → resources/settings/trust/context → session/compaction → pi_tui + piy wiring.
  • Research anchors: docs/research/upstream-agent-core.md, docs/research/upstream-coding-agent-extensibility.md, docs/research/litellm-streaming-tools.md, docs/research/edit-tool-designs.md.

Testing Decisions

  • What makes a good test: assert external behavior at package seams; do not lock internal file layout or private helpers. Prefer fakes/fixtures over live network.
  • Primary seams (approved):
    1. pi_llm stream boundary with recorded/handwritten chunks (no live API in CI).
    2. Agent / loop public surface with injected fake StreamFn — the thickest seam.
    3. Built-in tools against temporary directories.
    4. Resource discovery + settings/trust against fake HOME + project roots.
    5. Session + compaction against a temporary session tree.
    6. Light Textual pilots: inject runtime events, assert widget-facing updates (no pixel goldens).
    7. Thin piy integration (optional, few): fake LLM + temp dirs proving the interactive main path wires together.
  • Modules under test: each of the four packages; coding-agent owns tools/resources/session/piy wiring tests; pi_tui owns widget pilots.
  • CI bar: uv install/sync, ruff, typecheck, pytest. Live LLM not required to merge.
  • Prior art: none in-repo yet (greenfield); establish the pyramid with the first package tickets.

Out of Scope

  • Upstream orchestrator and pi-chat
  • Full multi-provider matrix à la pi-ai (aggregation library only)
  • TypeScript API parity / running against upstream TS packages
  • Reading/writing upstream session JSONL interchangeably
  • v1 themes and shareable Packages marketplace
  • v1 print/JSON and RPC modes
  • OAuth / subscription login matrix and OS keychain
  • Built-in permission/sandbox system (host permissions; external containerization if needed)
  • Branch summarization on tree navigation (deferred past compaction v1)
  • Pixel-perfect upstream TUI parity or custom differential renderer

Further Notes

  • Domain vocabulary must follow CONTEXT.md; do not re-litigate closed map tickets unless the destination changes.
  • Issue Handoff: implement v1 Python pi harness #17 remains the implementation handoff umbrella; this spec is the buildable collapse of map decisions for /to-tickets and /implement.
  • Tracer-bullet tickets should stay vertical and session-sized; work the frontier (unblocked tickets) one fresh context at a time via /implement.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentFully specified, ready for an AFK agent

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions