pm logopm

pm

An operating discipline for AI coding agents

Persistent memory · Enforced workflow · Recorded decisions

You install it. Claude lives inside it. pm sits between your coding agent and your codebase — enforcing planning before edits, tracking scope, and recording every choice so the next session doesn't redo what the last one figured out.

$ npm install -g @piotrjura/pmView on GitHub →

Free · Open source · MIT · Local-first · No telemetry

Every session, your agent starts from zero. It re-derives the same architecture, makes the same tradeoffs, and re-asks questions you already answered. pm injects prior decisions and workflow rules into every prompt via Claude Code hooks — context the agent sees whether it asks for it or not.

01 / pillars

Three things pm enforces

Implemented as Claude Code hooks — hard-blocks on edits and prompt injection on every interaction.

01
that survives

Memory

  • Decisions, rationale, and history persist across sessions in .pm/
  • pm decide records every choice with what, why, and how to apply it
  • pm why searches the archive before re-deriving
  • Relevant decisions auto-injected into every prompt
02
that's binding

Discipline

  • Two-phase work: Discovery (plan, ask, align) → Execution (autonomous)
  • Configurable planning, questions, and follow-up depth per project
  • At the strongest setting, edits hard-block until required doctrines are read
  • Settings appear in every prompt so the agent can't drift mid-feature
03
that hold

Guardrails

  • Edit without logged work? Blocked.
  • Issue grows past 4 files? Blocked — upgrade to a feature.
  • 3+ reads without delegating? Subagent nudge surfaced.
  • Stale state, orphaned tasks? Auto-recovered on session start.
02 / in action

What the agent sees

When the agent tries to edit a file but hasn't pulled the doctrines your settings require, the pre-edit hook returns this:

claude-code · pre-edit hook
~/projects/your-app
claude edit src/auth/middleware.ts
✗ BLOCKED — required doctrines not pulled this session
Your settings require these doctrines to be read before any code edit:
pm doctrine planning
pm doctrine questions
pm doctrine followup
pm doctrine decisions
Run all of the above, then retry your edit.
_

At the strongest settings, this is a hard-block — the pre-edit hook returns an error and the agent cannot write to any file until it runs the listed commands.

03 / lifecycle

What a session with pm looks like

  1. 1

    Session starts

    pm injects the doctrine router into context, briefs Claude on what's in progress, and resets the doctrine pull tracker. Claude sees the active task, recent work, and every recorded decision waiting to be searched.

  2. 2

    You give a prompt

    The prompt-context hook fires. Claude sees the active work, your workflow settings (planning=all, questions=thorough, followup=thorough), relevant decisions matched against your prompt, and — if required doctrines weren't pulled yet — a BLOCKING notice with the exact commands to run.

  3. 3

    Doctrines pulled

    Each pm doctrine <name> call is recorded silently. Once all required doctrines are read, the pre-edit hook unblocks.

  4. 4

    Discovery

    Claude reads the planning doctrine, runs pm recap, runs pm why "<keyword>" against past decisions, presents an approach, asks clarifying questions per your settings, and waits for your confirmation.

  5. 5

    Execution

    Tasks are created. Claude starts the first one and writes code. Each edit is allowed because there's active work. Each scope creep past 4 files is hard-blocked. Each Read and Grep is counted — past 3, the prompt-context surfaces a nudge to delegate exploration to a subagent.

  6. 6

    Decisions recorded

    Every choice future-you would benefit from knowing gets logged with pm decide — what, why, and how to apply it. The next session will see them.

  7. 7

    Sweep

    pm sweep closes outstanding items at the end of the conversation. Issues, stale tasks, orphaned drafts — gone. Every session leaves the project clean.

04 / heart

Decisions are always on

A decision is a five-line record: what you chose, why, and what future sessions should do about it. There is no toggle — decisions are recorded and surfaced on every prompt regardless of settings.

recording
$ pm decide _abc \
"Use SQLite over Postgres for cache" \
--reasoning "Single file, no native deps" \
--action "Never add Postgres to auth"
Decision recorded on _abc
searching
$ pm why "storage"
▸ Use SQLite over Postgres for cache
Single file, no native deps. Don't add Postgres to auth.
▸ JSON for config, never YAML
Stdlib parser, no extra deps. Tooling-agnostic.

The prompt-context hook also surfaces matching decisions on every prompt — Claude rarely runs pm why on its own, so pm pushes them in.

05 / doctrines

Ten focused docs, pulled on demand

Small markdown files. The router is always loaded; the rest are pulled with pm doctrine <name>. Each pull is tracked, and the strongest settings hard-block edits until the right ones are read.

router
Always loaded — points at the rest
planning
Before any medium or large change
questions
When asking the user clarifying questions
followup
After initial answers, when more questions emerge
decisionsreq
When making or recording a choice
scope
When an issue feels like it's growing past 1-2 files
sizing
Choosing between an issue and a feature
sweep
Wrapping up a conversation
recovery
Hit a stuck-state block
subagents
About to do 3+ reads or any broad grep
06 / hooks

Five hooks in .claude/settings.json

pm writes these into .claude/settings.json on first run and re-verifies them on every invocation. They merge with your existing hooks. If any are missing, pm restores them.

PreToolUse
Edit | Write
Blocks edits without active work, scope creep, or unread required doctrines
PreToolUse
Read | Grep
Counts exploration ops to drive subagent delegation nudges
PostToolUse
Edit | Write
Tracks files edited and updates scope counters
UserPromptSubmit
(all)
Injects active task, decisions, workflow settings, doctrine pull status
SessionStart
(all)
Reclaims stale tasks, briefs Claude, injects router doctrine, resets pull tracker
07 / settings

Three settings, per project

Run pm settings to cycle. The values appear in every prompt-context injection so the agent can't drift away from your configured depth mid-feature.

setting
planning
nonemediumall

How aggressively the agent must plan before writing any code.

setting
questions
nonemediumthorough

How many initial clarifying questions during Discovery.

setting
followup
nonemediumthorough

How deep the post-analysis follow-up conversation goes.

medium → advisory nudges in prompt context. strongest → hard-block on the pre-edit hook until doctrines are read.
08 / local-first

Everything stays on your machine

All state lives in .pm/ as JSON files. No database, no server, no network calls, no telemetry.

.pm/data.json
Features, issues, phases, tasks, decisions, log entries
.pm/config.json
Per-project workflow settings
.pm/session.json
Edit and read tracking for the active task
.pm/doctrine-session.json
Which doctrines have been pulled this session

Add .pm/ to your .gitignore and you're done.

09 / install

Two commands

install
# via npm
$ npm install -g @piotrjura/pm
# or, run directly
$ npx @piotrjura/pm
initialize a project
$ cd ~/your-project
$ pm
▸ TUI launches
▸ confirms .pm/, hooks, permission
▸ press y
✓ ready

Every subsequent pm invocation re-verifies the hooks and silently restores them. Read the docs →

10 / updates

Sign up

Release notes, doctrine changes, new hooks. Never any spam.