inkentry memory guide
How inkentry's project memory works: kinds, supersede chains, point-in-time queries, cross-project visibility, harvesting from git history, and git-notes storage.
inkentry memory is a per-project knowledge store. Use it to capture decisions,
context, requirements, questions, and handoff notes that would otherwise live
only in chat history or someone's head.
Code tells you what the system does. Memory tells you why it was built that way.
Storage
Memory entries are stored in a local SQLite database by default, and, with
store_in_git_notes enabled (the default), also written through to
refs/notes/inkentry on HEAD, so they travel with the repository. No external
database or server is required.
Memory is scoped to a local project. Run inkentry init once per repository to
create its .inkentry/ store; in a directory with no .inkentry/ project,
inkentry memory and inkentry context fail closed with a no inkentry project here error rather than reading or writing a machine-global store. An explicit
--db <path> overrides this.
- Use
--backend git-notesto make git-notes the primary backend instead of SQLite. - Point
server_urlat a sharedinkentry-serverto share memory across a team (see server setup). - Entries are searchable by full text at all times; semantic search (by meaning) is available when a server is running, and the local one is auto-started on demand.
The auto-started local inkentry-server (loopback) is used only for inference
(embeddings and LLM for semantic search): it does not store memory. Your
memory lives on a server only when you explicitly configure a team server_url.
git-notes write-through: when store_in_git_notes is true (the default),
inkentry memory add also appends the entry to refs/notes/inkentry on HEAD.
Failure to write the note is non-fatal: a warning is logged and the primary
SQLite write is unaffected. Outside a git repo this is a graceful no-op.
Memory kinds
| Kind | Use for |
|---|---|
decision | Architecture or design choices with rationale |
context | Background information that helps understand the codebase |
requirement | Product or technical requirements |
note | General observations (default) |
question | Open questions that need an answer |
answer | Answers to previously stored questions |
handoff | State transfer between work sessions or agents |
intent | Active work signal; surfaced by inkentry context with file-overlap warnings |
antipattern | Things to avoid; list with inkentry memory failures |
These nine kinds are the whole set; an unrecognized --kind is rejected before
any store is opened. inkentry memory failures is a shortcut for
inkentry memory list --kind antipattern.
Adding entries
# Quick note with body inline
inkentry memory add --title "Chunker uses a token-window fallback" \
--body "This applies to unsupported file types and oversized nodes." \
--kind context \
--tags chunker,indexer
# Open your $EDITOR for the body (omit --body)
inkentry memory add --title "Decision: use blake3 for file hashing" --kind decision
# Link to specific files
inkentry memory add --title "Auth middleware refactored" \
--body "Moved session validation to src/auth/middleware.rs" \
--files "src/auth/middleware.rs,src/auth/session.rs"When --body is omitted, inkentry opens $VISUAL or $EDITOR (falling back to
vi). Lines starting with # are stripped (comment convention).
From a URL
--from-url fetches content from a GitHub issue, Linear ticket, or any web page
and stores it as a memory entry. The title is inferred from the page
automatically.
# GitHub issue - uses `gh api` for clean structured content
inkentry memory add --from-url https://github.com/owner/repo/issues/42
# Override the inferred title
inkentry memory add --from-url https://github.com/owner/repo/issues/42 \
--title "Auth: session token storage compliance issue" \
--kind requirement
# Any URL - fetches page title and strips HTML
inkentry memory add --from-url https://linear.app/myteam/issue/ENG-1234/... \
--kind contextFor GitHub issues, inkentry calls gh api to get structured issue data
(requires the GitHub CLI and gh auth login). For all
other URLs it does an HTTP GET and extracts readable text.
For non-GitHub URLs, you can opt in to custom extraction: if a script exists at
~/.config/inkentry/scripts/web-to-md.ts, inkentry runs it under bun and uses
its stdout instead of the built-in HTML-stripping fallback (useful for sites that
need JS rendering). The script only runs if you have placed it at that exact,
inkentry-owned path; set INKENTRY_SCRIPTS_DIR to look elsewhere. If bun or the
script fails, inkentry silently falls back to the built-in extraction.
Supersede chains and point-in-time queries
Every memory entry has a valid_at timestamp (when it became true) and an
optional invalid_at timestamp (when it stopped being true).
# Record when a decision became valid (ISO 8601)
inkentry memory add --title "Adopted monorepo layout" --kind decision \
--valid-at 2026-01-15
# Record a replacement and the supersedes edge in one step: archives the old
# entry, sets its invalid_at, and links the new one
inkentry memory add --title "New auth approach" --kind decision --body "..." \
--supersedes <old-id>
# Link two entries that already exist: archive <old-id>, edge it to <new-id>
inkentry memory supersede <old-id> <new-id>
# Mark two entries as related - creates a relates_to edge (no archiving)
inkentry memory add --title "Follow-up note" --kind note --body "..." \
--relates-to <other-id>Use a supersede edge whenever an earlier decision changes: it keeps a traceable
chain of reasoning. Use --relates-to for non-superseding connections (a
follow-up note, a related observation). A third edge kind, contradicts, is
recorded automatically when the server detects a conflicting entry (see
server setup); it surfaces in
inkentry memory show and inkentry memory graph alongside the others.
valid_at / invalid_at make it possible to reconstruct what was known at any
past date:
# Only entries that were valid at this date
inkentry memory list --as-of 2026-01-01
inkentry memory search "auth decisions" --as-of 2026-01-01This is useful for post-mortems or understanding old decisions in the context they were made.
Searching, listing, and showing
# Semantic search - finds entries by meaning (hybrid is the default)
inkentry memory search "why did we choose sqlite"
inkentry memory search "authentication decisions" --limit 5
# Also surface 1-hop relates_to neighbours of each result
inkentry memory search "authentication decisions" --expand-graph
# Search mode: hybrid (default), semantic, text
inkentry memory search "auth" --mode semantic
inkentry memory search "auth" --mode text
# List recent entries (newest first)
inkentry memory list
inkentry memory list --kind decision
inkentry memory list --limit 50
# Include archived entries; filter by commit SHA (exact or prefix)
inkentry memory list --archived
inkentry memory list --source-ref abc1234
# Show a single entry - full body plus relationship edges
inkentry memory show 42
inkentry memory show 42 --format jsonquestion and answer entries show titles only in list view to avoid context
saturation. Use inkentry memory show <id> to read the full body.
Tracking topic evolution
inkentry memory timeline returns all entries related to a topic, sorted by the
time they became valid, useful for understanding how a decision or understanding
evolved.
inkentry memory timeline "authentication strategy"
inkentry memory timeline "database choice" --limit 30
inkentry memory timeline "auth" --format jsonRelationship graph
# Show all edges for an entry (text)
inkentry memory graph 42
# Machine-readable
inkentry memory graph 42 --format jsonmemory graph and --expand-graph surface supersedes, relates_to, and
contradicts edges with linked entry titles.
Cross-project visibility
When projects are linked with inkentry link, inkentry memory search,
inkentry memory list, and inkentry context automatically surface relevant
memory from linked projects alongside local results. This is how a settled
decision recorded in one project remains visible to agents working in a sibling
project.
Not all memory propagates. Only entries that match all three of the following criteria are surfaced from a linked project:
- Kind:
decisionorrequirement(neverhandoff,question, ornote). - Tag: must carry the tag
locked(for settled decisions) orcross-project(for cross-cutting items). Tags likeauthordatabasealone are not enough. - Status:
activeonly. Archived or superseded cross-project entries do not resurface after they are retracted in the source project.
Every result from a linked project is labelled with its origin: a
[from: <project>] badge in text output, and source_project /
source_project_path fields in JSON. Local results always appear first;
cross-project results are appended and are not counted against --limit.
# Tag a decision as locked so linked projects can see it
inkentry memory add --kind decision \
--title "SSE memory stream is server-owned" \
--body "Clients must not assume a local SSE surface." \
--tags v1,locked
# Skip the cross-project dep pass entirely
inkentry memory search "auth decisions" --local-only
inkentry memory list --kind decision --local-only
inkentry context --local-onlyThe dep pass reads each linked project's memory.db directly from disk (local
SQLite only). It does not route through inkentry-server or any remote endpoint,
so a linked project's memory is only reachable when its memory.db file is on
the local filesystem.
Harvesting from git history
inkentry harvest reads your git log, sends commit messages to the LLM, and
automatically extracts significant entries. It is a top-level command. Harvesting
requires a reachable inkentry-server with a chat endpoint configured; there is
no local-model path, and llm_model in ~/.config/inkentry/config.toml has no
effect on it.
# Default: last 10 commits
inkentry harvest
# Custom range, or an entire branch
inkentry harvest --git-range HEAD~30..HEAD
inkentry harvest --git-range v1.0..HEAD
inkentry harvest --branch feature/auth
# Source: git log (default), Claude Code session history, or antipatterns
inkentry harvest --source git
inkentry harvest --source claude-code --confirm
inkentry harvest --source failuresReading the Claude Code history file requires --confirm. Already-harvested
commits are skipped (tracked via a git:<sha> tag). Routine commits ("fix typo",
"wip", and so on) are ignored by the LLM.
inkentry memory harveststill works as a hidden, deprecated alias for one release; it prints a warning and runsinkentry harvest.
Automatic harvesting
Install the git hook and harvesting happens on every commit:
inkentry hooks installThis writes a post-commit hook that runs inkentry index and
inkentry harvest after each commit (both --detach, so git is not blocked).
Syncing with a team server
Once a team server_url is configured, keep local and shared memory in step.
The everyday path is inkentry sync; the one-way seeding primitives live under
plumbing:
# Two-way: push local and pull remote (also available as `inkentry memory sync`)
inkentry sync
# One-way: seed the server from local entries
inkentry plumbing push
# One-way: pull new server entries into the local memory.db
inkentry plumbing pullIn the default local_first mode you rarely run inkentry sync by hand. Your
writes commit to the local memory.db immediately and never block on the
network; from an interactive terminal a background reconciler then drains what
you recorded up to the server and pulls teammates' entries down, so the shared
memory converges on its own. inkentry sync is the explicit escape hatch for
when you want that reconcile to happen synchronously now rather than in the
background, such as a CI job that needs entries pushed before it exits. Code
never travels; only memory does. Archived entries are skipped by default; pass
--include-archived to propagate tombstones. Which server (if any) reads and
writes go to is governed by the mode config (offline / local_first /
cloud_first); see the config reference. See
server setup for configuring server_url and server_key.
Importing from a local server database
inkentry memory reconcile imports notes recorded by a running inkentry-server
daemon into the project's local memory.db. Dedup is by content hash, and the
source database is opened read-only.
# Import notes for the active project (default source: ~/.local/state/inkentry/server.db)
inkentry memory reconcile
# Preview what would be imported without writing anything
inkentry memory reconcile --dry-run
# Import notes for all projects found in the source database
inkentry memory reconcile --all-projects
# Override the source path
inkentry memory reconcile --source-db /var/run/inkentry/server.dbEntry identity and deduplication
Every entry has a content identity: a hash over exactly its kind, title, and
body. Two people who independently record the same decision in two clones
arrive at the same identity with no coordination, so inkentry memory list and
inkentry context fold duplicate copies as they read, and a decision recorded
twice shows once. Tags and linked files from the copies are merged onto the
survivor, so nothing recorded on a folded copy is lost.
A memory.db that predates this, or that gathered entries from more than one
machine, can hold rows that share an identity but differ in creation time, tags,
or status. These are harmless and left in place, but you can collapse them
explicitly:
inkentry memory dedupe --dry-run # preview what would be collapsed
inkentry memory dedupe # collapse duplicate groupsFor each group, the earliest-created row survives; the others are removed after
their tags and linked files are merged in, and the entry is archived if any copy
was. It runs as a single transaction, so a failure part-way leaves memory.db
exactly as it was. Deleting the losing rows is destructive, so back up
memory.db (or your git-notes ref) first if you want to be able to undo it.
If entries are missing their local embeddings - after the embedder was down, or
after a database migration - inkentry memory reindex backfills them (add
--dry-run to preview, --force to recompute existing ones).
Once a store has no duplicates, a plain inkentry memory add for byte-identical
kind/title/body no longer inserts a second row: it reuses the existing
entry (merging in the new call's tags and linked files) and prints Already recorded as ... instead of Stored ....
Machine-readable output
All memory commands support --format json, and setting AGENT=true forces JSON
mode globally:
AGENT=true inkentry memory list --kind question
AGENT=true inkentry memory search "database decisions"inkentry plumbing read-memory emits memory entries as JSONL for scripting.
Tips
- Store the "why", not just the "what" - the code already captures what was built.
- Use
questionkind actively - when you hit a decision point you are unsure about, store it. Come back withinkentry memory list --kind questionat the start of the next session. - Use
handoffkind at the end of a long session to summarise the current state for your next session (or for another agent). - Tag entries - tags like
auth,database,performancemakeinkentry memory listmore scannable and improve search relevance. - Record a supersede edge when updating a decision - it archives the old entry, sets its invalidation time, and creates a traceable edge so you can always follow the chain of reasoning.
- Use
--relates-tofor non-superseding connections. - Use
--as-offor archaeology.
What's next
- CLI reference - every memory subcommand, flag, and environment variable
- Server setup - share memory across a team
- Config reference -
store_in_git_notesand server config fields
Getting started with inkentry
Install inkentry, understand an unfamiliar codebase in the first five minutes, then add memory, agents, and team sharing as you need them. No API keys or servers required to start.
inkentry CLI reference
Every inkentry command, subcommand, flag, and environment variable, organised by command group.