All notes retain history on update. Previous versions are archived automatically.
Every note is a string — a linear chain of versions that grows each time you update it.
Your working context (now) accumulates a string of intentions as you work.
When a string of work is complete, keep move extracts matching versions by tag
and strings them into a named note.
This isn't version control (no branches, no merges) and it isn't an append-only log (you can reorganize). It's the temporal dimension of how knowledge evolved — and unlike other memory stores, you can re-string it by meaning.
Append @V{N} to any ID to specify a version:
ID@V{0}— current versionID@V{1}— previous versionID@V{2}— two versions agoID@V{-1}— oldest archived versionID@V{-2}— second-oldest archived version
keep get "%a1b2c3d4@V{1}" # Previous version
keep get "now@V{2}" # Two versions ago of nowdoc
keep get "now@V{-1}" # Oldest archived nowdockeep get ID -V 1 # Previous version (equivalent to @V{1})
keep get ID -V -1 # Oldest archived (equivalent to @V{-1})
keep get ID --history # List all versions
keep now -V 1 # Previous intentions
keep now --history # List all nowdoc versions--history shows versions as summary lines with version identifiers:
now 2026-01-16 Current summary...
now@V{1} 2026-01-15 Previous summary...
now@V{2} 2026-01-14 Older summary...
With --ids, outputs version identifiers for piping:
keep --ids now --history
# now@V{0}
# now@V{1}
# now@V{2}When viewing a single item (keep get, keep now), the output includes prev: and next: navigation:
---
id: %a1b2c3d4
prev:
- @V{1} 2026-01-14 Previous summary text...
---
Current summary here...Text-mode updates use content-addressed IDs for versioning:
keep put "my note" # Creates %a1b2c3d4e5f6
keep put "my note" -t done # Same ID, new version (tag change)
keep put "different note" # Different ID (new document)Same content = same ID = enables versioning via tag changes.
If a note returns to content that already exists in its archived history, keep does not create a branch. It still appends a new head state to the same linear version string:
A -> B -> AarchivesA, thenB, then makesAcurrent again- the later
Bis still present in history - the restored
Ais treated as known content for that same note
When this happens, keep restores previously-known derived outputs for that content when available, including:
- summary
- auto-tagging results
- embeddings
This avoids unnecessary re-summarization during checkouts and branch switches. Analysis parts are not version-restored. If parts from a later state are still attached to the note, they remain until keep analyze runs again. The tradeoff is that restored derived outputs may still be slightly stale if prompt selection or surrounding context changed while the content stayed the same.
keep del has revert semantics when versions exist:
keep del ID # If versions exist: reverts to previous version
# If no versions: removes item entirelykeep --ids now --history | xargs -I{} keep get "{}" # Get all versions
diff <(keep get doc:1) <(keep get "doc:1@V{1}") # Diff current vs previouskp.get_version(id, offset=1) # Previous version
kp.get_version(id, offset=2) # Two versions ago
kp.list_versions(id, limit=10) # Archived versions (newest first)See PYTHON-API.md for complete Python API reference.
Versions and parts are complementary dimensions:
- Versions (
@V{N}) are temporal — eachputadds a version - Parts (
@P{N}) are structural —analyzedecomposes content into sections
Versions accumulate (each one happened). Parts replace (each analyze produces
a fresh decomposition). Both use tag-based metadata and appear in search results.
See KEEP-ANALYZE.md for details on structural decomposition.
- KEEP-GET.md — Retrieving items and versions
- KEEP-NOW.md — Nowdoc version history
- KEEP-ANALYZE.md — Structural decomposition into parts
- REFERENCE.md — Quick reference index