npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

moonpi

v0.4.5

Published

Opinionated set of extensions for pi

Downloads

499

Readme


moonpi is set of extensions for pi that are actually useful for a coding agent. No fluff. No over-engineered architecture. Just practical guardrails, structured workflows, and pragmatism.


Opinions

moonpi is built around a few strong opinions.

If these resonate with you, you might find this set of extensions useful:

  • Subagents are a waste of tokens. Subagents are useless and just a conspiracy to make us use more tokens. Tin foil hat firmly on.

  • Plan mode is actually useful - but only if history is retained. Plan mode becomes pointless when the model outputs a "plan" and then loses all the context that produced it. Planning only works when the planning conversation remains part of the execution context.

  • Context is king. Why make the model guess which files matter for a task, wasting tokens and time wandering through the project, when you can inject the relevant files directly into the context? Context matters more than models or harnesses, control the context and you control the result.

  • Rejecting reads and writes outside the working directory is good steering. Yes, we all know the model can write and execute code, and yes, sandboxing is hard. But telling the model "hey, you cannot read that" when it reaches outside the project helps steer behavior. May our benevolent AI overlords accept this humble suggestion.

  • Read before write is mandatory. If a model tries to overwrite a file without reading it first, that is an error. It should not be allowed. Period.

  • Prompt cache affinity matters.
    Switching system prompts or tool definitions between phases destroys the provider's prompt cache, forcing a full re-read of the system prompt on every turn. The phase transition should be invisible to the cache: same prompt, same tool schemas, only runtime behavior changes.

  • Loops are stupidly simple.
    A specification file, a TODO list, and auto-compaction after every phase are more than enough for most use cases.

Installation

First, install the base pi coding agent globally:

npm install -g @mariozechner/pi-coding-agent

Then, install the moonpi extension set directly via pi:

pi install npm:moonpi

Screenshots

Features

moonpi adds a practical workflow layer on top of pi, focused on:

  • explicit work modes
  • persistent planning context with prompt cache retention across phase transitions
  • TODO-driven execution
  • safer file access behavior
  • pickable project documentation context and /context inspection
  • sprint-based long-running workflows
  • phase-by-phase execution loops

Modes

moonpi provides four modes (Auto Mode has two phases):

| Mode | Available Tools | Description | | --- | --- | --- | | Plan Mode | read, grep, find, ls, todo, question | Used to reason about the task before making changes. The model must produce a TODO list. No file modifications or shell commands are allowed. | | Act Mode | read, grep, find, ls, bash, edit, write, todo, question (+ end_phase in sprint loop) | Used to execute work. The model can read, write, edit, and run commands. TODO and QnA can be used when helpful, but are not mandatory. | | Auto Mode (Plan phase) | read, grep, find, ls, todo, question, end_conversation | Default mode. The model first plans, then acts while retaining the full planning conversation history. During the planning phase, an end_conversation tool is available for question-only requests that do not need a TODO list. | | Auto Mode (Act phase) | read, grep, find, ls, bash, edit, write, todo, question (+ end_phase in sprint loop) | After planning, the model executes the TODO list with full planning context intact. | | Fast Mode | read, grep, find, ls, bash, edit, write (+ end_phase in sprint loop) | Direct execution mode. No planning requirement, no TODO list, no QnA. Useful for quick edits and simple tasks. |

Modes can be cycled using Tab

Each mode has a different textbox color in the UI, making the current workflow state immediately visible.

Auto Mode

Auto Mode is the default moonpi workflow.

It works in two phases:

  1. Plan phase

    • editing tools are disabled at runtime (blocked by guards, not removed from the prompt)
    • the TODO list tool is enabled
    • the model plans the work
    • the model either:
      • produces a TODO list, then continues to Act phase
      • or calls end_conversation when the user is only asking a question
  2. Act phase

    • editing tools become available (guards no longer block them)
    • the conversation history from the Plan phase is retained
    • the model executes the TODO list with full planning context intact

This avoids the "plan then forget everything" problem.

Prompt Cache Retention

