pi-soly
Project management + workflow framework for pi-coding-agent. Plans, state, MANDATORY rules, self-review, multi-question picker, native footer + welcome chrome — one npm install, zero config. The LLM drives the workflow inline via the soly_workflow tool —
Package details
Install pi-soly from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-soly- Package
pi-soly- Version
2.2.1- Published
- Jul 8, 2026
- Downloads
- 9,532/mo · 2,458/wk
- Author
- lowern1ght
- License
- MIT
- Types
- extension, skill
- Size
- 1.9 MB
- Dependencies
- 7 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
],
"skills": [
"./skills"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
⚡ pi-soly
The project management + workflow engine for pi-coding-agent.
Plans · State · Rules · Multi-question picker. One npm install. Zero config.
Install · Commands · Rules & Docs · Architecture · Releases
⚡ Install
pi install npm:pi-soly
Restart pi (/reload), and you have:
- Project management — plans, state, phases, decisions
- Workflow engine — runs inline (no subagent plugin). The model proposes the next step and drives it via the
soly_workflowtool on your plain-language intent; the verbssoly discuss·plan·execute·verify·pause/resumestill work as text - Self-review loop —
soly verifyre-reviews the work until "No issues found." - Goal-aware verification — at the end of every
soly execute(task / plan / phase plan-level), the worker reads PLAN.md's## Goal+## Acceptanceand judges each item againstgit diff. A## Statussection is appended to PLAN.md with a PASS / BLOCKED verdict. OnBLOCKEDthe worker halts before callingsoly done— so you can't ship a plan whose goal isn't actually met. - Visual chrome — native footer, equalizer working spinner with live telemetry, gradient welcome banner
- Rules & docs modal —
/rulesand/docsopen a fuzzy list + preview panel (no chat dumps) - Mandatory rules — strict-mode directives injected every turn
- Multi-question picker —
ask_protool for the LLM (single/multi-select, free-text, skip) - Decision deck —
decision_decktool: full-screen TUI cards for comparing design options by code shape - HTML artifacts —
html_artifacttool serves self-contained HTML from a per-session browser gallery (live-updating, one stable URL) - Skill-based execution — LLM reads the
soly-frameworkskill on demand
The LLM drives execution inline, in the main session — no external subagent plugin. Say what you want in plain language ("let's plan this", "start executing") and the model calls the first-party soly_workflow tool for you; the soly <verb> text form still works as a fallback. You focus on the work.
Known install issue (upstream pi install)
pi install currently does not install transitive peerDependencies (it skips them the way --omit=optional would). pi-soly's MCP stack depends on @modelcontextprotocol/ext-apps, which in turn peer-requires @modelcontextprotocol/sdk (declared non-optional upstream). After pi install npm:pi-soly you may see:
Error: Cannot find module '@modelcontextprotocol/sdk/types.js'
Require stack:
- ~/.pi/agent/npm/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.js
Workaround (one-time, after each pi install of pi-soly or any pi-soly-related upgrade):
cd ~/.pi/agent/npm && npm install
This makes plain npm resolve the transitive peer deps that pi install skipped. After this, restart pi (/reload) and the MCP features work.
Tracked upstream — fix is expected on the pi side, not here.
🎯 Why pi-soly?
| Without pi-soly | With pi-soly |
|---|---|
| Re-invent plan/state/resume from scratch | /plan, /execute, /resume, /inspect ready |
| Forget rules mid-session | ## ⚠️ MANDATORY header in every system prompt |
| Wonder which rules eat context | /rules stats — Claude-memory-style breakdown |
| Wonder which docs eat context | /docs stats — same for intent docs |
| Ask the LLM the same clarifying question 5 times | ask_pro multi-question picker |
📋 Commands
Workflow — plain-text verbs (type soly <verb>, not slash)
# === Plan mode (recommended for new work — each plan is a git branch) ===
soly new feat/auth-jwt # create branch + .agents/plans/<name>/ + stub PLAN.md
soly discuss feat/auth-jwt # interactive discussion of the plan
soly plan feat/auth-jwt # flesh out PLAN.md via ask_pro
soly execute feat/auth-jwt # execute the plan inline in this session
soly done feat/auth-jwt # commit, push, open draft PR via gh
soly verify # self-review loop until "No issues found." (soly verify stop to exit)
soly pause # save a handoff; soly resume to pick it back up
soly status # current position + progress (no LLM round-trip)
# === Phase mode (legacy — still works for existing projects) ===
soly plan 3 # generate PLAN.md for phase 3 (numeric form)
soly execute 3 # execute phase 3 (or `soly execute 3.02` for one plan)
soly migrate phases-to-plans # one-shot: import each .agents/phases/<NN>-slug/plans/PLAN.md
# as a `migrate/legacy-<NN>-slug` branch with .agents/plans/legacy-<NN>-slug/PLAN.md
Why plans instead of phases? A global phase counter (1, 2, 3, ...) means two developers each starting a "phase 11" write to the same path. With plans, each is a git branch (
feat/auth-jwt,fix/login-redirect, …) with its own.agents/plans/<name>/PLAN.md— no collisions, clean isolation, and the branch list itself is the registry of what's in flight.
State inspection (/soly)
/soly # interactive modal picker (live preview per item, ⏎ to open)
/soly position # where am I in the plan
/soly state # current STATE.md content
/soly roadmap # all phases
/soly progress # phases/plans/tasks done vs total
/soly phases # list phases
/soly plan [N] # show plan for phase N
Rules & Docs
/rules # interactive list
/rules stats # context breakdown (always-on vs glob-matched)
/rules analytics # token analytics + warnings + duplicates
/rules show <name> # show rule body
/rules reload # re-read all rules
/rules enable <name> / disable <name>
/docs stats # context breakdown (inline vs preview vs phase-specific)
Setup
/soly init # scaffold .agents/ (templates: minimal|web-app|library|cli)
/soly-status # one-screen health report
/soly-log # recent notifications
Debug
/why # rules + project state that grounded the last turn
/rulewizard # interactive guide: rule vs .editorconfig vs linter
🧠 Rules & Docs
Two system-prompt injections, both opt-in and fully observable.
Rules — .agents/rules/ or ~/.agents/rules/
Markdown files with frontmatter. Three modes:
---
description: TypeScript code style
always: true # loaded every turn
---
Always use `strict` mode. Never use `any`...
---
description: React component rules
globs: ["**/*.tsx", "**/*.jsx"] # loaded only when prompt mentions matching file
---
Hooks only at top level. Use memo only for expensive renders...
System prompt injection (every turn, after before_agent_start):
## ⚠️ MANDATORY: soly project rules
**These rules are NON-NEGOTIABLE. Before writing or editing ANY code,
re-read the rules above that apply to the file path you are about to
modify. If a rule contradicts your instinct, the rule wins.**
See context breakdown anytime: /rules stats.
Docs — .agents/docs/ or ~/.agents/docs/
Zero-point intent docs (your vision, business context). Loaded as preview only (180 chars per doc) — cheap. Add inline: true to opt-in to full body injection.
---
title: Core principles
inline: true # full body loaded every turn (expensive!)
---
Our core principles are...
See context breakdown: /docs stats.
🎤 Multi-Question Picker
ask_pro tool for the LLM. Tabbed UI: single-select, multi-select, recommended ⭐, free-text Other.
ask_pro({
questions: [{
header: "Auth",
question: "How should we store the OAuth refresh token?",
options: [
{ label: "Encrypted in SQLite", description: "Survives restart, single-device.", recommended: true },
{ label: "OS keychain", description: "Native, multi-device via iCloud." },
{ label: "Plain env var", description: "Simplest, dev only." }
]
}]
})
The LLM calls ask_pro when it needs structured input. Tab through questions, pick ⭐ options, confirm.
Per-option preview shows a side panel (fenced code is syntax-highlighted); freeText: true makes a typed-answer question; multi-select takes minSelect/maxSelect; press s to skip a question.
🃏 Decision Deck
decision_deck tool for the LLM. A full-screen TUI deck — one framed card per option, each with a syntax-highlighted code snippet and pros/cons — for design/architecture forks where the choice hinges on seeing the concrete shape, not a label.
decision_deck({
title: "State management",
prompt: "How should modules communicate?",
options: [
{ title: "Direct calls", summary: "Call modules directly.", pros: ["simple"], cons: ["coupling"] },
{ title: "Event bus", code: "const bus = new Bus()\nbus.emit('x')", lang: "ts",
pros: ["decoupled"], cons: ["harder to trace"], recommended: true }
]
})
Flip cards with ←/→ (or 1-N), choose with Enter, Esc to cancel. Native TUI — no browser, no server.
🖼 HTML Artifacts
html_artifact tool for the LLM — soly's local "artifacts". Renders HTML (a full document or just body content, themed light/dark) and serves it from a per-session gallery SPA — a sidebar of every artifact this session, an iframe viewer, a filter box, a light/dark toggle, and live SSE updates — on one stable localhost URL, opened in your browser. Pass id to update an artifact in place; pass assets to write sibling files (images/css/json) the HTML references; restyle everything via .agents/artifact-theme.css. (Falls back to opening the file directly if the server is disabled.)
html_artifact({
title: "API examples",
html: "<h2>Usage</h2><pre><code>client.send(msg)</code></pre>"
})
Use it when a visual, rendered result beats terminal text (example galleries, comparisons, diagrams). The gallery URL lives only while the pi session runs. /artifacts reopens the gallery anytime (modal: Enter opens an artifact, g the gallery, x delete, /artifacts clear clears); a ▦ N footer indicator shows the live count. Config under artifacts (open, dir, server, theme, retentionDays).
🏗 Architecture
┌──────────────────────────────────────────────────────────────┐
│ pi-coding-agent (peer dep) │
└────────────────────────┬─────────────────────────────────────┘
│
┌────────────────┴────────────────┐
▼ ▼
┌────────────┐ ┌─────────────┐
│ ask_pro │ │ soly_read │
│ picker │ │ soly_log_ │
│ (tool) │ │ decision │
└────────────┘ └─────────────┘
│ │
└─────────────────┬───────────────┘
│
▼
┌──────────────────┐
│ Workflow engine │
│ │
│ /plan /execute │
│ /resume /inspect│
│ /discuss /quick │
│ /soly /why │
│ /rules /docs │
└────────┬─────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
.agents/STATE phases/<N>/ rules/
(current CONTEXT, docs/
position) PLAN, (system
RESEARCH) prompt)
│
▼
┌──────────────────┐
│ soly-framework │
│ SKILL.md │
│ │
│ LLM loads on │
│ demand \u2014 no │
│ subagent layer │
└──────────────────┘
State lives in .agents/ — portable, git-friendly, human-readable. (Projects from before the rename used .soly/; soly no longer reads it — run mv .soly .agents.)
.agents/
├── ROADMAP.md # phase table
├── STATE.md # current position + decisions log
├── docs/ # 0-point intent docs (preview-loaded)
├── rules/ # rules (glob-matched or always-on)
└── phases/
└── 01-foundation/
├── 01-CONTEXT.md # domain + decisions for this phase
├── 01-RESEARCH.md # what we looked up
└── tasks/ # unified model: one dir per task
└── auth-login-a3f9/
├── PLAN.md # frontmatter: id, kind, status, depends-on
└── SUMMARY.md
Legacy projects (standalone
NN-MM-PLAN.mdfiles / afeatures/dir) still load and run alongside the unifiedphases/<N>/tasks/layout.
📚 Events
| Event | When | What we do |
|---|---|---|
session_start |
session opens | Install soly-framework skill, build initial state |
before_agent_start |
every turn | Inject rules + docs sections into system prompt |
tool_call (edit/write) |
LLM edits file | Track edited files (silent — used by /why) |
turn_end |
turn finishes | Refresh rules/state, hot-reload changes |
session_shutdown |
session closes | Flush iterators, cleanup |
🛠 Development
Requirements
- Bun ≥ 1.3
- pi-coding-agent ≥ 0.78
Setup
git clone https://github.com/lowern1ght/pi-soly.git
cd pi-soly
bun install
Test + typecheck
bun test # run the test suite
bun run typecheck # tsc --noEmit
bun run ci # both
Live-reload in pi
pi install ./packages/pi-soly
# edit files → /reload in pi to pick up changes
🚢 Releases
Tag-based, fully automated. Push a pi-soly-v* tag, get a publish.
./scripts/release.sh pi-soly 1.9.1
git push github master
git push github pi-soly-v1.9.1 --force
CI runs on a self-hosted GitHub Actions runner:
| Trigger | Job | Action |
|---|---|---|
Push to master |
test |
bun install + bun test + bun run typecheck |
PR to master |
test |
same |
Push tag pi-soly-v* |
test → publish |
tests + npm publish to npmjs |
The publish job uses GitHub Environment npm-publish so NPM_TOKEN is only exposed during the publish step. Zero secrets in workflow YAML.
🤝 Compatibility
- pi-coding-agent ≥ 0.78
- Node ≥ 20 (pre-installed on the runner)
- Bun ≥ 1.3 (pre-installed on the runner)
- OS — Linux, macOS, Windows (anywhere Bun runs)
📜 License
MIT — see LICENSE.
Built by @lowern1ght · Powered by pi + Bun