decorated-pi0.12.2
decorated-pi is a practical enhancement pack for pi coding agent — token-efficient workflow, cache-friendly design, and smarter tools.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
decorated-pi
decorated-pi is a practical enhancement pack for Pi — token-efficient workflow, cache-friendly design, and smarter tools.
Install
pi install npm:decorated-pi
# or
pi install git:github.com/lcwecker/decorated-pi
# or
pi install /path/to/decorated-pi
Features
1. Token Efficiency
Multiple layers of token savings that compound across every session.
Talk Normal Prompt — injects a response-style prompt adapted from talk-normal (prompt.md v0.6.2), trimming filler, summary stamps, conditional follow-up menus, negation-frame phrasing, and verbose framing. This reduces assistant output tokens and keeps visible reasoning / explanation blocks tighter.
Codegraph — integrates codegraph to offer a code map of your project, so the LLM can navigate symbols and call graphs without chaining ls → grep → read. Create and maintain the project index yourself; see the codegraph documentation.
Auxiliary Models — offloads heavy-but-dumb tasks to cheaper models so your primary model only pays for the hard work:
- Image Read Fallback — detects image type via magic bytes, calls a configured vision-capable model, and injects the analysis text, so your main model never touches image tokens
- PDF Read — reads PDFs with the configured model: a document of ten pages or fewer whole, a longer one in page ranges rendered to images, returning the extraction as text
- Compact Model — handles context compaction with a smaller model instead of burning main-model capacity, and carries the task on after an automatic compaction so the run does not stop early (a manual
/compactdoes not resume)
Configured via
/dp-model.
Cache‑friendly Design — stable system prompt prefix:
- tool definitions, guidelines, and skills are sorted alphabetically so the system prompt stays deterministic for the same project and configuration
- MCP servers are registered with pi's built-in MCP extension, so the session keeps one connection path and one tool list
Pi Native Prompt Slimming — moves the default Pi documentation block out of the system prompt and into a builtin pi-docs skill, so the docs reference loads on demand instead of sitting in every turn's prompt.
Large Result Externalization — a tool_result hook saves a tool's first text result when it exceeds 30,000 characters to /tmp/decorated-pi-results/<tool>-<callId>.txt, replacing it with a one-line pointer ([Output too long, saved to /tmp/…]) that the LLM can read on demand. Only the oversized part is replaced — an image or a second text part in the same result stays in context. The built-in bash tool is left to pi, which captures shell output itself (50 KB / 2000 lines, full text in a spill file). Earlier days' files are swept on session start.
2. Smarter Tools
LLM-callable tools and workflow upgrades with better UX and fewer wasted turns.
Patch Tool
| Capability | Pi native edit |
patch |
|---|---|---|
| Anchor‑based search | ❌ extending oldText for uniqueness |
✅ anchor bounds scope for precise matching |
| Fuzzy whitespace match | ❌ only reports "not found" | ✅ auto‑corrects tab↔space / trailing whitespace mismatches |
| Edit fault diagnostics | ❌ only reports "not found" | ✅ pinpoint faults for LLM comprehension |
| Stale‑read protection | ❌ Blind to external changes | ✅ read captures mtime, patch rejects stale targets |
LSP support
A language server answers from the compiler's binding graph: imports, re-exports and overloads resolve exactly, every reference to a symbol is enumerated, and a rename's complete edit set comes back across every file that references it. A model reading the files works from the subset it opened.
lsp_definition— where a symbol is definedlsp_references— every reference to a symbollsp_document_symbols— a file's symbol outline, to find a positionlsp_rename— the exact workspace edits for a rename, applied to disk (or previewed)
Supported languages: c/cpp, go, java, lua, python, ruby, rust, svelte, typescript. TypeScript support is bundled; the other languages require their corresponding language-server binaries.
Ask tool
Collect text, single-choice and multi-choice answers when the agent needs clarification. One question per page in the terminal: type for free text, ↑↓ or digits to pick an option, Space to toggle in a multi-choice, Enter/Tab to commit and advance, Shift+Tab to go back, Esc to cancel the whole call.
- Interactive only — a session without a UI gets an error instead of a guess, so the agent puts the questions in its reply and works in rpc/json/print sessions.
- Configuration —
/dp-settings→ Tools → Ask, ormodules.tools.askindecorated-pi.json.
PDF Reader
read_pdf reads a PDF with the model configured for it. A document of ten pages or fewer goes to the provider whole; a longer one must be read in page ranges (pages: "1-5", 1-indexed, at most twenty pages per call), which are rendered to images with poppler's pdftoppm. Rendering is what makes the page path portable: an image block works on every vision model, including providers whose API cannot receive a PDF document (Bedrock is refused the whole read with a message pointing at the page range it does accept). The page count comes from pdfinfo and is stated in the result ([PDF: 42 pages, showing pages 11-15]), so the model reads a long document in consecutive windows; asking for a whole read of one fails with the count and an example range. read is untouched — a .pdf path handed to it still returns the file's raw bytes.
The model comes from /dp-model → PDF, falling back to the session's active model. Both poppler binaries are required: without poppler-utils a PDF cannot be read at all. /dp-settings reports the missing binary and takes a path override for it.
3. Web Access
Two native tools, both keyless. Search runs through three hosted backends and falls over automatically; fetching reads the URL directly and only leaves the machine when a plain HTTP client cannot render the page.
websearch — AnySearch → Exa → Parallel, first backend that returns results wins. A filter only one backend understands pins that backend, so includeDomains never lands somewhere it would be ignored.
| Backend | Strength | Endpoint |
|---|---|---|
| AnySearch | widest coverage: 17 vertical domains, batched queries, URL extraction | https://api.anysearch.com/mcp |
| Exa | semantic search plus category, domain, date and summary filters | https://mcp.exa.ai/mcp |
| Parallel | objective-shaped retrieval ranked against a stated goal | https://search.parallel.ai/mcp |
webfetch — local HTTP GET first (localhost and intranet hosts work, the URL stays local), with markdown / text / html output and image URLs returned as attachments. When a bot challenge, an HTTP error or a client-rendered page defeats the local fetch, it retries through AnySearch extract and then Jina reader. Private and local hosts skip those backends, and allowRemote: false keeps every URL on the machine; non-HTTP URLs are refused before any request is made.
Behind an HTTP proxy, Node's
fetchconnects directly and times out even thoughcurlworks — setNODE_USE_ENV_PROXY=1on Node 24+ to make it honourHTTPS_PROXY. Failure messages say so when a proxy variable is set.
4. MCP Ecosystem
Protocol, connections, tool registration and /mcp come from pi's built-in MCP extension. The pack contributes the one server definition it cannot do without, handed over with pi.registerMcpServer() and named by pi as mcp__<server>__<tool>:
| Server | Tool Prefix | Source |
|---|---|---|
| codegraph | mcp__codegraph__* |
local codegraph CLI, only where a .codegraph index exists |
Custom servers in ~/.pi/agent/mcp.json (global) or .pi/mcp.json (project, trusted projects only). Project entries replace global entries with the same name, and an mcp.json entry of the same name takes precedence over the builtin registration.
{
"mcpServers": {
"my-server": {
"url": "https://my-mcp.example.com/mcp",
"enabled": true
},
"my-disabled": {
"url": "https://my-mcp.example.com/other",
"enabled": false
},
"my-stdio": {
"command": "npx",
"args": ["-y", "my-mcp-server"],
"env": { "DEBUG": "1" }
}
}
}
Use /mcp to sign in, reconnect, enable or disable a server and change its exposure — the servers the pack ships appear there with scope extension. Servers speak stdio or streamable HTTP; the SSE transport of the older MCP spec is not available. An mcp.json entry of the same name replaces a builtin server, and it has to carry a valid command/url for the override to be accepted — { "codegraph": { "command": "codegraph", "args": ["serve", "--mcp"], "enabled": false } } switches it off. Servers the pack used to read from a project's .pi/agent/mcp.json are moved to .pi/mcp.json the next time the pack loads with the MCP module enabled — and like any project entry they count only in a trusted project.
5. Other
/code-review [prompt]— offload review of current SCM changes, or of a scope described in the prompt (e.g. a file/directory path, also without a git/svn repository), to a separately configured model, avoiding a/modelswitch in the main session and preserving its prompt cache. Without a scope the reviewer inspects the working tree itself via read-only SCM commands, but requires at least one tracked change (A/M/D/R/…); a tree with only untracked files (or none at all) needs an explicit scope./usage— token stats with cache‑hit rate, per‑model breakdown (Session / Today / This Week / This Month / All Time)/retry— continue after interruption- Progressive context — supports subdirectory
AGENTS.md/CLAUDE.mddiscovery and injection - WakaTime — coding activity tracking via WakaTime
Configuration
Runtime settings live in ~/.pi/agent/decorated-pi.json. Run /dp-settings to configure modules and dependency paths, and /dp-model to configure auxiliary models.
{
"modules": {
"tools": {
"patchOverrideEdit": true,
"ask": true,
"lsp": true,
"mcp": true,
"websearch": true,
"webFetch": true
},
"hooks": {
"wakatime": true,
"tps": true
},
"commands": {
"retry": true,
"usage": true
}
},
"dependencies": {
"wakatime-cli": {
"dontBother": true
}
}
}
modulescan be toggled on/off to enable/disable features. All are enabled by default.dependencies[binaryName].pathoverrides the lookup location for a binary (file or directory).dependencies[binaryName].dontBothersilences missing-dependency notifications for that binary. Both are optional.
License
MIT