Auto Mode is specifically designed to preserve the LLM provider's prompt cache across the Plan→Act transition. This means:

  • Same system prompt. Both phases use the identical system prompt text. The phase instructions are embedded in a single AUTO_MODE_PROMPT that covers both Plan and Act behavior — the prompt never changes between phases.
  • Same tool schemas. All moonpi tools (read, grep, find, ls, bash, edit, write, todo, question, end_conversation, end_phase) are always present in the tool definitions sent to the provider. Tools are never added or removed between phases.
  • Runtime enforcement only. In Plan phase, editing tools (bash, write, edit) are blocked by moonpi's runtime guards — the tool_call event handler rejects them with an error message. The tool definitions remain in the prompt. When the phase switches to Act, the guards simply stop blocking those tools.
  • Stable tool schemas for cache. Even in Fast mode where todo is disabled, its JSON schema is still advertised to the provider. This keeps the tool definition block identical across all modes and phases, maximizing cache hits.

Why this matters: providers cache the system prompt and tool definitions across turns. When the prompt or tool list changes, the cache is invalidated and the entire prefix must be re-processed — costing tokens, money, and latency. By keeping the prompt and tool schemas stable, Auto Mode ensures the cache is retained throughout the entire conversation, from Plan through Act and beyond.

Project Context Picker

moonpi injects only the files selected with /pick into the model context.

/pick

Opens a file-tree picker for the current working directory:

  • README.md, SPECS.md, and SPRINT.md context files are selected by default
  • use / to move
  • use / to close and open folders
  • use Space to select or deselect files and folders
    • selecting a folder recursively selects all descendant files that match the pickable extensions filter
    • selecting a folder with all descendants already selected will deselect them all
  • use D to deselect everything
  • use Enter to confirm and close the picker

The picker only shows files with pickable extensions (code, text, config, and documentation files). Binary files, images, lock files, and other non-text files are hidden. The extension filter is configurable via pickableExtensions (see Configuration).

/context

Shows which files are currently selected for prompt injection and whether they were auto-discovered at startup or manually selected via /pick.

Example output:

3 file(s) auto-discovered (use /pick to change):
  README.md
  SPECS.md
  SPRINT.md
5 file(s) manually selected with /pick:
  README.md
  src/config.ts
  src/context-files.ts
  src/types.ts
  src/modes.ts

At startup, a notification shows which files are currently selected for injection.

/context:clear

Deselects all currently active context files (both /pick-selected and auto-discovered). After clearing, no files are injected into the prompt until you run /pick again.

Example output:

Cleared context file selection (3 file(s) deselected). Use /pick to select files.

Custom Providers

moonpi includes the support from some custom providers, and provides slash commands to manage custom providers in ~/.pi/agent/models.json.

Synthetic Provider

Moonpi registers Synthetic as the synthetic provider using the OpenAI-compatible endpoint.

Configure credentials with either:

export SYNTHETIC_API_KEY=...

or run:

/login

Use /model to select a synthetic model. Use /synthetic:quotas to show your weekly token and rolling 5h usage quotas:

Synthetic quotas output

Web Search

When authenticated with Synthetic, moonpi makes a web_search tool available to the agent. This tool uses the Synthetic search API to perform zero-data-retention web searches and return results with title, URL, published date, and text excerpt.

The tool is only visible to the LLM when logged in with Synthetic — it is not registered at all when no API key is configured, so the model never sees it or knows it exists.

To disable the search tool even when logged in, set synthetic.search.enabled to false in your config:

{
  "synthetic": {
    "search": {
      "enabled": false
    }
  }
}

Managing Custom Providers

moonpi provides five slash commands to manage custom providers in ~/.pi/agent/models.json:

/custom-provider:add-provider

Interactive wizard that adds a new custom provider. Prompts for:

  1. Provider name — a unique identifier (e.g. my-vllm)
  2. API type — select from all supported APIs (openai-completions, anthropic-messages, google-generative-ai, etc.)
  3. Base URL — the API endpoint (sensible defaults per API type)
  4. API key — your API key or an environment variable name

Example models.json result:

{
  "providers": {
    "my-vllm": {
      "baseUrl": "http://127.0.0.1:8000/v1",
      "api": "openai-completions",
      "apiKey": "none",
      "models": []
    }
  }
}

/custom-provider:add-model

