@quandev104/pi-rules

Native Pi project rules package with rule injection, commands, and background maintenance.

Packages

Package details

extensionskill

Install @quandev104/pi-rules from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@quandev104/pi-rules
Package
@quandev104/pi-rules
Version
0.1.11
Published
Aug 26, 2026
Downloads
339/mo · 30/wk
Author
quandev104
License
MIT
Types
extension, skill
Size
536.3 KB
Dependencies
0 dependencies · 4 peers
Pi manifest JSON
{
  "extensions": [
    "./dist/extensions/pi-rules.js"
  ],
  "skills": [
    "./skills"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

@quandev104/pi-rules

CI npm license

Pi extension for path-scoped project rules. It discovers .pi/rules/**/*.md, matches rules to the files an agent is working on, injects relevant guidance, and lets agents recommend rule updates for user approval.


Install

pi install npm:@quandev104/pi-rules

Bootstrap rules for a project:

/pi-rules:init

Rules live in:

.pi/rules/**/*.md

Quick example

---
paths:
  - "src/api/**/*.ts"
summary: API handler conventions
triggers:
  - "create endpoint"
  - "add route"
priority: 10
guard: true
---

# API Rules

- Validate input with Zod.
- Return `Result<T>`; do not throw from handlers.
- Wrap authenticated routes with `withAuth()`.

When the agent works on src/api/login.ts, this rule can be injected into context. If guard: true and write guard is enabled, write/edit is blocked until the rule has been shown to the agent.


Config

Config files are optional.

Scope Path
Global ~/.pi/agent/pi-rules/config.json
Project .pi/pi-rules/config.json

Precedence:

defaults < global config < project config < env vars < CLI flags

Recommended low-noise setup in .pi/pi-rules/config.json:

{
  "mode": "static",
  "dynamicInjection": "off",
  "writeGuardEnabled": true
}

Config fields

Field Type Default
disabled boolean false
mode "static" | "dynamic" | "both" | "off" "both"
dynamicInjection "off" | "full" "full"
writeGuardEnabled boolean false
recommendationEnabled boolean true
widgetEnabled boolean true
appliedWidgetEnabled boolean true
maxRuleChars number 12000
maxContextChars number 40000
maintainerLogLines number 100

Environment variables

Variable Description
PI_RULES_DISABLED=1 Disable extension
PI_RULES_WRITE_GUARD=1 Enable write/edit guard
PI_RULES_DYNAMIC_INJECTION=off|full Control dynamic rule injection
PI_RULES_MAX_RULE_CHARS=12000 Per-rule body cap
PI_RULES_MAX_CONTEXT_CHARS=40000 Total context cap per injection
PI_RULES_MAINTAINER_LOG_LINES=100 Maintainer log tail length
PI_RULES_RECOMMENDATIONS_DISABLED=1 Disable rule recommendations
PI_RULES_APPLIED_WIDGET=1|0 Force-enable (1) or disable (0) the applied-rules chat annotation (on by default)

CLI flags

--pi-rules-disabled
--pi-rules-mode static|dynamic|both|off
--pi-rules-dynamic-injection off|full
--pi-rules-write-guard
--pi-rules-recommendations
--pi-rules-widget
--pi-rules-applied-widget

Applied-rules chat annotation

On by default: when an injection contains rules not already shown for the current agent run, a dim annotation is appended to the chat transcript:

├─ core/csharp.md       **/*.cs
└─ architecture/module-structure.md  src/Modules/**

Each line shows the rule file and how it matched (alwaysApply, a glob pattern, or a trigger phrase). Repeated injections of the same rule in one agent run are shown only once; newly discovered rules add a compact entry. The annotation persists in the session — it is display-only and never sent to the model context. Requires pi >=0.80.4 (custom entry renderers). To turn it off, set appliedWidgetEnabled: false in the config file or PI_RULES_APPLIED_WIDGET=0.


Injection model

Mode Behavior
static Inject matching rules at the start of the agent turn.
dynamic Inject matching rules after tool results.
both Static + dynamic. Default.
off Do not inject rules.

Dynamic injection can be muted independently:

{
  "dynamicInjection": "off"
}

This still tracks touched paths, but avoids appending full rules during exploration.

Write guard

Enable:

{
  "writeGuardEnabled": true
}

Then mark critical rules:

guard: true

Flow:

agent calls edit/write
→ pi-rules matches target path
→ if a guarded rule has not been injected: block tool call + show rule
→ agent retries with the rule in context

Currently guarded tools:

write, edit

Rule frontmatter

---
paths:
  - "src/auth/**/*.ts"
ignorePath:
  - "docs/**"
summary: Auth conventions
triggers:
  - "login flow"
alwaysApply: false
priority: 10
kind: rules
guard: true
---
Field Type Description
paths string | string[] Glob patterns matched against project-relative paths.
ignorePath string | string[] Glob patterns excluded from matching. The rule is skipped when every target path matches one of these patterns (e.g. alwaysApply rules that should stay silent while editing docs/).
summary string One-line routing summary.
triggers string | string[] Prompt phrases that should load the rule.
alwaysApply boolean Inject on every code-related turn. Use sparingly.
priority number Higher priority rules are injected first.
kind "rules" | "inventory" rules are injected; inventory files are listed as available.
guard boolean Require this rule before write/edit when write guard is enabled.
description string Human-readable description; not used for matching.

Parent/child behavior

When parent and child rules both match, child rules are injected fully and parent rules are summarized.

.pi/rules/api/api.md          → summary only
.pi/rules/api/auth/auth.md    → full body

Ignoring paths (ignorePath)

ignorePath excludes target paths from a rule. A rule is skipped when every target path of the turn matches one of its ignorePath patterns — useful for alwaysApply rules that would otherwise be injected (and waste tokens) while the agent only edits docs/.

---
paths:
  - "**/*"
alwaysApply: true
summary: Code conventions (skipped while editing docs)
ignorePath:
  - "docs/**"
  - "README.md"
---

Two strictness levels:

  • alwaysApply: true + ignorePath — still injected on signal-less turns (no path tokens in prompt, no tool activity yet) that are code-related.
  • paths: ["**"] + ignorePath — strictest: never injected when the turn carries no path signals at all, and skipped when all targets are ignored. Prefer this when the rule only matters for real code work.

Additionally, alwaysApply + ignorePath rules are suppressed entirely on non-code turns that carry no path signals (e.g. "improve the wording in the documentation"), since there is no target for the ignore check to evaluate.


Commands

Command Description
/pi-rules:init [...prompt] Bootstrap .pi/rules/.
/pi-rules:status Show rules, diagnostics, and pending recommendations.
/pi-rules:mode [static|dynamic|both|off] Set project injection mode; opens a selector when no arg is passed.
/pi-rules:write-guard [on|off] Configure project write/edit guard; opens a selector when no arg is passed.
/pi-rules:doctor Rule discovery diagnostics.
/pi-rules:context Show last injected rules.
/pi-rules:cleanup Show recommendation storage location.

Tools

Tool Description
create_rule Create a .pi/rules/*.md rule file.
pi_rules_recommend Queue a rule update recommendation for user approval.

Recommendations

Agents do not rewrite rules directly. They create recommendations, and the user approves them.

agent identifies a convention
→ pi_rules_recommend creates pending recommendation
→ user reviews and approves through the pi-rules TUI
→ maintainer skill updates the rule

Recommendation state is stored under:

.pi/.pi-rules/recommendations.json

Architecture

shared → domain → features → app → pi
extension-src/pi-rules/
├── shared/     path, fs, hash, glob, frontmatter
├── domain/     parser, scanner, matcher, formatter, engine
├── features/   recommendations, watcher, tool path extraction
├── app/        config, runtime state
└── pi/         Pi event handlers, commands, tools

Layer boundaries are enforced by dependency-cruiser.


Development

npm install
npm run typecheck
npm run lint
npm run depcruise
npm test
npm run build
npm run check

Current test suite: 223 tests.


License

MIT