@quandev104/pi-rules
Native Pi project rules package with rule injection, commands, and background maintenance.
Package details
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
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.