Getting started
From an empty folder or an existing repository to checked memory in a few minutes. Every step shows the real command output.
Requirements
Node.js 20 or newer. Git is optional: everything works without it, except the doctor's staleness check, which compares commit times and reports itself as not evaluated outside a git repository.
These pages document 1.0.0. On an earlier release init writes a larger set
of files than shown here and some commands differ — check what you have with
npm ls -g persist-os and upgrade with
npm install -g persist-os@latest.
Upgrading from 0.6: after installing, run persist doctor. It warns about
each skill directory that is no longer in the built-in catalog and prints the command
to remove it; a skill you wrote yourself can stay.
Install
Run it without installing:
$ npx persist-os@latest init
Every command works the same way through npx persist-os <command>.
Or install the persist binary globally:
$ npm install -g persist-os
$ persist --help
Initialize repository memory
persist init writes six memory documents, a decision directory, the agent
entry points, the git hooks, and a CI workflow. It never overwrites a file that already
exists, and it never touches your git configuration. Preview the writes first if you
like:
$ persist init --dry-run
On a terminal, init asks five questions first: which AI tools to generate files for,
whether to track features, whether to track modules, whether to enable the test
gate (it prints the detected test command before asking), and whether to enable the
Chesterton fence. Empty answers take the defaults shown in brackets.
--yes takes every default without asking, and any explicit flag such as
--features skips the questions too. The run below was recorded with
stdin piped, so it took the defaults and said so:
$ persist init
persist repository memory for AI-assisted software work
────────────────────────────────────────
Persist OS init complete.
Test gate: not configured — no one-shot test script detected (set testCommand in .persist/config.json to enable `persist test-gate`).
Chesterton fence: enabled (record why code is shaped this way in docs/60-engineering/FENCES.md; toggle fenceEnabled in .persist/config.json).
stdin is not a TTY — proceeded with defaults without prompting (as --yes).
Generated repository memory, 6 agent skills (.claude/skills/ and .agents/skills/), pre-commit and pre-push hooks, a CI workflow, a Claude SessionStart hook, and a Cursor rule that load memory automatically.
Created:
- .persist/config.json
- AGENTS.md
- CLAUDE.md
- .cursor/rules/persist-memory.mdc
- docs/00-product/PRODUCT.md
- docs/20-security/SECURITY_MODEL.md
- docs/50-quality/QUALITY_GATES.md
- docs/60-engineering/ENGINEERING_STANDARDS.md
- docs/60-engineering/CONVENTIONS.md
- docs/60-engineering/LESSONS.md
- docs/adrs/README.md
- .github/workflows/persist.yml
- .persist/hooks/pre-commit
- .persist/hooks/pre-push
- .claude/hooks/session-start.sh
- .claude/settings.json
- .claude/skills/chestertons-fence/SKILL.md
- .agents/skills/chestertons-fence/SKILL.md
- .claude/skills/plan-feature/SKILL.md
- .agents/skills/plan-feature/SKILL.md
- .claude/skills/security-review/SKILL.md
- .agents/skills/security-review/SKILL.md
- .claude/skills/security-review/scripts/scan-secrets.sh
- .agents/skills/security-review/scripts/scan-secrets.sh
- .claude/skills/conventions-adherence/SKILL.md
- .agents/skills/conventions-adherence/SKILL.md
Executable files written: .persist/hooks/pre-commit, .persist/hooks/pre-push, .claude/hooks/session-start.sh, .claude/hooks/context-prompt.sh, .codex/hooks/context-prompt.sh, .claude/skills/security-review/scripts/scan-secrets.sh, and .agents/skills/security-review/scripts/scan-secrets.sh.
Pre-commit and pre-push hooks written to .persist/hooks/ (pre-push is the final regression gate before you push).
Git hooks switched on for this clone (git config core.hooksPath .persist/hooks).
Next steps:
- Read CLAUDE.md and AGENTS.md, then the docs/ memory they point to.
- AI agent skills are in .claude/skills/ and .agents/skills/ — restart your AI tool to load them.
- Memory loads automatically per tool: a Claude SessionStart hook (.claude/hooks/session-start.sh), a Cursor rule (.cursor/rules/persist-memory.mdc), and AGENTS.md for Codex.
- CI is wired in .github/workflows/persist.yml; the pre-commit hook is in .persist/hooks/.
- Plan your first feature: persist feature create <name>.
- Record a decision: persist adr create <title>, then accept it with persist adr accept.
- Check repository memory health anytime: persist doctor.
Init names every executable it wrote. The one script is
security-review/scripts/scan-secrets.sh, a read-only secret scan the
skill can run instead of describing; the skill still works with the script deleted.
The "Test gate" line depends on your package.json. When init finds a
one-shot test script (test:run, or a test script that is not a
watch runner) it records that command as testCommand in
.persist/config.json, and records typecheck and
lint scripts as pre-push gates. These are values in a config file you own,
and the hooks are rendered from it.
Two options shape what gets written. --ai-tools claude,cursor limits the
entry points to the tools you use (the choices are claude,
codex, cursor, and generic; the default is
claude, codex, and cursor, and AGENTS.md is always written).
--features and --modules add the opt-in feature and module
memory indexes; you can also skip them and run persist feature create or
persist module create the first time you need one.
The hooks
The hooks are tracked files under .persist/hooks/, so they travel with the
repository. Git does not run them until the clone points at that directory. Init did
that above, because you said yes. On every other clone, teammates run the same line
once, and persist doctor reminds them until they do:
$ git config core.hooksPath .persist/hooks
From then on, every commit runs persist doctor plus your pre-commit gates,
and every push runs persist test-gate plus your pre-push gates. Details in
Hooks, test gate, CI.
Let your AI tool load it
Restart your AI tool so it picks up the new files. Claude Code reads
CLAUDE.md, which imports AGENTS.md, and runs the SessionStart
hook. Cursor applies .cursor/rules/persist-memory.mdc to every request.
Codex reads AGENTS.md. The four generated skills appear in
.claude/skills/ and .agents/skills/.
Record a first decision
A decision that affects architecture, a dependency, storage, auth, or a module boundary deserves an ADR. Create one as Proposed:
$ persist adr create "Use PostgreSQL for primary storage"
Persist OS ADR create complete.
ADR: docs/adrs/ADR-0001-use-postgresql-for-primary-storage.md
Created:
- docs/adrs/ADR-0001-use-postgresql-for-primary-storage.md
Next steps:
- Open docs/adrs/ADR-0001-use-postgresql-for-primary-storage.md and fill: Context, Decision, Alternatives, Consequences.
- It is Proposed — set Status to Accepted once the team agrees.
- The Chesterton fence is enabled: if this decision revisits why specific source files are shaped the way they are, record the human-confirmed reason in FENCES.md (the chestertons-fence skill walks through it).
Fill in the sections, then accept it when the team agrees:
$ persist adr accept use-postgresql-for-primary-storage
Persist OS ADR accept complete.
Accepted: docs/adrs/ADR-0001-use-postgresql-for-primary-storage.md
Overwritten:
- docs/adrs/ADR-0001-use-postgresql-for-primary-storage.md
Next steps:
- docs/adrs/ADR-0001-use-postgresql-for-primary-storage.md is now Accepted and is repository source of truth.
- Drift checks now treat references to it as resolved.
The full lifecycle, including how a decision is changed later, is in Decisions and ADRs.
Run the doctor
persist doctor reads the memory and exits 0 (healthy), 1 (warnings only),
or 2 (errors). Right after init in an empty repository it passes, and it
lists the checks that had nothing to look at rather than counting them as passed:
$ persist doctor
Doctor Report
INFO
- Persist OS config validates. (.persist/config.json)
- 0 feature folders detected.
- 0 module folders detected.
- 0 ADRs detected.
NOT EVALUATED
- standards: no feature folders or ADRs exist, so there are no completion claims or decisions to check
- content: no feature folders, module folders, or ADRs exist, so there is no memory content to check
- fence: nothing is staged and the branch has no upstream, so there is no change to check — the pre-commit hook checks each commit as it is made
- governing-adrs: no accepted ADR lists the paths it governs (an Applies To section), so no change can be matched to a decision
Result: PASSED
Once the repository has real work (an ADR, a feature, or a module), the doctor starts warning about template sections that were never filled in:
$ persist doctor
Doctor Report
WARNING
- Security model authentication and authorization section is still an unfilled template. (docs/20-security/SECURITY_MODEL.md)
- Product purpose is still an unfilled template. (docs/00-product/PRODUCT.md)
- Product users section is still an unfilled template. (docs/00-product/PRODUCT.md)
- Conventions canonical-primitives section is still an unfilled template. (docs/60-engineering/CONVENTIONS.md)
INFO
- Persist OS config validates. (.persist/config.json)
- 0 feature folders detected.
- 0 module folders detected.
- 1 ADRs detected.
Result: WARNINGS
[exit 1]
Everything the doctor checks, and what each severity means, is in Doctor.
Use it as the completion gate
The generated AGENTS.md tells the agent to run persist doctor
and fix every error before claiming work is complete. The same loop works for humans:
$ pnpm test:run && pnpm typecheck && persist doctor
When to use it, and when not to
Persist OS pays off when the code is meant to last and someone will inherit it: a teammate, a team, a fresh agent next week, or you next month. If you are spiking an idea you will throw away, skip it. There is no second session to hand off to, so the memory never gets read back. Even in a project that keeps it, keep the discipline proportional: a small fix gets built; a real feature or decision gets written down.
Found a problem?
Open an issue at
github.com/Karthick-Ramachandran/persist-os/issues.
Include the output of persist doctor --json if it is relevant; it names
every check and why any of them did not run.