Product
How Incremental Sync Keeps Memory Fresh Without Re-Indexing
A stale memory is a confident liar. It answers with yesterday's ownership, last week's architecture, and a bug that was fixed on Tuesday. That is worse than no memory at all, because your agent trusts it. So the real question for any memory layer is not how it indexes once. It is how it stays current.
The Oynix Team · June 10, 2026 · 6 min read
Why the naive answer fails
The obvious way to stay fresh is to re-index everything on a schedule. Read every file, every ticket, every doc again, and rebuild the graph from scratch. It works, and it is ruinous. On a large codebase a full rebuild is slow, expensive, and something you will avoid running often, which is how memory goes stale in the first place.
The trap is that full re-indexing makes freshness cost more the bigger you get. The teams with the most code, the ones who need current memory most, are the ones for whom keeping it current hurts the most. That is backwards.
The insight is that almost nothing changes between syncs. A monorepo with four million lines might see a few hundred lines move in a day. Reprocessing four million to capture a few hundred is the waste. Incremental sync exists to touch only what moved.
The four mechanisms that make it incremental
- Modified-time cursors. Each source remembers the timestamp of the last item it saw. On re-sync it asks only for things changed since that mark, so unchanged files and closed tickets are never fetched again.
- High-water marks. Per source, Oynix tracks the furthest point it has fully processed. If a sync is interrupted, it resumes from the mark instead of starting over, and it never double-counts what it already ingested.
- Content-hash dedup. Every item carries a hash of its content. If the hash matches what is already in the graph, the item is skipped. A file that was touched but not actually changed costs nothing to re-see.
- Per-source selection. You choose which channels, spaces, or folders sync. Work that you never selected is never scanned, so the surface area of every sync is exactly what you care about and no more.
What happens on a re-sync
- 1
Ask each source what changed
Oynix reads the modified-time cursor for every connected source and requests only items updated since that timestamp. Unchanged history is left untouched.
- 2
Filter to your selection
Changes are narrowed to the channels, spaces, and folders you chose to sync. Anything outside that selection is dropped before any work begins.
- 3
Hash and dedup
Each remaining item is hashed. Matches against the existing graph are skipped, so files that were touched but not truly changed cost nothing.
- 4
Update only the affected graph
The genuinely new or changed items are parsed, and only the nodes and edges they affect are rewritten. The rest of the graph stays exactly as it was.
- 5
Advance the marks
Cursors and high-water marks move forward to the newest point seen. The next re-sync starts from here, so the work never repeats.
Full rebuild versus incremental sync
| Aspect | Full re-index | Oynix incremental sync |
|---|---|---|
| What gets read | Everything, every time | Only what changed since the last mark |
| Cost as the codebase grows | Grows with total size | Tracks the size of the change, not the repo |
| Interrupted run | Start over | Resume from the high-water mark |
| Touched but unchanged file | Reprocessed | Skipped by content hash |
| Sources scanned | All of them | Only the ones you selected |
| How often you will run it | Rarely, because it hurts | Often, because it is cheap |
Why the monorepo costs the same as the side project
Incremental sync prices work by change, not by size. A side project where you edited ten files today and a four million line monorepo where you edited ten files today do the same amount of work on re-sync, because the same ten files changed. The rest of the monorepo is untouched, unhashed, and unread.
This flips the usual penalty. Instead of large codebases being expensive to keep fresh, they are simply large. Freshness cost is decoupled from repository size and tied to daily churn, which stays roughly constant no matter how big the history behind it gets.
It also means you can sync often. When a re-sync only pays for what moved, running it frequently is cheap, and frequent is how memory stays honest. The graph reflects this morning's merge, not last month's snapshot.
Incremental sync bills the diff, not the repository. Ten changed files cost the same whether they live in a toy or a monorepo.
Fresh by default
A memory layer earns trust by being right about now. The cursors, marks, hashes, and selection all serve one goal, which is to keep the graph current without ever paying to reprocess what did not change.
The result is a graph you can re-sync as often as you like without watching a cost curve. Your agent asks who owns a file and gets today's owner. It asks what a function calls and gets this morning's call sites. The memory keeps up because keeping up is cheap.
Keep your graph honest without re-indexing
Sync as often as you want and pay only for what actually changed, so your agent always reasons over the state of your work right now.
Install Oynix