Adds a model to an existing custom provider. Prompts for:

  1. Provider — select from existing custom providers
  2. Model ID — the model identifier (e.g. Qwen/Qwen3-27B)
  3. Display name — optional human-readable name
  4. Advanced options — optional configuration for reasoning, context window, max tokens, image input, and API type override

/custom-provider:scan-models

Auto-detects models from an OpenAI-compatible provider endpoint. Works with providers using openai-completions or openai-responses API.

  1. Select provider — choose from OpenAI-compatible custom providers
  2. Scan — fetches /v1/models from the provider's base URL
  3. Select models — checkbox UI shows all discovered models; already-added models are greyed out
    • Space to toggle individual models
    • a/A to select/deselect all
    • Enter to confirm (adds all new models if none selected)
  4. Auto-fills contextWindow from max_model_len when available

/custom-provider:remove-provider

Removes a custom provider and all its models from models.json. Asks for confirmation before deleting.

/custom-provider:remove-model

Removes a single model from a custom provider. Prompts for the provider, then the model to remove, with confirmation.

After any change, run /reload to refresh pi's model registry and make new models available in /model.

Moonpi loop

moonpi includes sprint-oriented loop for larger projects.

/sprint:init

Creates a new sprint for a larger project.

This command asks one question: the sprint objective.

It then delegates SPRINT.md and TASKS.md creation to the agent, which writes:

./sprints/<sprint_number>/SPRINT.md
./sprints/<sprint_number>/TASKS.md

The sprint is divided into phases.

Each phase includes tasks and verification steps that define when the phase is complete.

The goal is to turn a vague big project into a concrete, phased execution plan.

/sprint:loop

Runs the latest sprint phase-by-phase. Automatically picks the most recent sprint.

The loop works like this:

  1. complete one phase
  2. mark completed tasks in:
./sprints/<sprint_number>/TASKS.md
  1. compact the conversation/context
  2. proceed to the next phase
  3. repeat until the sprint is complete

The model signals the end of a phase by calling a special end_phase tool.

This keeps long-running projects simple, resumable, and grounded in actual files.

Does it work?

Watch a drastically sped-up video of Qwen/Qwen3.6-27B working unattended for over an hour on this sprint prompt:

create WebOS a fully functional web-based operating system with apps, games and everything

https://github.com/user-attachments/assets/92670a55-a3c4-4c31-a4a2-0afc449f0137

And judge the result yourself here.

Configuration

Configure .pi/moonpi.json (project) or ~/.pi/agent/moonpi.json (global):

{
  "defaultMode": "auto",
  "preserveExternalTools": false,
  "customEditor": true,
  "synthetic": {
    "search": {
      "enabled": true
    }
  },
  "contextFiles": {
    "enabled": true,
    "fileNames": ["README.md", "SPECS.md", "SPRINT.md"],
    "maxTotalBytes": 120000,
    "maxDepth": 4,
    "maxScannedEntries": 10000,
    "maxDefaultFiles": 25,
    "pickableExtensions": [
      ".ts", ".js", ".py", ".rs", ".go", ".md", ".json", ".yaml",
      ".toml", ".sql", ".html", ".css", "Dockerfile", "Makefile"
    ],
    "ignoreDirs": [
      ".git", ".svn", ".hg",
      "node_modules", ".next", ".turbo",
      ".venv", "venv", "__pycache__",
      "target", "dist", "build", "coverage",
      ".env", ".gradle", ".idea", ".vscode"
    ]
  },
  "guards": {
    "cwdOnly": true,
    "allowedPaths": ["~/.pi/agent"],
    "readBeforeWrite": true
  },
  "keybindings": {
    "cycleNext": "tab",
    "cyclePrevious": ""
  }
}

General

| Field | Default | Description | | --- | --- | --- | | defaultMode | "auto" | Mode used at session start. One of "plan", "act", "auto", "fast" | | preserveExternalTools | false | When true, tools registered by other extensions are kept alongside moonpi tools when applying mode tool restrictions | | customEditor | true | When false, moonpi skips installing its mode-colored editor, preserving editor customizations from other extensions |

Synthetic

| Field | Default | Description | | --- | --- | --- | | synthetic.search.enabled | true | When false, the web_search tool is not registered even if logged in with Synthetic |

Keybindings

