{"slug": "pie-yet-another-open-source-coding-agent-in-rust", "title": "Pie: Yet another open-source coding agent in Rust", "summary": "Pie, a new open-source terminal-based AI coding agent written in Rust, has been released as a rewrite of the original pi project. The agent runs inside a project directory, can inspect and edit files, execute shell commands, remember preferences, and resume previous sessions while supporting multiple model providers including local OpenAI-compatible servers. The project aims to serve as a local agent runtime for developer workflows with features like slash commands, session history, MCP tools, cron triggers, and inter-agent messaging across machines.", "body_md": "`pie`\n\nis a Rust rewrite of the original [pi](https://github.com/earendil-works/pi) project (pi-coding-agent). `pie`\n\nis a terminal-based AI coding agent, run it inside a project, ask it to inspect files, make edits,\nrun shell commands, remember preferences, and continue previous sessions.\n\nThe initial reason was that I had some proactive, long-term automated tasks to run on a local DS v4 model. Therefore, I needed a customizable agent runtime to support these custom tasks, such as triggers, to perform some simple automation, Over time, the project gradually became more and more usable, so I thought I might as well turn it into a proper project. Of course, most of the code in this project was written by AI. If you’re sensitive to AI-generated code or AI coding, feel free to simply ignore it.\n\nPie runs inside your local project directory, can inspect/edit files, run shell commands, keep resumable sessions, and use different model providers, including local OpenAI-compatible servers.\n\nThe goal is not just to build another chat UI for coding, but a local agent runtime for developer workflows: slash commands, session history, skills, MCP tools, cron/triggers, and a small hub so agents running on different machines can send messages to each other.\n\n```\ngit clone https://github.com/c4pt0r/pie.git\ncd pie\ncargo build --release\n```\n\nThe CLI binary will be at `./target/release/pie`\n\n.\n\n`pie`\n\nauto-detects the first available provider credential. Set an API key before starting:\n\n```\nexport ANTHROPIC_API_KEY=sk-ant-...\n# or: OPENAI_API_KEY, OPENROUTER_API_KEY, GROQ_API_KEY,\n#     MISTRAL_API_KEY, GEMINI_API_KEY, GOOGLE_API_KEY\n```\n\nYou can also store a key from inside `pie`\n\n:\n\n```\n/login anthropic sk-ant-...\n```\n\n`pie`\n\ncan also use local OpenAI-compatible servers. Add a model definition to\n`~/.pie/models.json`\n\n(user-global) or `<project>/.pie/models.json`\n\n(project-local, higher\nprecedence), then select it with `--provider`\n\nand `--model`\n\n.\n\nExample for [DS4](https://github.com/antirez/ds4), the DeepSeek V4 Flash local\nserver. The Responses endpoint is the preferred OpenAI-compatible API for\nCodex-style clients; chat completions also works for simpler integrations.\n\n```\n# In the DS4 checkout:\n./ds4-server --ctx 100000 --kv-disk-dir /tmp/ds4-kv --kv-disk-space-mb 8192\n# If launching from another directory, add: --chdir /path/to/ds4\n{\n  \"models\": [\n    {\n      \"id\": \"deepseek-v4-flash\",\n      \"name\": \"DeepSeek V4 Flash (local DS4)\",\n      \"api\": \"openai-responses\",\n      \"provider\": \"ds4\",\n      \"baseUrl\": \"http://127.0.0.1:8000/v1\",\n      \"reasoning\": true,\n      \"thinkingLevelMap\": {\n        \"off\": null,\n        \"minimal\": \"low\",\n        \"low\": \"low\",\n        \"medium\": \"medium\",\n        \"high\": \"high\",\n        \"xhigh\": \"xhigh\"\n      },\n      \"input\": [\"text\"],\n      \"cost\": { \"input\": 0, \"output\": 0, \"cacheRead\": 0, \"cacheWrite\": 0 },\n      \"contextWindow\": 100000,\n      \"maxTokens\": 384000,\n      \"compat\": {\n        \"supportsStore\": false,\n        \"supportsDeveloperRole\": false,\n        \"supportsReasoningEffort\": true,\n        \"supportsUsageInStreaming\": true,\n        \"maxTokensField\": \"max_tokens\",\n        \"supportsStrictMode\": false,\n        \"thinkingFormat\": \"deepseek\",\n        \"requiresReasoningContentOnAssistantMessages\": true\n      }\n    }\n  ]\n}\n```\n\nThen run:\n\n```\nexport DS4_API_KEY=dsv4-local\n./target/release/pie --provider ds4 --model deepseek-v4-flash --base-url http://127.0.0.1:8000/v1\n```\n\nDS4 is local and accepts placeholder bearer tokens. You can also store the same\nlocal placeholder with `/login ds4 dsv4-local`\n\n. Using the `ds4`\n\nprovider keeps\nlocal model credentials separate from real `OPENAI_API_KEY`\n\ncredentials.\n\n`--base-url`\n\n, `DS4_BASE_URL`\n\n(or `DS4_URL`\n\n) registers the conventional `ds4`\n\n/\n`deepseek-v4-flash`\n\ndescriptor without a `models.json`\n\nfile. CLI `--base-url`\n\nwins for the current run. Keep `models.json`\n\nwhen you need different limits,\ncompatibility flags, or a project-local override.\n\n```\n# Start in the current project\n./target/release/pie\n\n# Choose a specific provider/model\n./target/release/pie --provider anthropic --model claude-haiku-4-5\n\n# Enable extended thinking where supported\n./target/release/pie --thinking high\n\n# Resume the most recent session for this project\n./target/release/pie --resume\n```\n\nOnce the REPL opens, type a request such as:\n\n```\nsummarize this repository\nfix the failing tests\nadd a README example and run the relevant checks\nwhen ~/build.done appears, run cargo test and show me the result\n```\n\nInside `pie`\n\n, slash commands control the session:\n\n| Command | What it does |\n|---|---|\n`/help` |\nShow all commands |\n`/model [provider:model-id]` |\nShow or switch model |\n`/thinking` |\nShow or set thinking level, off, minimal, low, medium, high, xhigh |\n`/sessions` |\nList sessions for the current project |\n`/save [path]` |\nExport the transcript to Markdown |\n`/compact [instructions]` |\nCompact long context |\n`/undo` |\nRemove the most recent user/assistant turn |\n`/cost` |\nShow token and cost totals |\n`/login <provider> <api-key>` |\nStore an API key |\n`/logout <provider>` |\nRemove a stored API key |\n`/triggers` |\nShow trigger rules, sources, running actions, and audit |\n`/triggers rules` |\nList dynamic trigger ids and state |\n`/triggers enable <id>` / `/triggers disable <id>` |\nResume or pause a trigger |\n`/triggers remove <id>` |\nDelete a trigger |\n`/cron` |\nList local scheduled jobs |\n`/cron add \"<minute hour dom month dow>\" <prompt>` |\nRun a prompt on a local schedule |\n`/cron enable <id>` / `/cron disable <id>` |\nResume or pause a scheduled job |\n`/cron remove <id>` |\nDelete a scheduled job |\n`/hub status` |\nShow built-in `pie.0xfefe.me` hub config, credential, and connection state |\n`/hub join` |\nSign in to the public hub and store this agent's hub credential |\n`/hub send name@namespace \"message\"` |\nSend a private hub notification summary to another agent |\n`/hub inbox [--limit 1..10]` |\nList recent hub inbox entries |\n`/hub connect` / `/hub logout` |\nConfigure the official hub MCP server or remove the stored hub credential |\n| `/config hub.inject [off | summary |\n`/quit` |\nExit |\n\nCLI helpers:\n\n```\n./target/release/pie --help\n./target/release/pie --list-sessions\n./target/release/pie --list-all-sessions\n./target/release/pie --delete-session <id>\n./target/release/pie --image screenshot.png\n```\n\nThe agent has tools for common coding workflows:\n\n- read, write, and edit files\n- list files and search with grep/find\n- run shell commands\n- manage persistent memory\n- delegate focused sub-tasks\n- resume JSONL-backed sessions per project\n- attach images to the first prompt with\n`--image`\n\n- create session-scoped natural-language triggers that run actions when local checks or MCP push events match\n- create session-scoped cron jobs that run prompts on a local schedule\n- receive server-pushed MCP notifications and normalize them into the same trigger runtime\n- join the public\n`pie.0xfefe.me`\n\nhub, send private notification summaries to other agents, and gate first-contact hub messages before they affect your session - run local command hooks or HTTP webhooks on agent lifecycle events; see\n[docs/hooks.md](/c4pt0r/pie/blob/main/docs/hooks.md)\n\nTriggers let you describe an automation in normal chat:\n\n```\nwhen $HOME/helloworld exists, print its contents\n```\n\n`pie`\n\nturns that request into a dynamic trigger rule. Rules are stored next to the active\nsession, so a new session starts cleanly and `--resume`\n\nbrings that session's rules back.\nDynamic triggers fire once by default; ask for a repeating trigger when you want it to keep\nrunning.\n\nTrigger actions run in a separate sub-agent. The sub-agent inherits the parent model, tools,\ntool hooks, thinking level, and skill catalog, but it does not receive the full parent\nconversation by default. Trigger output is shown in the TUI and written to trigger audit\nrecords. If you explicitly ask for the result to be visible to future turns, the rule is\ncreated with `promote_to_chat=true`\n\nand successful trigger output is inserted into the main\nchat context with a `[Trigger ...]`\n\nprefix.\n\nLocal dynamic checks poll every 10 minutes by default, and only emit checks while at least\none enabled dynamic rule exists. Configure the interval in `~/.pie/config.toml`\n\n:\n\n```\n[triggers]\npoll_interval_secs = 600\n```\n\nFor one run, override it with:\n\n```\n./target/release/pie --trigger-poll-secs 60\n```\n\nNotifications are trigger sources too. Each configured MCP server may expose a server-push\nstream; `pie`\n\nconsumes those frames through a `NotificationHook`\n\n, converts them into bounded\ntrigger envelopes, and runs them through the same deduping, audit, prompt, and action queue as\ndynamic trigger checks. Built-in MCP notifications such as tool/resource/prompt list changes use\nstable replacement keys, so repeated updates collapse to the latest event. Custom\n`notifications/*`\n\nevents must include `_meta.pie_dedup_key`\n\nor `_pie_dedup_key`\n\n; otherwise they\nare dropped at the adapter and counted in hook status.\n\nThe notification privacy boundary is intentionally conservative. Raw MCP notification params are\nnot persisted as chat content or trigger audit. Unknown/custom notifications persist only a\nbounded method-style summary unless the server provides `_meta.pie_summary`\n\n, which is capped and\nredacted before display or audit. This same notification runtime is used by ordinary `mcp.toml`\n\nservers, cron hooks, and the built-in public hub.\n\n`pie`\n\nincludes an optional built-in MCP client for the public `pie.0xfefe.me`\n\nhub. The hub lets\nagents discover each other and exchange short notification summaries without exposing provider\nAPI keys or local session data.\n\nJoin once:\n\n```\n/hub join\n```\n\nOn a desktop, `pie`\n\nopens a browser and completes the join through a loopback callback. In SSH or\nremote sessions, it prints a login URL and asks you to paste the one-time code shown by the hub.\nThe resulting hub token is stored under the reserved credential key `pie-hub:default`\n\n; when that\ncredential exists, the built-in `pie-hub`\n\nMCP server is added automatically at startup.\n\nCommon hub commands:\n\n```\n/hub status\n/hub send alice@dongxu \"build finished; please review the diff\"\n/hub inbox --limit 5\n/hub logout\n```\n\n`/hub send`\n\ncurrently sends a bounded summary only. The full payload remains local in this client\nslice (`payload_visibility = Local`\n\n), so another agent receives the notification summary but not\nyour transcript, files, tool output, or provider credentials.\n\nIncoming hub notifications use the trigger prompt path. A first-contact sender can be accepted\nonce, trusted for future notifications, blocked, or skipped. Persistent allow/block decisions are\nstored locally in `~/.pie/hub-trust.json`\n\nand are audited without raw payload or hub token\nmaterial. The TUI also shows a compact automation panel with trigger rules, polling status, cron\njobs, MCP servers, notification hooks, and runtime features when the terminal is wide enough.\n\nHub notification delivery into chat is controlled separately from trust:\n\n```\n/config hub.inject off      # default: keep notifications in the trigger/audit path\n/config hub.inject summary  # insert the notification summary into chat\n/config hub.inject run      # insert the summary and run one model turn\n```\n\nThe same setting can be persisted manually in `~/.pie/config.toml`\n\n:\n\n```\n[hub]\ninject = \"off\" # off | summary | run\n```\n\nThe official built-in hub profile is reserved for `https://pie.0xfefe.me/mcp`\n\n. Custom or staging\nhubs must be configured as separate MCP servers with their own server name and credential scope.\n\nCron jobs are time-based automations, separate from dynamic triggers. By default they are\nstored next to the active session transcript, so a new session starts cleanly and `--resume`\n\nbrings that session's scheduled jobs back. Cron jobs use local time and support standard\n5-field cron expressions:\n\n```\n/cron add \"*/30 * * * *\" summarize the repo state\n/cron list\n/cron disable cron-...\n```\n\nWhen a cron job is due, it enters the same serialized agent turn queue used by prompts and\ntrigger inject-and-run actions. `pie`\n\ndoes not backfill missed ticks after downtime. If a\njob is still running when its next tick arrives, that tick is skipped and recorded in the\njob status. Cron config stores only the schedule and action text; control-plane audit and\nUI output use bounded, redacted previews.\n\n`/cron add`\n\nand natural-language scheduled jobs are session-scoped. They do not write a\nuser-global `~/.pie/cron.toml`\n\n; a global cron install must be an explicit separate user\naction rather than the default behavior.\n\nBy default, `pie`\n\nstores local state under `~/.pie`\n\n:\n\n| Path | What |\n|---|---|\n`~/.pie/sessions/<cwd-hash>/<uuidv7>.jsonl` |\nSession history for each project |\n`~/.pie/memory/*.md` |\nCross-session memory injected into future sessions |\n`~/.pie/auth.json` |\nStored API keys from `/login` |\n`~/.pie/models.json` |\nUser-global local/custom model definitions |\n`~/.pie/history` |\nPrompt history |\n`~/.pie/mcp.toml` |\nUser-global MCP server config; project config may live at `<repo>/.pie/mcp.toml` |\n`~/.pie/hooks.toml` |\nOptional command/webhook hooks |\n`~/.pie/hub-identity.json` |\nLast joined public hub identity metadata |\n`~/.pie/hub-trust.json` |\nLocal first-contact allow/block decisions for hub notifications |\n`~/.pie/sessions/<cwd-hash>/<uuidv7>.triggers.json` |\nSession-scoped dynamic trigger rules |\n`~/.pie/sessions/<cwd-hash>/<uuidv7>.cron.toml` |\nSession-scoped cron jobs |\n`~/.pie/config.toml` |\nOptional user config, including trigger poll interval and hub injection mode |\n\nSet `PIE_DIR`\n\nto use a different base directory.\n\n```\ncargo build --workspace\ncargo test --workspace\ncargo clippy --workspace --all-targets -- -D warnings\ncargo fmt --all --check\n```\n\n", "url": "https://wpnews.pro/news/pie-yet-another-open-source-coding-agent-in-rust", "canonical_source": "https://github.com/c4pt0r/pie", "published_at": "2026-06-04 01:00:06+00:00", "updated_at": "2026-06-04 01:16:47.296973+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "ai-products"], "entities": ["pie", "pi", "Rust", "earendil-works", "c4pt0r", "MCP", "DS v4", "OpenAI"], "alternates": {"html": "https://wpnews.pro/news/pie-yet-another-open-source-coding-agent-in-rust", "markdown": "https://wpnews.pro/news/pie-yet-another-open-source-coding-agent-in-rust.md", "text": "https://wpnews.pro/news/pie-yet-another-open-source-coding-agent-in-rust.txt", "jsonld": "https://wpnews.pro/news/pie-yet-another-open-source-coding-agent-in-rust.jsonld"}}