pi-muselinn-harness
Kimi Code-style agent orchestration harness for Pi coding agent — Swarm (concurrent subagents + braille TUI), Goal (lifecycle + budget + queue), Plan (plan mode + tool restrictions), Permission (18-level policy chain: auto/yolo/manual), Task (background +
Package details
Install pi-muselinn-harness from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-muselinn-harness- Package
pi-muselinn-harness- Version
0.9.15- Published
- Aug 1, 2026
- Downloads
- 3,196/mo · 1,779/wk
- Author
- muselinn
- License
- MIT
- Types
- extension
- Size
- 720.4 KB
- Dependencies
- 1 dependency · 3 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-muselinn-harness
Kimi Code-style agent orchestration for the Pi coding agent — Swarm · Goal · Plan · Permission · Ask · Task · Cron · Todo · Hooks · Skills · TUI, one package that builds the features Pi deliberately skips (sub-agents, plan mode, todo, …) and aligns them with Kimi Code's subsystem behavior.
Compatible with pi 0.81.x–0.83.x on macOS, Ubuntu, and Windows · Node 22/24 · CI-tested on Ubuntu + Windows.

What is this?
Pi is a focused coding agent: no sub-agents, no plan mode, no todo. This harness adds them — in the same style as Kimi Code — as a single install:
| You want | You get |
|---|---|
| Parallel sub-agents | agent_swarm / agent — real max_concurrency, live braille-grid TUI, run_in_background, /resume |
| Plan before execution | enter_plan_mode — read-only exploration, approval gate, Kimi Code permission model |
| Stay on task | /goal — lifecycle, budgets, queue, completion-criterion gate |
| Safety rails | 18-level permission chain (auto / yolo / manual), destructive-command + .env guards |
| Work that outlives the turn | run_background + cron_create — persistent tasks and scheduled prompts |
| The agent asks properly | ask_user_question — tabbed multi-question dialog with previews |
| Task tracking | /todo + todo_list — phased plan with inline panel and reminders |
| A nicer editor | ╭─╮ │ ╰─╯ closed-box TUI with spinner + model in the border |
| Lifecycle automation | [[hooks]] engine — 16 events, blockable PreToolUse/Stop/UserPromptSubmit |
Quick start
pi install npm:pi-muselinn-harness # or: pi install git:github.com/MuseLinn/pi-muselinn-harness
pi # restart, then:
Try it out:
/swarm on # enable swarm mode
/goal Refactor the auth module # set a goal with budget tracking
/todo init "Phase 1: scanner" # start a phased task plan
/plan # enter plan mode (read-only exploration)
/tui style plain|boxed|compact # switch editor chrome anytime
Everything works out of the box — no companion extensions required. All tools are model-callable, all commands are slash commands with Tab completion.
Upgrading from ≤ 0.7.4? Remove the old companion extensions — they conflict with the built-in tools (pi refuses to start on duplicate tool names):
pi remove npm:@juicesharp/rpiv-ask-user-question pi remove npm:rpiv-todo
Features
Swarm
- In-process subagents —
createAgentSession()execution,coder/explore/plantypes - Real concurrency control —
runProgressive()worker pool with truemax_concurrencycap + exponential backoff retries - 30-minute timeout — per-subagent
AbortSignal.timeout(aligned with Kimi Code) - run_in_background — whole swarm goes to a background task, early task-ID return, report written to
output_path - Smart model routing — task-aware selection from
ctx.modelRegistry - Braille progress bars — driven by real tool-call progress, 250 ms frames with a state-fingerprint gate (unchanged frames cost nothing)
- Harness-branded spinner — single-width braille rotation by default (
PI_MUSELINN_SPINNER=braille|pulse|bounce|moon, incl. Kimi moon-phase compat) - Adaptive layout — pi-tui Component protocol, status bar width adapts to the terminal (10–60)
- Three-pane task browser — status glyphs (○ pending / ◐ running / ✓ done / ✗ failed / ▲ aborted), strikethrough on done rows, overflow collapse (
+N more, running kept first), named keybindings,ctrl+shift+t - Cancel / resume — UserCancellationError + AbortSignal chain, two-step
/cancel
Goal
- Lifecycle — active / paused / blocked / complete / usage_limited / budget_limited
- Active Guard —
create_goalrefuses to silently overwrite an active goal (replace=trueor/goal replace) - Blocked 3-turn threshold — three consecutive blocks for the same reason before really blocking
- Completion-criterion gate — a declared criterion must be verified before completing (
verified=truein the sameupdate_goalcall; documented in the tool description) - Triple budget checks — tokenBudget + turnBudget + wallClockBudgetMs (
turns/tokens/ms/s/minutes/hours) - Goal Queue — FIFO + high/normal priority + auto-switch + prioritize/drop/skip
- Persistence — appendEntry + session_start restore; counters merge monotonically (max per goalId), so a stale entry can never pull turns/tokens backwards;
clear()writes a tombstone entry so completed goals stay completed - Context injection —
<untrusted_objective>tag into the system prompt - Recovery — compaction preservation + context-overflow detection + 429 detection
Plan
- Plan mode — the LLM explores, writes a plan, and only executes after approval
- Kimi Code permission model — bash is NOT blocked in plan mode; it follows the normal permission mode (auto/yolo/manual). Only Write/Edit (outside plan file), TaskStop, CronCreate, CronDelete are blocked
- Plan file path matching — exact path,
local://scheme basename, and resolved absolute path undersessionDir/plans/— all three accepted - ExitPlanMode reads the plan file — presentation matches what was actually written to disk
- Revise keeps your plan — a revised or cancelled review re-enters plan mode with the same plan object (id/path/content), never a trap, never lost work; review timeout 600 s
- Restore validation — a stale persisted active-plan entry with no content and no file on disk deactivates plan mode instead of trapping the session
- Context injection — the plan is injected into the system prompt
Permission
- 18-level policy chain —
auto/yolo/manual; safety policies (destructive, sensitive files) short-circuit before modes - Destructive detection —
rm -rf/git push --force/drop table/git reset --hardregex recognition, always asks, never short-circuited by session approvals - Sensitive-file guard —
.env/id_rsa/*.keyread/write interception, even in auto mode - Session approval fingerprints — approvals remembered per sessionId + input fingerprint, never degrading into "permanent allow"
- Approval panel — numbered dialog with per-tool action titles ("Run this command?" / "Apply these edits?"), digit-key direct select, four outcomes: Allow once / Always allow (session) / Deny / Deny with reason (reason relayed to the model)
- Subagent gating — swarm worker tool calls run through the same policy chain (shared in-process manager):
/modeswitches propagate to in-flight subagents by construction,askverdicts degrade to blocks (never silent approval) - AGENTS.md hierarchy — project (nearest
AGENTS.mdor.kimi-code/AGENTS.md) → global$KIMI_CODE_HOME/AGENTS.md→ cross-tool~/.agents/AGENTS.md, aggregated;destructive-ask-alwayscan upgrade ask to deny - Config cache — permission config cached by file mtime, edits take effect immediately
Task (background + cron)
- run_background — subagent in the background, immediate task ID;
output_pathpages full output via Read - 30-minute timeout — background tasks auto-fail (
stopReason=timeout_30min) - task_list / task_output / task_stop —
active_onlyfilter,block+timeoutwaiting,offset/limitpaging - 50-task cap + 7-day stale cleanup + orphaned tasks degrade to
process_restarton restart - Incremental persistence — single-task changes append a single entry; restore stays compatible with old snapshots
- Cron — 5-field cron (local timezone) + deterministic jitter (10% of period, ≤15 min) + recurring/one-shot + 50 cap + 7-day stale auto-delete
Hooks
- Kimi Code-aligned
[[hooks]]engine — reads$KIMI_CODE_HOME/config.toml(default~/.kimi-code/config.toml) + project.kimi-code/config.toml; event/matcher/command/timeout fields - Full event coverage — UserPromptSubmit / PreToolUse / Stop (blockable) + PostToolUse / PostToolUseFailure / PermissionRequest / PermissionResult / SessionStart / SessionEnd / SubagentStart / SubagentStop / StopFailure / Interrupt / PreCompact / PostCompact / Notification
- Exit-code semantics —
0allow (stdout appended as context),2block (stderr as reason), anything else / timeout / crash fails open; stdout JSONpermissionDecision: denysupported - Built-in TOML mini-parser — zero dependencies; invalid rules warn and skip without breaking the extension; mtime-cached hot reload
- Safety net — Stop auto-disables after 3 consecutive blocks (anti-loop); every trigger mirrored to
pi.eventsfor other extensions
Skills
- Seven-scope pi-native scanning — project
.pi/skills,.kimi-code/skills(Kimi compat),.agents/skills→ user~/.pi/agent/skills,~/.pi/skills,$KIMI_CODE_HOME/skills,~/.agents/skills; pi-native dirs win, Kimi dirs as compat layer, dedupe by name - Directory + flat forms —
SKILL.mdsubdirs (with auxiliary files) and single.mdfiles; full frontmatter fields (name/description/type/whenToUse/disableModelInvocation/arguments, kebab/snake variants) - Available to subagents — swarm and background subagent sessions receive skills via resourceLoader; the main session is injected via
resources_discover(collision-free: only files from dirs pi does not scan natively, minus names pi already provides) - Zero-dependency frontmatter parser + mtime directory-tree cache
TUI
Closed-box editor — Kimi Code's
wrapWithSideBordersported: pi-tui's horizontal-only borders post-processed into a╭╮│╰╯closed box; spinner + working state (Thinking/Streaming/Running tools) embedded in the top border; three stylesplain | boxed | compact(pi-spark-style info border = compact), default boxed; model name opt-in via"modelInBorder": trueThe first content line carries a prompt chevron (
│❯ text │), padding is clamped to ≥2 so the bars never touch the text or cursor./tuicommand — hot-switch styles without restarting (pi preserves text/focus/keybindings when swapping editors);/tui timingshows render timing; config persisted to~/.pi/agent/muselinn-tui.json(project.pi/override)Plan badge —
plantext badge on the top border while plan mode is active (no border recoloring — zero conflict with pi's thinking-level colors)Timing probe —
PI_MUSELINN_HARNESS_TUI_TIMING=1records editorrender()P50/P99; spinner only ticks at 250 ms while the agent worksShimmer working message (OMP-style) — the working label in the editor border gets a wall-clock driven light-band sweep (
classiccosine band orkittK.I.T.T. scanner); the crest paints accent+bold so dim text stays legible mid-animation.low: dim / mid: muted / high: accentby default;/tui shimmer <classic|kitt|disabled>switches live, config persistedStable animation frame-rate — the keep-alive timer uses a fixed 200ms quiet gate (≈10fps ceiling) so the animation cadence never changes; natural streaming renders ride pi's own frames at zero extra cost, and a stalled agent loop costs at most ~10 full-tree renders per second even on very large sessions. (Adaptive thresholds based on measured render latency were tried and rejected: latency noise made the frame rate stutter.)
Ask (interactive questions)
ask_user_questiontool — the agent asks 1-4 structured questions in one tabbed dialog: per-question header tabs (1/3 · header, ←/→/Tab to switch), numbered options with description sub-lines,multi_selectcheckboxes (Space toggles, Enter confirms), and an automatic free-text Other option on every question; digit keys 1-9 jump straight to an option, arrows/jk navigate, Esc cancels- Robust by default — long option lists scroll inside a bounded window, duplicate answers are deduplicated, and questions can be posed from background tasks without wedging the UI
- Previews, notes, chat row — options can carry Markdown previews (side-by-side pane on wide terminals, stacked below on narrow ones); attach a per-option note with
n; a Chat about this row ends the dialog with achatresult so the user can discuss the question instead of answering it - Shared dialog component — the same component backs permission approval (single-select, no Other); in print/RPC mode the tool returns the questions as text instead of blocking
- Answer reporting — per-question answers (multi-select as an array); skipped questions and Esc-cancelled dialogs are reported distinctly
- Auto-mode safe — auto mode denies
ask_user_questionby policy (no unattended hangs)
Todo
- Inline panel — above-editor widget with roman-numeral phase tree (
Ⅰ. Scanner · 2/4),/todo toggleexpand/collapse; finished tasks auto-clear afterPI_MUSELINN_TODO_CLEAR_DELAYseconds (default 60,0= instant,-1= manual) so completed plans fade out of the HUD instead of lingering /todocommand — full oh-my-pi phase model:init,start,done,drop,rm,append,export,import,copy,edit,add_notes,update_details, bare/todoprints Markdowntodo_listtool — model-driven task management with same ops- Reminder system — incomplete todos injected as
<system-reminder>when agent stops (max 3 reminders, debounced) - Subagent matching — pending tasks matching swarm subagent descriptions get highlighted with
◔spinner - Markdown round-trip —
/todo export/importfor persistence and sharing between sessions - Notes — per-task notes via
add_notes/update_details - Phase counts — widget header shows
N active · M pending · K done - Session persistence — survives hot-reload and session restart
Web fetch
fetch_urltool — no-auth URL fetch (20s timeout, 5MB stream cap, redirect follow); HTML → readable text (dependency-free extractor), JSON → pretty-print, everything else raw; 20k char cap withmax_charstuning
Plugins (declarative bundles)
muselinn.plugin.json— six declarative capabilities:skills(skill dirs merged into discovery),sessionStart(context injected on the session's first turn),hooks(merged into the[[hooks]]engine),commands(.md files become slash commands), plusmcpServers/interfacerecorded with skipped-diagnostics- Discovery — project
.pi/plugins/*/then user~/.pi/agent/plugins/*/, first-wins name dedupe;/pluginslists capabilities and diagnostics
Output truncation
- Oversized tool results spill to disk — results over 40k chars are written to
<sessionDir>/tool-results/and replaced in context with a sanitized head+tail preview carrying theoutput_pathand read-paging instructions (KimitoolResultTruncationpattern)
Commands
| Command | Description |
|---|---|
/swarm on|off |
Toggle swarm mode |
/cancel |
Cancel current work (two-step confirm) |
/resume |
Resume an interrupted swarm |
/tasks |
Task browser (ctrl+shift+t) |
/goal <objective> |
Set a goal |
/todo |
Task plan with phase model; shortcuts: start done drop export import copy edit toggle |
/todo toggle |
Expand/collapse the todo panel (replaces former alt+t) |
/plugins |
List loaded plugins and their capabilities |
/swarm-status |
Show status |
/goal/swarm/plan/mode/tuiall support Tab completion.
Tools
| Tool | Description |
|---|---|
agent_swarm |
Batch parallel subagents (max_concurrency / run_in_background / output_path / model_map) |
agent |
Single subagent |
create_goal / get_goal / update_goal / set_goal_budget |
Goal management |
enter_plan_mode / exit_plan_mode |
Plan mode |
ask_user_question |
Tabbed structured questions (multi-select, Other free text) |
todo_list |
Model-driven task plan with inline panel |
fetch_url |
No-auth URL fetch with content-aware extraction |
run_background / task_list / task_output / task_stop |
Background tasks |
cron_create / cron_list / cron_delete |
Cron jobs |
Kimi Code alignment
Against the Kimi Code CLI docs — Agents & Subagents:
| Capability | Status | Notes |
|---|---|---|
| Three built-in subagent types (coder/explore/plan) | ✅ | coder=read/write+bash; explore=read-only; plan=read-only, no shell |
| Context isolation | ✅ | Independent sessions; only final results flow back |
| Parallel dispatch + max_concurrency | ✅ | Real worker-pool cap + progressive launch |
| 30-minute timeout | ✅ | Per-subagent AbortSignal.timeout |
| Background execution (run_in_background) | ✅ | Early task-ID return, blockable task_output, report to output_path |
| Resume an existing subagent | ⚠️ | Conservative semantics: same-id re-run; resume validated (saved state + nothing in flight + remaining items); true session resume pending pi-coding-agent API |
| Nested subagents (coder spawning more) | ❌ | Deliberately closed — no recursive dispatch; subagent toolset excludes agent/agent_swarm |
| Permission inheritance | ✅ | Worker tool calls pass through the shared policy chain; /mode propagates by construction; asks degrade to blocks |
| Instruction-file hierarchy | ✅ | Project AGENTS.md / .kimi-code/AGENTS.md → $KIMI_CODE_HOME/AGENTS.md → ~/.agents/AGENTS.md |
| wire.jsonl session persistence | ❌ | Subagents use SessionManager.inMemory() (in-process lifecycle) |
Hooks ([[hooks]] lifecycle) |
✅ | All 16 events, exit-code/stdout-JSON block semantics, fail-open |
| Agent Skills (four scopes) | ✅+ | Kimi's four covered and extended to seven pi-native scopes; directory + flat forms; subagent + main-session channels |
Architecture
Core/adapter split: packages/core/ is pure logic with zero pi imports;
the repo root holds the pi adapter (entry, pi-tui components, tool registration).
pi-muselinn-harness/
├── index.ts entry (agent_swarm/agent tools, background runner, module wiring)
├── state.ts shared state
├── packages/core/ @muselinn/core — pure logic, no host imports
│ ├── ports.ts host contracts (PersistencePort, ScopeDirs)
│ ├── text-utils.ts visibleWidth & friends
│ ├── shell-output.ts control-sequence sanitizer
│ ├── truncation/ oversized tool-result spill (pure)
│ ├── webfetch/ HTML→text / JSON extraction (pure)
│ ├── completions.ts slash-command argument completions
│ ├── ask/ question spec + formatting (pure)
│ ├── todo/ todo model + Kimi folding strategy (pure)
│ ├── plugin/ muselinn.plugin.json manifest parse/discovery
│ ├── goal/ Goal module (state machine, budgets, queue, persistence)
│ ├── plan/ Plan module (tool whitelist, path guard, injection)
│ ├── permission/ Permission module (18-level chain, approval contract)
│ ├── hooks/ Hooks module (TOML mini-parser, executor, 16 events)
│ ├── skills/ Skills module (frontmatter, seven-scope scanner)
│ ├── swarm/ pure swarm half
│ │ ├── types.ts state/constants (+ goal re-export)
│ │ ├── helpers.ts braille bars / layout / spinner (memoized)
│ │ ├── estimator.ts progress estimation (geometric mean)
│ │ ├── widget-lines.ts braille grid line builders (pure)
│ │ ├── wrap-tools.ts permission gate wrapper (pure)
│ │ ├── resume-guard.ts resume ownership/idle validation (pure)
│ │ ├── report.ts swarm report formatting
│ │ └── task-list-utils.ts collapse + key routing
│ ├── task/ cron + task persistence state (pure)
│ └── tui/ box/config/parse/switch/timing (pure chrome parts)
├── swarm/ adapter: subagent execution, /swarm commands,
│ SwarmWidgetComponent, three-pane task browser
├── task/ adapter: background task manager (session spawn)
├── tui/ adapter: MuselinnEditor + event wiring
├── ask/ adapter: question dialog + ask_user_question tool
├── todo/ adapter: todo_list tool + inline panel widget
├── webfetch/ adapter: fetch_url tool
├── plugin/ adapter: plugin loader + /plugins command
└── tests/ node-level unit tests (below)
Tests
Pure node-level unit tests, no model quota needed (23 suites, 660+ assertions):
npm test # all suites (node tests/run-all.mjs)
or individually:
node tests/musepi-config.test.mjs # MusePi config compat — 9
node tests/permission.test.mjs # Permission policy chain + subagent gate — 22
node tests/goal.test.mjs # Goal state machine + monotonic restore — 32
node tests/plan.test.mjs # Plan mode round-trip + restore validation — 42
node tests/task.test.mjs # Task restore/list/output/block + loader runtime — 16
node tests/cron.test.mjs # Cron subsystem — 16
node tests/hooks.test.mjs # Hooks engine — 43
node tests/skills.test.mjs # Skills scan/parse/scopes/discover — 38
node tests/tui.test.mjs # TUI collapse/keys/completions/spinner — 62
node tests/tui-box.test.mjs # TUI box/config/probe/switch — 61
node tests/agent-file.test.mjs # agent file discovery/parse — 11
node tests/agent-lifecycle.test.mjs # agent lifecycle events — 6
node tests/ask.test.mjs # ask spec/dialog/answers/approval titles — 123
node tests/tool-policy.test.mjs # tool policy gate — 13
node tests/todo.test.mjs # todo model + folding strategy — 21
node tests/shell-output.test.mjs # output sanitizer — 21
node tests/shimmer.test.mjs # shimmer sweep engine — 10
node tests/truncation.test.mjs # tool-result spill — 13
node tests/resume-guard.test.mjs # swarm resume validation — 6
node tests/webfetch.test.mjs # web extraction — 12
node tests/plugin.test.mjs # plugin manifest/discovery — 17
node tests/renderer.test.mjs # incremental renderer buffer/tree — 16
node tests/stream-rules.test.mjs # stream entry rules — 14
The suites run on Node 20/22/24 (20 via tests/ts-esm-loader.mjs, a
TypeScript-transpile ESM loader; 22.6+ strips types natively). CI runs the
full matrix — ubuntu + windows × node 20/22 — on every push and PR.
Roadmap
- i18n — bilingual harness UI text and notifications (docs are already split en/zh-CN; the project page has an EN/中 toggle)
- Math renderer graduation — merge
feature/math-rendereronce compaction-path context safety is confirmed - Clustered diff preview — kimi-style ±3-line clustered diffs in edit/write approval messages (deferred from the P1 batch)
- True fullscreen — container-swap fullscreen (kimi tasks-browser pattern); no alt-screen, preserving terminal scrollback
Dependencies
- Pi >= 0.80.0
@earendil-works/pi-coding-agent,@earendil-works/pi-ai,@earendil-works/pi-tui(peers)typebox
Experimental branches
feature/math-renderer— renders$$...$$display math in assistant messages via txm (cell-based 2D typesetting, works in Windows Terminal; no image protocol). Context-safe: the original Markdown is restored before every LLM call. Enable with/tui math onaftercargo install txm.
Acknowledgments
Design and implementation inspired by these open-source projects:
Kimi Code (Moonshot AI)
- Agent Swarm concurrency architecture (max_concurrency worker pool, 30-min timeout, run_in_background)
- Goal system design (GoalActor tracking, Budget Report, blocked 3-turn threshold, context injection)
- Plan-mode lifecycle (enter/exit/approve/reject, ExitPlanMode disk read)
- Permission policy chain (auto/yolo/manual, destructive-always-ask, AGENTS.md priority)
- Cron scheduling (5-field + jitter + 7-day stale + 50 cap)
- TUI component design (braille progress bars, three-pane task browser,
wrapWithSideBordersclosed-box editor) - Cancel/resume mechanism (AbortSignal chain, UserCancellationError)
pi-spark (zlliang)
- Editor top-border info slots (spinner + working state + model embedded in the border)
- Component-replacement TUI customization path (
setEditorComponent/setFooter/setWidget)
@narumitw/pi-goal (narumitw)
- Goal Queue FIFO + auto-switch mechanism
- usage_limited / budget_limited state design
- Wrap-up instruction injection (post-budget behavior)
- Stale Tool Blocking design
- Compaction retention policy
pi-codex-goal (fitchmultz)
- Goal persistence (appendEntry + session_start restore)
- Goal state transitions
- Budget checking
- Recovery Machine concept (simplified)
Note: this extension is mostly an independent implementation. Exception: tui/box.ts's wrapWithSideBorders is ported from Kimi Code (MIT), with attribution kept in comments and used under the MIT license.
Releasing (maintainers)
Tag to mark the release (CI publish removed — publish locally with OTP):
npm run version-patch && git tag v0.9.1 && git push origin v0.9.1
Changelog
See CHANGELOG.md for the full version history.