| Field | Default | Description | | --- | --- | --- | | cycleNext | "tab" | Keybinding to cycle to the next mode when the editor is empty | | cyclePrevious | "" (disabled) | Keybinding to cycle to the previous mode when the editor is empty |

Context files

| Field | Default | Description | | --- | --- | --- | | enabled | true | Enable or disable context file injection entirely | | fileNames | ["README.md", "SPECS.md", "SPRINT.md"] | Filenames auto-discovered at startup (before any /pick selection) | | maxTotalBytes | 120000 | Maximum total bytes injected into the prompt. Files are truncated beyond this limit | | maxDepth | 4 | Maximum directory depth for startup auto-discovery only. The /pick picker has no depth limit | | maxScannedEntries | 10000 | Maximum filesystem entries inspected during any scan (startup or /pick). Prevents walking huge trees | | maxDefaultFiles | 25 | Maximum files selected by auto-discovery. Does not affect /pick selections | | pickableExtensions | (80+ entries, see defaults) | File extensions (.ts, .py) and exact filenames (Dockerfile, Makefile) shown in /pick. Non-matching files are hidden from the picker | | ignoreDirs | (40+ entries, see defaults) | Directory names skipped during both auto-discovery and /pick. Covers VCS, language-specific caches, build output, IDE folders, and more |

Guards

| Field | Default | Description | | --- | --- | --- | | cwdOnly | true | Reject file access outside the current working directory | | allowedPaths | [] | Directories permitted for read access even when cwdOnly is enabled. Supports ~ expansion and relative paths (resolved from cwd) | | readBeforeWrite | true | Require the model to read a file before writing or editing it |

Recommended tuning for huge monorepos:

  • lower maxDepth to 2 or 3 if READMEs are mostly near the root
  • lower maxScannedEntries to cap worst-case startup and per-picker-session scanning latency
  • add generated/vendor folders to ignoreDirs
  • narrow pickableExtensions to only the file types you care about
  • lower maxDefaultFiles if too many READMEs are injected by default
  • set enabled: false and use manual @file references if you do not want automatic context injection

If a scan hits a limit, moonpi shows a warning in startup notifications or /pick.

The system prompt also instructs the model to keep selected project documents up to date, making README.md and SPECS.md living project documents instead of abandoned archaeology.

TODO List Tool

moonpi includes a TODO list tool that can be updated at any moment.

Whenever an item is modified, the current full state of the TODO list is returned to the model.

This keeps the agent grounded in the actual progress of the task instead of relying on vibes, memory, or whatever it hallucinated three messages ago.

Filesystem Guardrails

moonpi adds practical file access rules.

Stay inside the working directory

Reads, writes, and edits outside the current working directory are rejected.

This is not presented as magical security theater. It is a behavioral constraint that helps steer the model toward project-scoped work.

Allowed paths

When cwdOnly is enabled, you can grant the agent read access to specific directories outside the project via guards.allowedPaths. This is useful when the agent needs to read its own documentation, extension files, or shared configs that live outside the working directory.

{
  "guards": {
    "allowedPaths": [
      "~/.pi/agent",
      "/home/user/Projects"
    ]
  }
}

Paths support ~ expansion (resolved to home directory) and relative paths (resolved from cwd). Only read access is granted for allowed paths - writes and edits are still restricted to the working directory.

The setting works in both global (~/.pi/agent/moonpi.json) and project-level (.pi/moonpi.json) configs.

Read before write

moonpi requires the model to read a file before writing to it.

If the model tries to write to a file without reading it first, the write tool returns an error.

This prevents careless overwrites and forces the agent to inspect the current state of a file before modifying it.

Why moonpi?

moonpi is not trying to be a giant agent framework.

It does not try to invent a new architecture for every task.

It does not summon a committee of subagents to discuss whether a file should be edited.

It gives the coding agent a simple structure:

  • plan when needed
  • act when needed
  • keep the plan in context
  • inject the right project files up front
  • track work explicitly
  • stay inside the project
  • read before writing
  • compact after meaningful phases
  • keep project docs alive

That is usually enough.

And when it is not enough, it is still better than burning tokens on fake organizational charts for imaginary agents.

Fun Fact: I used moonpi to build moonpi, making it a bootstrapped coding agent.

License

MIT