ASCII / MOTION LAB · 001Explore all seven experiments ↗

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 status shows what an agent recorded. The one thing partyline commits is a passing loop batch step, and those commits leave memory/ as it was at HEAD.
$ ptln memory where      # the directory, and how many facts it holds

Set 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:

WrittenSource
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 itgenerated 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 migrationsread 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 intentionalon 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 right

ptln 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.md or GEMINI.md, are not counted.
  • facts that name a file (internal/importer.go, Makefile:12, or a file: source) that has changed since the fact was last committed. Such a fact may still be right; check it, then edit, rm or verify it. Derived facts are re-derived by build instead, questions are not checked, and memory/ 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
KindUse for
overviewthe description of the project. One per repository; change it with edit.
decisiona choice, and why it was made
constraintsomething the code must respect
contractan interface another component depends on
gotchaa trap that costs time
questionsomething 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

WhenWhatEngines
session starta generated instruction block with the overview and selected facts, capped at approximately 8 KiBengines that load the repository's instruction file; no Partyline hook required
each turnfacts recorded since the session's last turn, at most 5engines with the hook installed (below)
end of a turnup 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 rewrittenClaude, 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.

SettingEffect
PARTYLINE_MEMORY_REFRESH=offdisable per-turn refresh, and with it the setup offer and the out-of-date notice; instruction-file memory still applies
PARTYLINE_MEMORY_CAPTURE=offdisable 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
EngineEventTrust
ClaudeUserPromptSubmit, Stopnone: passed per session when partyline starts or resumes it
CodexUserPromptSubmitapprove once in the Codex TUI
GeminiBeforeAgenttrust the workspace, or --skip-trust
AntigravityPreInvocationadd 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 writing

Trailers: 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.