Install PHARN into an existing project: a reviewable workflow for AI-written code.
PHARN is an open, audit-grade methodology for Claude Code. It keeps the intent, constraints, plans, checks, and review trail for AI-assisted changes in plain files inside your repo, so the reasoning behind a change survives beyond the chat window.
npx @pharn-dev/pharn@latest init- What is PHARN?
- Why use it?
- Quick start
- How it works
- What gets installed
- After install
- Day-to-day workflow
- CLI commands
- Safety model
- Current scope
- Documentation
- Development
- Security
- License
PHARN is a repo-local methodology for making AI-assisted development easier to review, repeat, and maintain. It gives Claude Code a structured path from feature intent to implementation review:
spec -> plan -> grill -> test -> build -> regress -> verify -> ship
The npm package, @pharn-dev/pharn, is the installer. It does not scaffold your
app. It detects what kind of project you already have, installs the matching
PHARN capabilities from pharn-dev/pharn-oss,
and records the install in pharn.config.json and pharn.records.json.
AI agents can move fast, but a fast diff without durable context is hard to trust. PHARN is built around a simple idea: the reasoning behind a change should be committed beside the change.
- Preserve intent. Specs, plans, constraints, and review notes live in the repository, not only in an agent transcript.
- Make work inspectable. PHARN installs grillers and lenses: pipeline auditors and review perspectives that help interrogate a plan or diff before it ships.
- Keep updates safe.
pharn updateuses per-file hashes to avoid overwriting local edits unless you explicitly choose--force. - Stay tool-shaped, not service-shaped. The CLI fetches open content, copies files into your project, and leaves the state in version-controlled markdown and JSON.
Run PHARN inside an existing git project:
npx @pharn-dev/pharn@latest initFor a new app, initialize git before installing PHARN:
npx create-next-app@latest my-app
cd my-app
git init
git add -A
git commit -m "init"
npx @pharn-dev/pharn@latest initAfter install, open Claude Code in the project and start with:
/pharn-spec
Or run the whole chain in one command:
/pharn-loop implement password reset with a one-time token
Either way the run begins at the spec, and it has to: /pharn-plan enforces a
deterministic input gate and halts unless an Approved, un-drifted SPEC.md
already exists, so there is no entry point further down the chain. The exact
command files come from the pharn-dev/pharn-oss version installed into your
repo.
Your project needs a test runner with per-test results. The test stage
writes each acceptance criterion's test before any code exists and requires it
to fail, so it needs a test script (plus test:e2e or e2e for end-to-end
criteria) whose reporter writes per-test JSON, named under testResults in
pharn.config.json. Without one, /pharn-test stops and asks, and
/pharn-loop ends with blocked: no-test-runner. A fresh app like the
create-next-app one above has no test script, so set the runner up first,
as its own increment (a SPEC with spec_kind: test-infra). Setup is in
upstream's
Per-test results.
pharn init is archetype-driven. There is no stack questionnaire and no module
catalog.
| Step | What happens |
|---|---|
| Detect | Reads package.json dependency names and performs a bounded, symlink-safe file-tree scan to classify the project as ssr, backend, spa, lib, or a combination. |
| Fetch | Resolves pharn-dev/pharn-oss@main to a commit SHA, downloads the GitHub codeload tarball, and extracts it into a temp directory. |
| Resolve | Selects capabilities whose applies value is universal or intersects your detected archetypes. Skipped capabilities are named with the reason. |
| Install | Copies the selected capabilities plus fixed PHARN product surfaces into your repo, mirroring the upstream layout. |
| Record | Writes pharn.config.json and pharn.records.json so future updates can tell PHARN-owned files from local edits. |
The current upstream install layout places most runtime surfaces under pharn/
and Claude Code integration under .claude/. Older flat-layout installs are
still understood through the recorded layout field.
| Artifact | Purpose |
|---|---|
pharn/pharn-pipeline/grillers/<name>/, pharn/pharn-review/<name>/ |
Pipeline auditors and review lenses selected for your project archetype(s). |
.claude/commands/, .claude/hooks/ |
The installed /pharn-* Claude Code slash commands and deterministic .cjs hooks. |
pharn/pharn-contracts/, pharn/floor/ |
Schemas shared across PHARN stages and floor checkers invoked by the workflow. |
pharn/pharn-core/ |
Agent-readable mechanism skills, including the seam resolver. |
pharn/CONSTITUTION.md, pharn/ARCHITECTURE.md |
Trusted PHARN docs copied from upstream in the current layout. |
THREAT-MODEL.md, LIMITS.md |
Trusted PHARN docs copied at the project root in the current layout. |
pharn/LICENSE (flat: PHARN-LICENSE) |
PHARN's Apache-2.0 license copy. Your root LICENSE is never overwritten. |
pharn/features/README.md |
The feature-loop boundary contract referenced by installed commands (pharn layout). |
pharn.config.json |
Installed version, commit, layout, archetypes, capabilities, and defaults. |
pharn.records.json |
Per-file hashes for drift-safe updates. Commit this with the config. |
An existing .claude/settings.json is preserved. PHARN may create it when
absent, but it never overwrites your Claude Code settings.
As you run the workflow, PHARN writes one directory per increment —
pharn/features/<name>/ — holding that increment's SPEC.md, PLAN.md,
AC-TESTS.md, GRILL.md, BUILD.md, REGRESSION.md, VERIFY.md, then
SHIP.md + BRIEFING.md (/pharn-ship) or LOOP.md (/pharn-loop), a
RUN-REPORT.md, and the machine-readable records beside them
(AC-TESTS.lock.json, cost.json, the *-report.json files). Those are the
durable record; commit them. .pharn/ (runtime scratch), .pharn-backup/ (see
Safety model) and .pharn.lock are not — add them to your
.gitignore. PHARN never edits .gitignore for you.
Two version numbers, on purpose. The npm package @pharn-dev/pharn carries
the installer's version. The content it installs carries its own,
recorded as skillsVersion in pharn.config.json and taken from upstream's
SKILLS_VERSION. They move independently, and pharn status / pharn update
are keyed to the latter.
Three things about the installed hooks are worth knowing on day one.
Hooks enforce only once they are registered in .claude/settings.json. If
your project already had that file, PHARN preserved it and printed a warning
instead of overwriting it — so until you copy the hook wiring across, every
guarantee that depends on a PreToolUse hook is inactive.
Once wired, the write guard is fail-closed. With no active scope, Claude
Code's Write/Edit/MultiEdit/NotebookEdit tools are restricted to
pharn/features/** and .pharn/**; ordinary edits to your own source are denied. That is the
intended posture — a stage sets the scope from the concrete paths your
PLAN.md declared — but it means the guard is not a drop-in for editing
outside a PHARN run. Clearing the scope returns to this default; it does not
re-open your source.
Writes issued through Bash bypass both write guards entirely.
/pharn-loop has a Stop guard too. require-loop-record.cjs is not a
write guard: while an unattended /pharn-loop run has written no LOOP.md, it
refuses to let the turn end, a bounded number of times, and it fails open. It
also does nothing until registered — under Stop, with no matcher. The
settings.json upstream ships has registered it since pharn-oss 6.12.0, but a
file PHARN preserved, or one created by an earlier install, lacks the entry:
copy it across by hand. pharn update never edits .claude/settings.json;
pharn status and pharn update name the missing entry in a HOOKS note.
The full set of bounds lives in upstream's
LIMITS.md and
README.
Once PHARN is installed, use the slash commands from Claude Code. The pipeline is eight typed stages, each reading what the previous one produced:
| Stage | Command | Purpose |
|---|---|---|
| Spec | /pharn-spec |
Capture feature intent and scope. Stops for your approval. |
| Plan | /pharn-plan |
Turn the approved spec into an implementation plan, mapping each acceptance criterion to a test (AC-TESTS.md). |
| Grill | /pharn-grill |
Challenge the plan before code is written. |
| Test | /pharn-test |
Write each acceptance criterion's test before the build, run it, and require it to fail. /pharn-build refuses to start without that evidence. |
| Build | /pharn-build |
Implement an approved increment. |
| Regress | /pharn-regress |
Look for regressions outside the just-built feature. |
| Verify | /pharn-verify |
Verify behavior and PHARN floor requirements, including that every acceptance criterion's test now passes. |
| Ship | /pharn-ship |
Run stages 1-7 in order, then stop at the merge/fix/abandon gate. |
/pharn-ship is itself the eighth stage: it orchestrates the seven before it in
one pass, so you rarely run them by hand, and it keeps both human gates —
approve the spec before code is written, decide merge/fix/abandon after
verification. /pharn-loop runs that same chain unattended: the model approves
the spec, iterates build -> regress -> verify until green, an iteration cap, or
a terminal failure, commits a green result to a new local branch (never pushed
or merged), and leaves the merge/fix/abandon decision to you after the run.
/pharn-spec fills PHARN's default SPEC template, or your own if you put one at
pharn.spec-template.md in the project root. The write guard denies Claude
Code's edit tools on that path, so edit it yourself; see upstream's
Your own SPEC template.
Two commands sit outside the pipeline:
| Command | Purpose |
|---|---|
/pharn-review |
Run the review lenses in parallel over any code and merge their findings deterministically. Standalone — no pipeline stage invokes it. |
/pharn-memory-promote |
Promote one lesson into memory-bank/ through a gated provenance check. |
| Command | Description |
|---|---|
pharn init |
Detect archetypes and install matching capabilities. This is also the default when no command is given. |
pharn add [capability] |
Add one capability manually, for example a11y or lens:n-plus-one. With no argument, opens an interactive picker. |
pharn remove [capability] |
Remove one installed capability. With no argument, opens an interactive picker. |
pharn update |
Re-fetch and apply the latest PHARN content using drift-safe per-file decisions. --force overwrites files you changed; --yes/-y skips the confirmation prompt. |
pharn list |
Show installed archetypes and capabilities. Use --json for machine-readable output. |
pharn status |
Read-only version and drift report. Use --strict to make drift fail CI, or --no-drift to skip byte comparison. |
pharn --help |
Show command help. |
pharn --version |
Show the installed CLI version. |
init also accepts --archetype, a deprecated no-op kept for one release —
archetype detection is now the default.
Three behaviours matter if you script the CLI:
- Options are per-command. Passing one a command does not take prints
Unsupported option for `status`: "--json"to stderr with the usage text and exits 1; an extra positional is refused the same way. Both previously parsed, were silently dropped, and exited 0. initandupdateare interactive-only. Off a TTY they exit 1 rather than prompting into a dead stream.update --yesis the way through in CI;initdeliberately has no--yes, because its second prompt is the destructive overwrite confirmation.- One writer at a time.
init,add,removeandupdatetake an advisory lock at.pharn.lock; a second run refuses rather than queueing.add,removeandupdatealso re-readpharn.config.jsononce they hold the lock, and refuse — writing nothing — if another run changed it after they read it (for example while a confirm prompt was open).listandstatusnever take it and are never blocked by one, sopharn status --strictstays runnable in CI while an update is in flight.
PHARN is intentionally conservative about writes:
initchecks for existing install targets and asks before overwriting them, and refuses the whole install — writing nothing — when a destination path crosses a symlinked directory.updateusespharn.records.jsonto skip files it cannot prove are untouched.update --forcebacks up overwritten files under.pharn-backup/<timestamp>/before writing.adddoes the same for any destination file that differs from upstream, and refuses the whole install — writing nothing — when a destination path crosses a symlinked directory.statusandlistare read-only.removedeletes only the selected capability directory and prunes its records; it never touchesCONSTITUTION.md,memory-bank/, or your detected archetypes, and refuses when that directory's path crosses a symlink.
PHARN can also refuse to install at all: if upstream declares a minimum CLI
version newer than yours, init/add/update stop with a named error before
writing anything.
Remote content is treated as untrusted input. Capability names, copyable file names, versions, commit SHAs, and paths are validated against strict allowlists; path traversal and symlink escapes are rejected; copied file contents are not executed by the CLI.
PHARN is intentionally scoped:
- It targets Claude Code today. Codex and Cursor support are planned, not shipped.
- It requires a git-initialized project and Node >= 20.13.0 (the floor its prompt library needs). CI runs on Node 24, and a smoke job starts the packed CLI on exactly Node 20.13.0.
- Archetype detection is JS/TS-shaped. The signals are
package.jsondependency names plusnext.config.*,app/route handlers,.tsx/.jsx,migrations/and.sql. A Python, Go or Rust repo produces no signal, resolves tolib, and receives the universal capabilities only — a correct outcome, not a failure. - It does not scaffold your application or install framework packages.
- It does not replace tests, human review, or release judgment. It gives those activities a structured record and repeatable workflow.
statusreports modified, missing, and unreadable PHARN-owned paths; orphaned-file detection is still planned.
See the roadmap for shipped versus planned work.
Start here: docs/
npm install
npm run dev -- init
npm run build
npm run test
npm run checkUseful scripts:
| Script | Purpose |
|---|---|
npm run typecheck |
Type-check source and tests. |
npm run lint |
Run ESLint with zero warnings. |
npm run lint:md |
Run markdownlint over docs and root markdown. |
npm run test:coverage |
Run the Vitest coverage gate used by CI. |
npm run build:install-local |
Build and install the local CLI into local test apps. |
Set PHARN_DEBUG=1 for verbose fetch and install errors. See
CONTRIBUTING.md for contributor notes and release discipline.
The CLI has a small trust boundary: it downloads PHARN content from GitHub, validates and extracts it, then copies selected files into your project. The security-sensitive path validation, tar extraction, symlink handling, and update decision tables are covered by tests.
Please report vulnerabilities through SECURITY.md, not public issues. The detailed model is in THREAT-MODEL.md and LIMITS.md.