Your repo's knowledge in AgentMemory

How-toUpdated 9 min read
View as Markdown
On this page

You already write down how your code works for your coding agents: a CLAUDE.md at the root, an AGENTS.md in a service, a LEARNINGS.md next to the code that burned you. OPVS can read those files and keep each section as a lesson in AgentMemory, attached to the file and folder it came from. An agent about to change src/billing/ then gets the rules for src/billing/, not the whole rulebook.

Your repository stays the source of truth. You change a lesson by editing the file, and the next sync brings the change in.

There are two ways in. If a machine in your workspace indexes the repository, this happens by itself. If not, you run one command. Either way you need a project with the repository attached.

Which files OPVS reads

File

Where

Index job

opvs memory sync

CLAUDE.md, AGENTS.md, GEMINI.md, LEARNINGS.md

Any depth

Yes

Yes

.cursorrules, .windsurfrules

Any depth

Yes

Yes

.cursor/rules/*.mdc

Any depth

Yes

Yes

.github/copilot-instructions.md

Any depth

Yes

Yes

.claude/rules/*.md

Any depth

Yes

No

learnings/*.md

Any depth

Yes

No

What is left out. Anything your .gitignore excludes, and anything your root .opvsindexignore excludes. So to keep a file out of AgentMemory, list it there. An index job also skips folders it never reads, such as node_modules and dist.

Limits. 512 KB per file, 400 files and 4 MB per sync. Past a limit the sync is marked truncated with the reason, and nothing is cut silently. When an index job hits a limit, it keeps your instruction files first, then LEARNINGS.md files, then learnings/*.md with the newest dates first.

How a file becomes lessons

Each ## section is one lesson, and the text before the first ## is one lesson too. Deeper headings (### and below) stay inside their section, and a ## inside a code block is not a heading. This src/billing/LEARNINGS.md gives three lessons:

# Billing

Everything here applies to the invoice pipeline.

## Round totals half-even

Round invoice totals half-even, never half-up.

### Why

The tax authority audits the rounding mode.

## Never call the tax API in a loop

It is rate limited per account. Batch the lines instead.

Lesson

Id

The text before the first ##

knowledge:<project-id>:src/billing/LEARNINGS.md

Round totals half-even, including its ### Why

knowledge:<project-id>:src/billing/LEARNINGS.md#round-totals-half-even

Never call the tax API in a loop

knowledge:<project-id>:src/billing/LEARNINGS.md#never-call-the-tax-api-in-a-loop

The project is part of the id, so two microservices that each have a root CLAUDE.md never overwrite each other, as long as each repository has its own project. If a file repeats a heading, the later ones get -2, -3 and so on.

Each lesson is anchored to its file and its folder. A lesson from src/billing/LEARNINGS.md sits on that file and on src/billing/, and one from a root file sits on the file and on the repository root. Ask about any file and you also get the lessons on the folders above it, so asking about src/billing/tax.py returns the rules in src/billing/ and your root CLAUDE.md. OPVS works out the anchors itself, for your own project, and ignores any a client sends.

An anchor is not the same as a pinned lesson. Pinned lessons come first in search results, and nothing in this sync pins one.

A lesson can also name the test that checks it, with a Checked by: line. See A lesson checked by a test.

When you change a file

A sync is a full picture of one repository at one commit. OPVS compares it with what it already holds for that project and branch.

You do this

The next sync does this

Edit a section

Replaces that lesson

Change nothing

Nothing. Sending the same files twice changes nothing

Delete a section or a file

Retracts the lesson: it is kept, but search no longer returns it

Put the section back

Makes the lesson active again

Rename a heading, or move a file

Adds new lessons under the new id and retracts the old ones

A truncated sync retracts nothing, because a file missing from it may only have been past a limit.

Where your files go

Only into your own workspace. The workspace comes from your token, never from what the request says. Another workspace cannot read these lessons, and a project that is not yours answers 404, the same as one that does not exist.

This is stored text, unlike the code index. The code index keeps structure only. This feature keeps the text of the files listed above, and sends each lesson's text to an embedding model so that search can find it by meaning. Keep secrets out of these files, and use .opvsindexignore for any file you do not want stored.

Way 1: attach a repository

If a build machine in your workspace runs your index jobs, there is nothing to set up. Attach the repository and a branch to a project, and every index of that branch brings your knowledge files in with it.

If this sync fails, your index still completes and your existing lessons stay as they were. No route shows you the sync's result yet, so to check it, search for something you know is in one of your files:

opvs memory search "round totals" --type knowledge

Way 2: opvs memory sync

Use this when no machine indexes your repository. You still need a project with the repository attached: without one the command answers project not found.

# 1. Find your project id
opvs projects list

# 2. See what would be sent. This sends nothing.
opvs memory sync --project <project-id> --dry-run

# 3. Send it
opvs memory sync --project <project-id>

The command reports what it did. For example:

Files: 12
Entries: 64
Upserted: 64
Unchanged: 0
Retracted: 0
Truncated: no

Entries is the number of lessons in this sync, Upserted the new or changed ones, and Retracted the ones whose section or file is gone.

Option

What it does

--project <project-id>

Required. The project the repository is attached to

--branch <name>

The branch to record. Defaults to your current branch

--dry-run

Lists the files that would be sent, and sends nothing

--allow-dirty

Syncs files with uncommitted changes, as they are on disk, against the current commit

Your token needs memory:ingest, and searching needs memory:read. New tokens ask for both by default, so you only need to act if the command tells you to. See Auth Commands.

Errors

Error

When

Resolution

project not found

No project has this repository attached

Attach the repository to a project, then pass that project's id with --project

A missing-scope refusal

Your token lacks memory:ingest

Request a token that includes memory:ingest (see Auth Commands above)

Without an index, lessons are stored but not attached to code. With no index, OPVS has no code to attach them to. Search by text still finds them, but asking about a file does not, and the Code view shows no counts, until the repository has been indexed and synced again.

Three things to get right

  • Sync the whole repository, not a folder. opvs memory sync apps/api sends only that folder,

and OPVS treats every sync as the whole repository. Each lesson outside apps/api/ is then retracted. Running the plain command from inside a folder is safe: it starts from the repository root.

  • Sync the attached branch. The branch is not part of a lesson's id, so a project holds one

copy of each section. Syncing a feature branch replaces the matching lessons with that branch's text.

  • Use one way per project. If an index job already reads your repository, you do not need this

command. It does not send .claude/rules/*.md or learnings/*.md, so running it on an indexed project retracts those lessons until the next index restores them.

If the command stops

You see

What it means

What to do

Refusing to sync a dirty worktree

You have uncommitted changes

Commit them, or pass --allow-dirty

No repository knowledge files to send.

No file matched. Nothing is sent, so nothing is retracted either

Check the table of files, your ignore files, and --dry-run

Knowledge path is not a regular file: CLAUDE.md

The file is a symbolic link, often CLAUDE.md pointing at AGENTS.md. The whole sync stops

Replace the link with a real file. An index job handles links for you, sending the file once

Knowledge file is not valid UTF-8: <path>

The file is not UTF-8 text. The whole sync stops

Save it as UTF-8, or exclude it

Could not read the current branch

You are on a detached commit, as many CI jobs are

Pass --branch <name>

No such remote 'origin'

The repository has no origin remote

Add one

request a token that includes memory:ingest

Your token lacks the scope

Get a token with memory:ingest and run it again

project not found

The id is wrong, the project belongs to another workspace, or it has no repository attached

Check the id, and attach the repository

How a session finds them

Search by words. This works in any repository:

opvs memory search "tax API" --type knowledge

Ask about the code you are about to change. This returns the lessons on those files and on the code around them:

opvs memory near src/billing/tax.py --project <project-id>

See them in the dashboard. Open a project, open the project canvas and select Code. A directory, file or symbol that has lessons shows how many, as 3 memories.

Your coding agent can use these reads too: opvs memory install <runtime> connects codex, claude-code, cursor, opencode or cline to OPVS memory. To call them from your own code, use the routes under Lessons near the code.

Did this answer your question?