Repo memory
Store knowledge across sessions, models, and repos. Keep each repository's decisions, constraints and gotchas alongside its code so later sessions can use what earlier sessions learned.
Each repository keeps its own knowledge as Markdown files under memory/, shared with teammates
through Git.
- One Markdown file per fact. Git can merge independently added facts; edits to the same fact or generated instruction block can still conflict.
- Cloning the repository brings its facts. There is no server, account or second repository.
- partyline does not commit facts. A fact is written to your working tree; you review and commit
it with the change it belongs to.
git statusshows what an agent recorded. The one thing partyline commits is a passing loop batch step, and those commits leavememory/as it was at HEAD.
$ ptln memory where # the directory, and how many facts it holdsSet up a repository
The overview, drift and refresh behavior below needs partyline 0.108.0 or later
(ptln version). Per-turn refresh on Codex and Gemini needs 0.109.2 or later.
$ ptln memory build # print what it would write
ptln memory build --apply # write it--apply writes:
| Written | Source |
|---|---|
an overview: the problem the project solves and for whom, what it does, how it is built, what it deliberately leaves out, how to extend it, and how to build, test and deploy it | generated by claude -p with read-only tools (Read, Glob, Grep), only when there is no overview. It reads the last commit; uncommitted changes are left out. |
| build and test commands, CI workflows, database migrations | read from the files, each fact citing its source: the file, or scan:migrations for migrations |
| open questions only a person can answer: who it is for and what problem it solves, what it replaced, who owns it, what breaks if it stops, what is planned next, what must not change, how it is deployed, what looks wrong but is intentional | on first setup only |
Overview generation reads the last commit and requires at least one commit. Generation requires Claude Code
(Sonnet, with no MCP servers, stopped after 6 minutes) and uses your account. Its duration depends on the repository and provider. The overview treats code comments and README text as claims to check against the code, not as
facts. If generation fails, build says so and writes the rest. Read the overview against the code and correct it with
ptln memory edit.
Without --refresh, running build again leaves facts a person wrote unchanged: it updates a derived fact
whose evidence changed, and it lists a derived fact whose evidence is gone without deleting it
(--remove-stale deletes it). Questions are not added back once removed.
Keep it current
Memory does not update itself when the code changes. A fact counts as checked at the last commit
that changed its file; a fact with uncommitted changes counts as current. ptln memory verify
confirms a fact without changing its text: it writes verified: into the file, so committing it
moves that commit forward. Two branches that verify the same fact conflict on that line.
$ ptln memory build # how far memory is behind, and which facts to check
ptln memory build --apply --refresh # rewrite the overview from the last commit
ptln memory verify 20261017-2013 # checked against the code; still rightptln memory build reports two things:
- how many code commits have landed since the overview was last committed. Merge commits, and
commits that change only
memory/,AGENTS.md,CLAUDE.mdorGEMINI.md, are not counted. - facts that name a file (
internal/importer.go,Makefile:12, or afile:source) that has changed since the fact was last committed. Such a fact may still be right; check it, thenedit,rmorverifyit. Derived facts are re-derived bybuildinstead, questions are not checked, andmemory/and the map files never count as evidence.
--refresh rewrites the overview in place, keeping its id. The model starts from the current
overview and keeps what the code still supports, including corrections people made by hand. This is a model instruction, not a preservation
guarantee: review the diff, especially if you have edited the overview yourself.
When the code is 20 or more commits past the overview, the first turn of a partyline session tells
the agent to finish your request, then tell you and ask once whether to update the memory. If you
decline, it asks again after another 20 commits. The record of when it last asked is in
~/.partyline/.
From a session
The first time a partyline session runs in a git repository with no memory/, the agent finishes
your request, then offers once to set memory up. If you agree, it runs
ptln memory build --apply, checks the overview, and answers the open questions it can verify from
the code, history and docs. For the questions only you can answer, it drafts answers from the README
and docs and asks you to correct them. It then records a few facts that the overview does not
cover, each naming its evidence. It does not commit.
The offer is made once per repository on this machine; all worktrees of a repository count as one.
The record that it was made is in ~/.partyline/, not in the repository. Until a repository has
memory/, partyline writes nothing into it.
Record and correct
$ ptln memory add gotcha "The importer rejects CSV files with a byte-order mark."
ptln memory edit 20261017-2013 "The importer strips a byte-order mark since v2.4."
ptln memory append 20261017-2013 "Older exports still need re-saving without one."
ptln memory rm 20261017-2013| Kind | Use for |
|---|---|
overview | the description of the project. One per repository; change it with edit. |
decision | a choice, and why it was made |
constraint | something the code must respect |
contract | an interface another component depends on |
gotcha | a trap that costs time |
question | something unresolved that needs a person |
edit, append, verify and rm accept an id prefix; --supersedes needs the full id.
--tags architecture places a fact under Architecture in the generated block. ptln memory ls
(also bare ptln memory) lists current facts.
A filter refuses, with a reason, a fact that is empty or under 25 characters, and recognized forms of
machine state, work-item status, time-bound wording (currently, right now) and session chatter
(I just, let's, TODO). It does not verify whether an accepted claim is true or useful. The
refusal quotes the words that matched. Questions and the overview are exempt from the pattern rules,
on add, edit and append, but not from the length check.
$ ptln memory add constraint "The build machine's disk keeps filling up and needs 25 GB free."
ptln: not a durable fact: this records how full a machine is right now, which stops being true as soon as something is deleted
matched: "disk keeps filling up and needs 25 GB"
if the durable fact is that something grows without bound, say that instead
the test: would this still be true and useful to someone who opens this repo in three months?An unknown kind is refused with the kind that was probably meant: trap suggests gotcha, rule
suggests constraint.
Agents record facts with the same commands. The generated block in AGENTS.md tells every session
to treat the facts as correct unless the code contradicts them; to record a decision, constraint,
contract or gotcha when one comes up; to say what a decision costs as well as why it was made; to
name the evidence for each fact; to add a question when it cannot verify something; and not to
commit. It also points to ptln loop guide for running work through a loop.
What a session sees
| When | What | Engines |
|---|---|---|
| session start | a generated instruction block with the overview and selected facts, capped at approximately 8 KiB | engines that load the repository's instruction file; no Partyline hook required |
| each turn | facts recorded since the session's last turn, at most 5 | engines with the hook installed (below) |
| end of a turn | up to two facts recorded from the session's recent work, at most once every 20 minutes, marked by: harvest. They reach later sessions through the per-turn hook; the instruction-file block is not rewritten | Claude, in repositories that already have memory/ |
ptln memory brief prints a memory briefing for inspection: at most 12 facts, flagging as
disagreeing any two facts of the same kind, sharing a tag, by different authors. The generated instruction-file block is a
separate, size-limited view; ptln memory map rewrites it. Partyline updates whichever of AGENTS.md, CLAUDE.md and
GEMINI.md already exist; if none exists, it creates only AGENTS.md. An engine must load that
file for the block to reach its context. Check your engine's instructions and trust settings.
| Setting | Effect |
|---|---|
PARTYLINE_MEMORY_REFRESH=off | disable per-turn refresh, and with it the setup offer and the out-of-date notice; instruction-file memory still applies |
PARTYLINE_MEMORY_CAPTURE=off | disable automatic capture, not explicit memory commands |
Automatic capture sends the last 24 KiB of the transcript to a separate Claude Code invocation (Haiku, no tools) and can consume account usage. It records proposals, not verified facts. See Security.
Hooks per engine
$ ptln memory hooks # what runs on this machine, and what needs a trust grant
ptln memory hooks --install| Engine | Event | Trust |
|---|---|---|
| Claude | UserPromptSubmit, Stop | none: passed per session when partyline starts or resumes it |
| Codex | UserPromptSubmit | approve once in the Codex TUI |
| Gemini | BeforeAgent | trust the workspace, or --skip-trust |
| Antigravity | PreInvocation | add the directory to trustedWorkspaces |
ptln memory hooks reports Codex trust as unknown: Codex stores trust as a hash partyline cannot
recompute, and codex exec runs with untrusted hooks disabled and prints no warning. partyline prints the Codex configuration for you to paste instead
of editing config.toml.
Facts from commits
harvest and propose work only in legacy side-repo projects. In a repository with its own
memory/ they exit with this repo is not in a project.
A commit can declare a fact in a trailer:
fix the POS callback handling
Ptln-Gotcha: The POS callback retries 3x with no jitter, so anything
downstream has to be idempotent.$ ptln memory harvest # record what new commits declare
ptln memory harvest -n # print it without writingTrailers: Ptln-Overview, Ptln-Decision, Ptln-Constraint, Ptln-Contract, Ptln-Gotcha,
Ptln-Question. Indented lines continue a trailer. The first harvest reads at most 50 commits. The fact cites its commit, and its id derives from the commit
hash, so harvesting twice writes the same file. --since <rev> harvests a range.
Facts from other systems
$ ptln memory propose --from odoo:ACR-1412 --from commit:4a50eb9 \
gotcha "The POS callback retries 3x with no jitter"At least one --from <system>:<id> citation is required. Proposed facts are marked by: harvest;
ptln memory brief ranks them below facts a person wrote. A duplicate is reported as already known
and not written again.
Superseding
--supersedes <id> on add records a fact that replaces another. It takes the full id and does not
check that the id exists, so a prefix or a typo leaves the old fact briefed. When the id matches, the old one is no longer briefed and stays visible with ptln memory ls --all. Use edit when a claim was wrong, and --supersedes
when a design changed and both versions are worth keeping.
A fact is a markdown file under memory/ in the repository you are working in, not in a side
repository, a server or a database. Cloning the code clones its facts, and a fact is reviewed in the
same pull request as the change it describes.
partyline does not commit facts. A fact is written to the working tree for you to commit. The only
commits partyline makes are passing loop batch steps, and those keep memory/ as it was at HEAD.
ptln memory sync exists only for legacy side-repo projects and does nothing in your own repository;
which case applies is decided by the directory's location, not by a flag.
Facts can be edited, appended to and deleted. ptln memory edit <id>
replaces the text rather than annotating it, and keeps the id, because ids are cited in commit messages and other facts. An append-only store briefs a
session with a claim and its correction at the same time, with nothing saying which is current.
git log -p memory/ records every edit, its author and its date.
Facts reach sessions through instruction files and hooks. Partyline updates managed blocks in
existing AGENTS.md, CLAUDE.md and GEMINI.md files, or creates AGENTS.md when none exists.
The block contains a size-limited selection of facts. Startup delivery depends on the engine
loading that file. Hooks can add newer facts during a long session.
Three of the four engines need a trust grant before a hook runs, and Codex degrades silently:
codex exec disables an untrusted hook without saying so.
ptln memory hooks reports Codex trust as unknown, because Codex stores trust as a hash
partyline cannot recompute. If facts are not reaching a session, check the file before the hook.
ptln memory build derives facts only from what it can cite: build files, CI workflows and
migrations, each fact naming its source. What would require knowing why something exists becomes an
open question instead of a claim. The project overview is the exception: it is generated by a model reading the
repository's last commit, written as a proposal, and meant to be checked and corrected.
Before recording a fact, ask whether it will still help someone opening the repository in three months. The write-time filter rejects facts under 25 characters and recognized patterns of machine state, host configuration, work-item status, time-bound wording and session chatter. It cannot determine truth; accepted facts still need review.