<div align="center">
  <img src="https://raw.githubusercontent.com/MonsieurBarti/The-Forge-Flow-CC/refs/heads/main/assets/forge-banner.png" alt="The Forge Flow" width="100%">

  <h1>📐 @the-forge-flow/pi-rules</h1>

  <p>
    <strong>Auto-load path-scoped rule files for the PI coding agent</strong>
  </p>

  <p>
    <a href="https://github.com/MonsieurBarti/pi-rules/actions/workflows/ci.yml">
      <img src="https://img.shields.io/github/actions/workflow/status/MonsieurBarti/pi-rules/ci.yml?label=CI&style=flat-square" alt="CI Status">
    </a>
    <a href="https://www.npmjs.com/package/@the-forge-flow/pi-rules">
      <img src="https://img.shields.io/npm/v/@the-forge-flow/pi-rules?style=flat-square" alt="npm version">
    </a>
    <a href="LICENSE">
      <img src="https://img.shields.io/github/license/MonsieurBarti/pi-rules?style=flat-square" alt="License">
    </a>
  </p>
</div>

---

PI extension that auto-loads path-scoped rule files from `.pi/rules/` and `.claude/rules/`. When the agent reads, edits, or writes a file, every rule whose `paths` match that path is injected into the context for that turn.

## Install

```bash
pi install npm:@the-forge-flow/pi-rules
```

## Quickstart

1. Create `.pi/rules/style.md`:

```md
---
description: TypeScript style for src/.
paths:
  - "src/**/*.ts"
---
Prefer named exports. Avoid `any`.
```

2. Run `pi -p "Read src/index.ts"`.
3. The rule body now prefaces the tool's read result.

## Rule format

```yaml
---
description: Short summary
paths:
  - "src/**/*.ts"
---
Body markdown here. Injected verbatim when the rule fires.
```

- `description` — required string.
- `paths` — optional `string` or `string[]` of picomatch-compatible, project-relative patterns. **Omit** for always-on rules. Accepts a YAML array (`["src/**/*.ts"]`) or a comma-separated string (`"src/**/*.ts, lib/**/*.ts"`).

The legacy `globs` field is still accepted with a deprecation warning, and the legacy `alwaysApply` field is ignored with a warning.

## Matching & injection

When `read` / `edit` / `write` fires on a path, every matching rule (or always-on rule with no `paths`) prepends its body to the tool's result for the next model turn. No precedence: all matching rules apply, in discovery order. Once-per-session dedup keyed by realpath.

## Hot reload

Edits to rule files (create / modify / delete / rename) during a running session trigger a matcher recompile; subsequent `tool_result` injections reflect the new rule set. Watcher errors emit a stderr warning and keep the last-known matcher.

## Two directories, one format

`.pi/rules/` and `.claude/rules/` are both first-class. They behave identically and may both be present. A rule symlinked between them counts once (realpath identity).

## Per-user rules

Rules under `~/.pi/rules/` and `~/.claude/rules/` apply to every project on the machine. They merge with project rules; realpath dedup applies across both sources. Missing directories are silently skipped.

## Authoring rules

This package ships a `rule-authoring` skill at `dist/skills/rule-authoring/SKILL.md`. PI agents that load skills will pick it up automatically; humans can read the source at `src/skills/rule-authoring/SKILL.md`. The skill covers the frontmatter contract and a terse, readable style — every char in a rule body ships on every match, so the savings from concise rules compound across a session.

Worked examples:

- `examples/.pi/rules/typescript-style.md` — path-scoped project rule.
- `examples/.claude/rules/always-be-terse.md` — always-on rule (no `paths`).

## Diagnostics

Inside a running pi session, type `/pi-rules doctor` to print a discovery report: every rule with id, source path, paths, plus any parse errors and skipped files. The report header is `pi-rules doctor: OK …` when discovery is clean and `pi-rules doctor: ERRORS …` when any rule failed to parse.

## Limitations

- Compaction-survival: if pi-coding-agent compacts the conversation, injected text is dropped. Not re-injected.
- Once-per-session dedup is by realpath. Two independent files with identical bodies inject twice.
- No precedence / conflict resolution. All matching rules apply, in input order.
- Parse errors (invalid YAML, missing `description`, malformed `paths`) skip the file with a stderr warning. Discovery does not abort.
- Custom tools (`bash`, `grep`, `find`, `ls`, custom) do not trigger injection. Only `read` / `edit` / `write`.

## Migrating from `.claude/rules/`

Already have `.claude/rules/`? Install the package — same files, same matching, no migration needed. The format on this page is the one used in `.pi/rules/`. If your existing files use a different convention (no frontmatter, etc.), they'll be skipped with a stderr warning until you add the frontmatter shown above.

## Development

```bash
bun install
bun run check     # biome lint + format
bun test
bun run build
```

`bun run test:e2e` exercises the extension under the live `pi` binary. Requires a working `pi` provider config (e.g., `FIREWORKS_API_KEY`) and the `pi` binary on disk via `bun install`. Costs a few cents per run. Not run in CI. If the test fails because the model declined to call the `read` tool (rare, but cheap fast models occasionally ask for clarification), re-run.

## License

MIT
