|
| 1 | +# Pion |
| 2 | + |
| 3 | +**A minimal, hackable coding agent harness in Python** — a from-scratch reimplementation of the core architecture of [pi](https://github.com/earendil-works/pi) (TypeScript, by Mario Zechner), rebuilt for the Python ecosystem. |
| 4 | + |
| 5 | +[中文文档](README.zh-CN.md) |
| 6 | + |
| 7 | +> primitives, not features — the kernel stays tiny; everything else is an extension. |
| 8 | +
|
| 9 | +## Why pion |
| 10 | + |
| 11 | +pi proved that a coding agent needs no bloat: a <1000-token system prompt, four tools (`read`/`write`/`edit`/`bash`), and a powerful extension system. pion ports that philosophy to Python (~3.5k lines of core): |
| 12 | + |
| 13 | +- **Two API shapes, every model** — OpenAI-compatible endpoints (DeepSeek, Kimi/Moonshot, Qwen, Zhipu, OpenAI, vLLM/Ollama…) and Anthropic Messages (Claude), unified behind one streaming event protocol. |
| 14 | +- **A real agent loop** — streamed turns, parallel/sequential tool execution, steering & follow-up queues, truncated-tool-call protection, graceful abort. |
| 15 | +- **Tree-structured sessions** — append-only JSONL with branches, plus auto-compaction (structured summarization when the context fills up). |
| 16 | +- **Hooks, not features** — drop a `.py` file into `~/.pion/extensions/` to intercept tool calls, rewrite context, register tools/commands. Hot-reloadable. |
| 17 | + |
| 18 | +## Install |
| 19 | + |
| 20 | +Requires Python ≥ 3.11. |
| 21 | + |
| 22 | +```bash |
| 23 | +# from GitHub |
| 24 | +pip install git+https://github.com/your-name/pion.git |
| 25 | + |
| 26 | +# or with uv |
| 27 | +uv tool install git+https://github.com/your-name/pion.git |
| 28 | + |
| 29 | +# from source (development) |
| 30 | +git clone https://github.com/your-name/pion.git |
| 31 | +cd pion && uv sync --extra dev |
| 32 | +``` |
| 33 | + |
| 34 | +## Quickstart |
| 35 | + |
| 36 | +```bash |
| 37 | +# 1. set a provider key (DeepSeek shown; see table below for others) |
| 38 | +export DEEPSEEK_API_KEY=sk-... |
| 39 | + |
| 40 | +# 2. start the agent |
| 41 | +pion # interactive REPL |
| 42 | +pion -p "create hello.txt with hello world, then cat it" # single-shot |
| 43 | +pion -m kimi-k2-0905-preview # pick another model |
| 44 | +pion --session my.jsonl # resume a session |
| 45 | +``` |
| 46 | + |
| 47 | +REPL slash commands: `/help` `/model <id>` `/compact` `/stats` `/exit`. Ctrl-C aborts the current run gracefully. |
| 48 | + |
| 49 | +No key? Run the fully offline end-to-end demo (scripted provider, real agent + tools): |
| 50 | + |
| 51 | +```bash |
| 52 | +uv run python demos/mock_e2e.py |
| 53 | +``` |
| 54 | + |
| 55 | +## Built-in models |
| 56 | + |
| 57 | +| Model id | Provider | API | Env var | |
| 58 | +|---|---|---|---| |
| 59 | +| `deepseek-chat` / `deepseek-reasoner` | DeepSeek | openai-completions | `DEEPSEEK_API_KEY` | |
| 60 | +| `kimi-k2-0905-preview` | Moonshot | openai-completions | `MOONSHOT_API_KEY` | |
| 61 | +| `glm-4.6` | Zhipu | openai-completions | `ZHIPU_API_KEY` | |
| 62 | +| `qwen3-max` | Alibaba | openai-completions | `DASHSCOPE_API_KEY` | |
| 63 | +| `claude-sonnet-4-5` / `claude-opus-4-1` | Anthropic | anthropic-messages | `ANTHROPIC_API_KEY` | |
| 64 | + |
| 65 | +Any OpenAI-compatible/self-hosted endpoint works via `--base-url` + `--api-key`, or `register_model()` in code. `<PROVIDER>_BASE_URL` env vars override endpoints. |
| 66 | + |
| 67 | +## Extensions |
| 68 | + |
| 69 | +Drop a file at `~/.pion/extensions/my_ext.py` (or `.pion/extensions/` in a project): |
| 70 | + |
| 71 | +```python |
| 72 | +def setup(api): |
| 73 | + # block dangerous commands |
| 74 | + @api.on("tool_call") |
| 75 | + def guard(event): |
| 76 | + if event.tool_name == "bash" and "rm -rf /" in str(event.args): |
| 77 | + return {"block": True, "reason": "dangerous command blocked"} |
| 78 | + |
| 79 | + # inject context before every LLM call (RAG, memory, …) |
| 80 | + @api.on("context") |
| 81 | + def inject(messages): |
| 82 | + return messages # or a transformed copy |
| 83 | +``` |
| 84 | + |
| 85 | +Events: `before_agent_start`, `context`, `tool_call` (blockable), `tool_result` (overridable), `agent_start`, `agent_end`, `session_before_compact`. Extensions can also `api.register_tool(...)` and `api.register_command(...)`. |
| 86 | + |
| 87 | +## Architecture |
| 88 | + |
| 89 | +| pion module | pi counterpart | what it does | |
| 90 | +|---|---|---| |
| 91 | +| `pion/llm/` | `packages/ai` | unified streaming LLM API, 2 provider shapes, usage/cost | |
| 92 | +| `pion/agent/` | `packages/agent` | agent loop, event stream, tool orchestration | |
| 93 | +| `pion/tools/` | `packages/coding-agent` tools | read / write / edit / bash | |
| 94 | +| `pion/session/` | session-manager + compaction | JSONL session tree, auto-compaction | |
| 95 | +| `pion/hooks.py` | extension system | lifecycle hooks, dynamic tools/commands, hot reload | |
| 96 | +| `pion/cli.py` | `packages/coding-agent` CLI | REPL, slash commands, sessions | |
| 97 | + |
| 98 | +Intentionally **not** ported: pi's custom TUI (differential rendering), themes, keybindings — pion keeps a simple rich-based REPL. |
| 99 | + |
| 100 | +## Development |
| 101 | + |
| 102 | +```bash |
| 103 | +uv sync --extra dev |
| 104 | +uv run pytest -q # 95+ tests, no network needed |
| 105 | +uv run python demos/mock_e2e.py # offline e2e |
| 106 | +uv run python demos/real_e2e.py # live DeepSeek e2e (needs DEEPSEEK_API_KEY; exits 2 = honest skip without it) |
| 107 | +``` |
| 108 | + |
| 109 | +## Roadmap |
| 110 | + |
| 111 | +- [ ] Long-term memory / RAG extension (built on the `context` + `session_before_compact` hooks) |
| 112 | +- [ ] MCP client extension + multi-agent orchestration |
| 113 | +- [ ] Agent trajectory export & LLM-as-a-Judge evaluation |
| 114 | + |
| 115 | +## Credit & License |
| 116 | + |
| 117 | +Architecture and design philosophy credit goes to [pi](https://github.com/earendil-works/pi) by Mario Zechner and Earendil Inc. pion is an independent Python reimplementation. MIT License. |
0 commit comments