# Sideroom Pi: make "done" mean done

<p align="center">
  <img src="https://raw.githubusercontent.com/RMRdeveloper/sideroom-pi/main/media/logo.png" alt="The Sideroom Pi mark" width="640">
</p>

[![npm version](https://img.shields.io/npm/v/@rmrdeveloper/sideroom-pi?label=npm&logo=npm)](https://www.npmjs.com/package/@rmrdeveloper/sideroom-pi)
[![npm monthly downloads](https://img.shields.io/npm/dm/@rmrdeveloper/sideroom-pi?label=downloads&logo=npm)](https://www.npmjs.com/package/@rmrdeveloper/sideroom-pi)
[![npm license](https://img.shields.io/npm/l/@rmrdeveloper/sideroom-pi?label=license)](https://www.npmjs.com/package/@rmrdeveloper/sideroom-pi)

**The open-source quality layer for Pi.** Your agent asks before it guesses,
follows your code rules on the lines it writes, and reviews its changes
before finishing.

```bash
pi install npm:@rmrdeveloper/sideroom-pi
```

![Sideroom asking a multi-question batch and keeping the live board below it](https://raw.githubusercontent.com/RMRdeveloper/sideroom-pi/main/media/preview.png)

> "Done, everything works." You open the project. The tests are red.
>
> Sideroom is for people who use Pi on real work and are tired of reviewing
> and redoing what the agent delivered. Same freedom and price as Pi; the
> discipline you expect from a senior review.

For developers who chose Pi for control or cost and need the result to be
actually ready: Sideroom is the quality layer that makes Pi follow your
rules, ask when there are two reasonable paths, and review its changes
against the loaded guide before finishing.

## Why Sideroom exists

Every long agent session drifts toward the same failure modes:

1. **Silent guessing.** The agent hits an ambiguous decision and picks
   something instead of asking — because asking in plain chat is awkward
   and easy to ignore.
2. **Invisible work.** "What is it doing? Which step is it on? Did it skip
   something?" Progress disappears into thousands of lines of transcript.
3. **Repo pollution.** Workarounds appear as `todos.json`, scratch notes,
   and half-abandoned plans committed next to real code.
4. **Style drift.** Each session reinvents conventions: nesting depth, error
   handling, naming, validation. Review becomes cleanup.
5. **Unapplied guidelines.** The contract is read, then ignored: a braceless
   `if`, a swallowed error, `console.log`, and `TODO` land in the diff anyway.
6. **Premature completion.** The agent announces it is done while the
   formatter, linter, type checks, or tests were never run.

Sideroom answers each one with a small, opinionated surface:

| Failure | Sideroom answer |
| --- | --- |
| Silent guessing | `sideroom_ask` — questions with an opinion, one batch at a time |
| Invisible work | `sideroom_todo` — a live board above the editor, always one step in focus |
| Repo pollution | Session-branch state — the board and history die with the session, never with a commit |
| Style drift | A pre-edit gate + the on-demand `sideroom-guidelines` skill + an end-of-turn review steer |
| Invisible monorepo skills | `monorepo-skills` — trusted child folders join Pi's available skill list |
| Vague plans | `sideroom-grill` — an interview that settles the words before the work |
| Costly growth and refactors | `sideroom-codebase-design` — evidenced improvements to module design, tests, and long-term scaling |
| Unapplied guidelines | `sideroom_rules` — mechanical checks that block or flag the lines you add |
| Unchecked judgment rules | `jev` — asks a decision model about guide rules with visible evidence |
| Unclear answers | `sideroom_persona` — one voice: direct, plain, and free of unnecessary technical words |
| Premature completion | Guidelines review — asks for relevant checks and reuses valid results |
| Work left unexplained | `explain` — invites a walkthrough in the final response after meaningful work |

## What it feels like

You ask the agent for something non-trivial. Instead of vanishing into a
wall of tool calls, it:

- **Asks like a senior would.** A clean TUI questionnaire appears — tabs for
  several questions, a simple list for one. Every question carries a
  recommendation, and a plural one lets you tick several answers at once. You
  can always answer *Out of scope* or write your own, and everything is written
  in your language. Escape cancels the whole batch. No guessing, no twenty
  follow-up clarifications in chat.
- **Works in the open.** A compact board sits above the editor:
  `pending → in_progress → completed`. Exactly one step is active at a
  time; the agent completes the current step and starts the next one in the
  same move, so skipped steps become structurally hard. The widget shows at
  most five rows, keeps the active step visible, and `F9` opens the full
  read-only board. The board survives reload, tree navigation, and
  compaction.
- **Shows its traces.** Below the board, the last edited files appear as
  clickable `file://` links. `F8` opens the full session history; `R` clears
  it. Only successful Pi `write`/`edit` calls are tracked — no guesses from
  shell output, Git, or subagents.
- **Writes code that reads the same every time.** Before the first edit in
  each agent run, the agent must read the shared contract and the one complete
  guide matching the target language. Premature `write`/`edit` calls are
  blocked. The guides cover guard clauses, braced conditionals, fail-fast
  errors, focused units, and all 20 canonical rules without dumping them into
  the system prompt.
- **Finds the skills below the working directory.** In a trusted monorepo, Pi
  normally ignores project skills stored under child folders. Sideroom scans
  three levels down, adds their `.pi/skills` and `.agents/skills`, and leaves
  duplicate-name warnings to Pi.
- **Cannot sneak sloppy lines past the gate.** Each write and edit is checked
  against the mechanical rules on the added lines only: braceless
  conditionals and swallowed errors block the mutation; vague names, stale
  `TODO`s, commented-out code, and debug output are appended as notes to the
  result. A rule that keeps firing degrades instead of trapping the agent.
- **Reviews before finishing.** The guidelines review asks for missing,
  failed or stale checks and reuses valid results. Check observation never
  forces another response just to run a command.

## What's inside

### `sideroom_ask` — decisions, not interrogations

One call is one 1–N question batch. Each question needs an `id`, a `prompt`,
at least two `{ value, label }` options, and a recommendation:
`recommendationIndex` for the default single answer, or
`selectionMode: "multiple"` with `recommendedIndices` when the question accepts
several. The UI adds the rest: the recommended mark, the always-on *Out of
scope* row, and a custom answer.

TUI-only by design. In print, JSON, or RPC modes it fails fast with
`UI not available` instead of hanging.

### `sideroom_todo` — a board, not a bureaucracy

A display-only, ordered work board. The agent maintains it; you steer through
chat. It never creates a repository task file or a `/todos` command.

- `propose` replaces the full board (interactive TUI only).
- `update` patches `{ id, status?, content? }` items and works everywhere,
  including headless modes.
- Invariant: while anything is pending, exactly one item is `in_progress`.
- Widget: at most five rows — open items before resolved ones, the
  `in_progress` row always visible — plus a `…+N more · F9: view all` hint.
  `F9` opens the full board as a read-only overlay, so the widget stays small
  without hiding work from you; the agent still gets every item in its context.

### Edited files — proof, not promises

Automatic tracking of successful `write` and `edit` results for the active
session. The compact view shows at most five recent paths below an active
board; the extended `F8` view scrolls through everything. Paths outside the
project are labelled `external`. A new session starts clean.

### Browser context — point to the element

Press `F7` to authorize the bundled browser companion once per Pi installation.
It reconnects automatically and remembers Windows and WSL independently; choose
a destination if several Pi sessions are open. Press `Alt+Shift+S` to select
several elements without opening the popup; Escape or the shortcut exits.
Review their local source candidates in Pi and send your
instruction. The click prepares context; it never starts the agent. No project
configuration or framework plugin is needed for inferred source candidates.
For more precise locations, ask Pi to enable visual compiler context in one
project. It prepares the development dependency and configuration, including
projects below your working folder. Compiler locations are checked against local
markup; missing or mismatched locations stay unresolved.
Download [the companion ZIP](https://github.com/RMRdeveloper/sideroom-pi/releases/latest/download/sideroom-browser-extension.zip)
from GitHub Releases, extract it, and load its folder in your browser's developer mode.
No extension store is required; installation and updates are manual. The same
companion ships in the npm package. See [browser context](docs/extensions/visual-context.md)
for installation, Windows/WSL pairing and supported source searches.

### Grill — settle the words first

An on-demand skill for fuzzy plans. It interviews you in `sideroom_ask`
rounds — reading the codebase first so it never asks what the code already
says — until you share one understanding. Its recommendations favor choices
that are easy to maintain and meet known growth needs over the cheapest initial
build. It names the upfront cost; if a missing fact could change the choice,
it asks for that fact before recommending a solution. Resolved terms land in
`CONTEXT.md` the moment they resolve. Only hard-to-reverse, surprising choices
with a real trade-off qualify for a record under `docs/adr/`; the user is asked
first. Everything else stays in the conversation, ready to become a
spec or an implementation. Vocabulary sharpening during the rounds follows
the companion `sideroom-domain-modeling` skill, which also runs on its own
whenever the words — not the plan — are the problem. And when there is no
one to interview at all, `sideroom-domain-scaffold` reads the central
domain code as source of truth, builds or completes `CONTEXT.md` on its
own, and grills the conflicting terms once, at the end.

### Codebase design — improve how the code grows

`sideroom-codebase-design` reviews existing code, identifies where changes or
growth create friction, and designs improvements with small interfaces and
clear responsibilities. It considers growing features, teams, traffic, and
data, using known needs and evidence rather than hypothetical infrastructure.
Each recommendation explains the problem, benefit, cost, confidence, migration,
and verification in text. It produces no diagrams or HTML reports. A review
stays a review; when implementation is requested, it follows the authorized
scope and preserves behavior and compatibility. See
[skill activation](docs/skills.md) for routing and examples.

### Guidelines — a gate, not a novel

A short system-prompt contract points at the packaged
`sideroom-guidelines` skill. Before `write` or `edit`, call
`sideroom_guidelines` with the target file's `path` to load the complete skill
and matching language guide from the packaged catalog. Unsupported languages
load only the general skill. Full `read` calls of the packaged documents also
satisfy the same guard; failed or incomplete loads do not. Reuse loaded guides
in the same run and reload after compaction or a new run. Requires Pi and
pi-tui 1.2.0 or later; call the tool directly, not through another tool.
Each guide mirrors all 20 rules in the canonical seed with idiomatic examples.
The seed, `assets/artifacts/GUIDELINES_TEMPLATE.md`, is never pasted into the
system prompt. After any successful mutation, one hidden review steer fires when
the turn settles and asks the agent to re-check every changed file against the
loaded guide and run the relevant formatter, linter, type checks, and tests —
so the contract is applied, not just read. Rule 20, Decomposition by intent,
asks for coherent named operations that clarify the caller's flow, even with
one caller. It keeps tightly coupled steps together and imposes no line limit.

### Monorepo skills — child skills are still project skills

Pi discovers `.pi/skills` only from its working directory and
`.agents/skills` from that directory and its ancestors. `monorepo-skills`
closes the downward gap: in a trusted project it scans at most three child
levels, respects `.gitignore`, `.ignore`, and `.fdignore`, and contributes the
same skill locations without writing project configuration. Skill bodies stay
on demand; only names, descriptions, and locations enter the system prompt.

Duplicate names keep Pi's precedence and diagnostics. Root and global skills
load before extension paths, so use `pi config -l` to disable one that shadows
a needed child-folder skill.

### Rules — enforcement, not advice

The guidelines gate makes the agent read the rules; `sideroom_rules` makes it
follow them. On every `write`/`edit`, only the added lines are checked against
the mechanical rules from the canonical seed. Braceless conditionals and
swallowed errors block the mutation with an actionable reason; banned
identifiers, stale comments, commented-out code, and debug artifacts are
appended as notes to the tool result. A per-rule circuit breaker degrades a
repeatedly firing block to a note so the agent never dead-locks. No files
written, no config read: the catalog ships with the package.

### Jev — judgment where no check reaches

Reading the guide covers the mechanical rules. `jev` makes one optional call
to TypeSafe's decision model about the changed file and, when available, up to
four directly related source files. It checks guard clauses, fail fast,
command/query separation, null handling, immutability, repeated validation,
responsibility, dependency direction, comments, testability, redundant
abstractions, decomposition by intent, consumer compatibility and test quality
only when the supplied
files support the question. An answer above the cutoff travels with the
end-of-run guidelines review instead of interrupting each edit. READMEs, JSON,
lockfiles, deletion-only edits, and files outside the project are never sent.

It never blocks and never enters the system prompt. No conversation or session
history leaves the machine. Successful questionnaires also send their question
wording and options, without user answers. Newly completed tasks may send their
descriptions, up to four observed changed files and a check status, without
commands or logs. These additional calls review explicit contradictions and
ambiguous choices. Related source excludes ignored, hidden, sensitive-
named and symlinked paths; a normal source file can still contain a secret.
The footer counts the calls the session made, and `F10` shows the same count
beside the key source. Without a key nothing is called, and when Jev runs out of
quota, rejects the key,
or stops answering, the extension goes quiet without touching the turn. A rate
limit only pauses it until your next prompt, and Escape cuts a request in
flight. The key
lives in `TYPESAFE_API_KEY` or in your agent directory, and `F10` captures it
without ever writing it to the session.

### Persona — one voice, not a costume

`sideroom_persona` is the agent's voice, and there is exactly one of it. A
short reminder rides the system prompt on every turn, so it survives
compaction; the full guide lives in the on-demand `sideroom-persona` skill.
The voice is direct and dry, free of filler. It uses everyday words even when
you use technical terms. It keeps a technical term only when needed to
understand or act, and explains it the first time. Emojis and decorative
symbols in the lines a `write`/`edit` adds block the mutation; flattering
openers, hedging, automatic apologies, and AI meta-commentary are answered
with a capped steer. No profiles to switch and no profile selection to store.

### Done — passive check observation

`sideroom_done` detects the project's check command — `package.json` scripts
(`check` → `test` → `lint` → `typecheck` → `types`) with the right
package manager, `pytest`, `go test ./...`, `cargo test`, or a `make check`
target — and observes checks the agent chooses to run. It shares successful
results with guidelines review, so that review can reuse them. It never requests
a continuation to run checks. A coverage notice can join an existing review or
style continuation, but never opens one on its own.

### Explain — the walkthrough invitation

After meaningful changes, review and checks are complete, `explain` lets the
agent end its final response with a short invitation to explain the changes
or how to test them. It skips trivial work and explanations already given.
There is no automatic questionnaire, file-count threshold or extra model turn.
Only after you accept, the agent may clarify the scope through `sideroom_ask`
in the TUI; if your request is clear, it explains directly. A fixed reminder
keeps the system prompt stable across turns. No tool, widget or persisted state.

## Quick path

1. Install globally from npm. Pi records this in your user settings, so do
   not use `-l`.

   ```bash
   pi install npm:@rmrdeveloper/sideroom-pi
   ```

2. Start Pi in the repository you want to work in.
3. Ask the parent agent something that needs a decision or a visible plan.
   It calls `sideroom_ask` or `sideroom_todo` in the TUI.

Pin for reproducibility — a pinned version does not move on Pi's package
update:

```bash
pi install npm:@rmrdeveloper/sideroom-pi@7.0.0
```

Update an unpinned installation with:

```bash
pi update --extension npm:@rmrdeveloper/sideroom-pi
```

## Reference

### Questionnaire contract

Each batch accepts one to four questions, with two to four caller-provided
options per question. A question takes one answer unless it declares
`selectionMode: "multiple"`, which requires `recommendedIndices` and at least
one selection. Tab labels accept at most 16 characters and option labels at
most 60. Inputs that exceed a limit are rejected rather than truncated.

Write prompts, tab labels, and option copy in the language the user is
speaking; keep ids, option values, and TUI chrome in English. Do not send
*Out of scope* or custom-answer rows yourself — the UI always adds them.

### Board contract

Items have stable string ids, short content, and one of `pending`,
`in_progress`, `completed`, or `cancelled`. Complete the current item and
start the next one in the same `update` call. Snapshots live in the active
session branch and are rebuilt after navigation and compaction.

- Widget: max five rows. Open items win the cap over resolved ones, the
  `in_progress` row is always shown, and a `…+N more · F9: view all` line
  appears when rows are hidden.
- Extended view: `F9` toggles a read-only overlay. `↑`/`↓` and `PgUp`/`PgDn`
  scroll; `Esc` or `F9` closes. It never mutates the board.
- The cap is display-only: every item still reaches the system prompt.

A forked session inherits the board visible at its fork point. Later board
updates are reconstructed from each session's active branch, so the fork and
the original session evolve independently.

### Edited-files contract

- Trigger: only successful Pi `write`/`edit` results.
- Compact widget: max five paths, reapplied below the board.
- Extended view: `F8` toggles, `R` clears session history.
- Links: OSC 8 `file://` — click behavior depends on your terminal.

### Guidelines contract

In each agent run, fully read the exact packaged skill path before the first
`write`/`edit`. For Java, PHP/Laravel, TypeScript/TSX, Python, Go, or Rust,
also fully read the packaged guide matching the target path. Reads with
`offset` or `limit`, failed reads, and same-named files elsewhere do not count.
The extension blocks the mutation until the required reads succeed; unsupported
languages use the shared table. Do not route around
the gate through Bash or another file-mutation path. After any successful
`write`/`edit`, one hidden review steer fires on `agent_before_settle` (at most
once per turn) asking the agent to re-check every changed file against the
loaded guide and run the relevant project checks. It is skipped after Escape,
after an error, and while a user message is pending. Interactive input sent
while the agent is idle clears the steer flags; a message typed during a run
and `before_agent_start` do not, so a steer continuation never re-triggers
itself.

### Monorepo-skills contract

- Trigger: `resources_discover` after project trust resolves, in every mode.
- Scope: `.pi/skills` and `.agents/skills` in child folders at most three
  levels below Pi's working directory.
- Traversal: ignore-aware, no directory symlinks, deterministic child-folder
  order, `.pi/skills` before `.agents/skills` inside one folder.
- Safety: untrusted projects and CLI `--no-skills`/`-ns` contribute no paths.
- Collisions: Pi keeps the first name and reports skipped paths. Child-folder
  skills cannot override root or user skills added earlier.
- Prompt: one static, idempotent note prefers the skill whose location matches
  the folder being edited.

### Rules contract

- Trigger: every `write`/`edit` call, in every mode.
- Scope: only lines added by the call. For `edit`, each `oldText → newText`
  pair; for `write`, the new content against the existing file.
- Blocking rules: braced conditionals (rule 1) and explicit error handling
  (rule 5). Warning rules: clear names (6), comments (19), and debug artifacts.
- Blocked calls return the rule id, the reason, and the fix. Warnings are
  appended to the tool result.
- A rule that blocks three times in a run degrades to a warning until five
  clean checks or a new interactive prompt reset it.

### Jev contract

- Off without a key: no request, and behavior identical to a package without
  this extension.
- Warn only. A finding goes to the guidelines review on `sideroom:review-note`
  and rides its end-of-run steer, with one follow-up per turn for notes that
  arrive after the review fired; nothing blocks and nothing reaches the system
  prompt.
- One request per successful `write`/`edit` of a project file in a supported
  language that added lines, with applicable `noul` questions on the complete
  changed file and up to four directly related source files, prioritizing tests
  and production consumers before imports.
- One additional request per successful, non-cancelled questionnaire and per
  eligible completion update. Only validated question wording or targeted
  completion descriptions and bounded observed evidence travel; no answers,
  conversation history or command output. All requests share the same limits.
- The official 32k-token state-plus-longest-question and 64k-token request
  limits are observed conservatively using 32,000 and 64,000 UTF-8 bytes.
  Oversized neighbours are omitted whole; if the changed file cannot fit,
  the call is skipped. An answer at or above `0.8` becomes a note.
- The request follows the run's abort signal; a cancelled request is not a
  failure.
- Quota (`402`) and a rejected key (`401`, `403`) stop the calls immediately. A
  rate limit (`429`) pauses them until the next idle prompt. Network errors and
  other `4xx`/`5xx` stop after three consecutive failures. A success rearms the
  breaker, and `F10` rearms it by hand.
- Every request increments a session call counter, shown in the footer and on
  `F10`; it resets on `session_start` and is never persisted.
- The key comes from `TYPESAFE_API_KEY` or from
  `getAgentDir()/sideroom.json` at mode `0600`, and never enters the session.

### Persona contract

- One built-in voice. No profiles, no switching, and no persisted profile
  state; runtime guard counters stay in memory. The footer shows the run's block
  and steer counts (`persona: direct · 2 blocks · 1 steer`) and drops back to
  `persona: direct` on the next run.
- Injection: a short reminder appended in `before_agent_start`, chained after
  the other extensions and idempotent by heading, so it returns after
  compaction.
- Blocking: decorative symbols in the lines a `write`/`edit` adds. Full rewrites
  resolve Pi path aliases before comparing existing content; semantic copyright,
  trademark, and registration symbols remain valid. Three fires degrade the
  prohibition to a steer; five clean mutations reset the counters.
- Steering: one corrective message per violating assistant message, at most
  three per run.
- `sideroom_persona` takes no arguments and returns every rule and every
  prohibition with its enforcement mode.

### Done contract

- Detected command: `package.json` scripts in priority order with the
  lockfile's package manager, then `pytest -q` for Python, `go test ./...`,
  `cargo test`, or `make check`. Detection is cached per working directory.
- Green means that command ran with a zero exit in this run. A later
  successful `write`/`edit` clears green again.
- Observation only: no standalone check or coverage continuation. Coverage
  notices join another necessary continuation at most once per user turn.

### Explain contract

- Delivery: a fixed, idempotent reminder on `before_agent_start`; no per-turn
  state is interpolated into the system prompt.
- After meaningful work, review and checks, the agent may include one short
  invitation in the final response, in the user's language. Trivial work,
  explanations already provided and requests for no follow-up skip it.
- No file-count threshold, automatic questionnaire, closing hook or extra turn.
- After explicit acceptance, clarify scope through `sideroom_ask` only when
  needed in the TUI. Otherwise explain directly, or clarify in ordinary
  conversation outside the TUI.

### Grill contract

Load the skill at the start of a change with a fuzzy plan.
Single-session scope only. Files are created lazily: nothing exists until
the first term or decision crystallises. A session with a sharper glossary
and zero ADRs is working as designed.

### Coexisting with other grilling skills

See [skill activation](docs/skills.md) for selection boundaries and discovery
diagnostics. Pi routes skills by description, not by name, so several grilling
skills can be installed at once. `sideroom-grill` claims non-trivial plans before
implementation and states precedence over other grilling, interview, and spec
skills. If a third-party skill still wins, remove it from routing by adding
`disable-model-invocation: true` to its frontmatter, or exclude its path with
`-path` in `settings.skills`. A literal name collision keeps the first skill
found: project `.pi/skills`, then project `.agents/skills`, then
`~/.pi/agent/skills`, then `~/.agents/skills`, then packages. Child-folder
paths contributed by `monorepo-skills` come later and cannot override any of
them.

## Documentation

Maintainer reference lives in [`docs/`](docs/README.md): the
[architecture](docs/architecture.md) and one page per
[extension](docs/extensions/ask.md).

## Contributing

Contributions are welcome: bug reports, feature requests, language guides, and
pull requests. Start with [`CONTRIBUTING.md`](CONTRIBUTING.md) for setup, the
commands, the design rules, and the branch and release flow — pull requests
target `develop`, and `main` only carries releases.

- [Report a bug](https://github.com/RMRdeveloper/sideroom-pi/issues/new?template=bug_report.yml) or [request a feature](https://github.com/RMRdeveloper/sideroom-pi/issues/new?template=feature_request.yml).
- Report vulnerabilities privately through [`SECURITY.md`](SECURITY.md).
- Participation is covered by the [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md).

## License

MIT.
