| title | CLI Reference |
|---|
Complete reference for all uteke commands. Version 0.13.0.
| Flag | Description | Default |
|---|---|---|
--store <path> |
Override store location | ~/.codecora/uteke |
--namespace <name> |
Namespace (deprecated: prefer rooms, tags and author; writes to a non-default namespace print a warning on stderr, see Namespaces are deprecated) | default |
--json |
Output as JSON | off |
--verbose |
Enable debug logging | off |
Config file path is auto-resolved (~/.codecora/uteke/uteke.toml + .uteke/uteke.toml); there is no --config flag.
Interactive onboarding wizard — guides new users from zero to productive. Detects install, picks agent, configures extraction mode, toggles features, writes config, installs agent integration, runs a memory test, and introduces Rooms.
# Interactive (recommended for first-time users)
uteke onboard
# Non-interactive (defaults: agent=hermes, namespace=default, tool mode, offline extraction)
uteke onboard --yes
# Pre-select agent and namespace
uteke onboard --yes --agent claude --namespace work| Flag | Description |
|---|---|
--yes |
Skip interactive prompts, use defaults |
--agent <name> |
Pre-select agent (hermes, claude, cursor, pi, opencode) |
--namespace <name> |
Pre-select namespace |
The wizard steps:
- Install detection — checks if
utekeis on PATH and if a store exists - Agent selection — Hermes, Claude, Cursor, Pi, or OpenCode
- Integration mode — manual tool vs memory-provider (auto recall + extraction)
- Namespace — for multi-agent isolation
- Feature toggles — toggle ON/OFF for: Aging, Auto-maintenance, Graph rerank, Salience boost, Recency boost, Server mode
- Config write — generates
~/.codecora/uteke/uteke.toml - Agent init — runs
uteke initwith your selections - Feature showcase — prints all commands grouped by category
Check for updates and upgrade to the latest Uteke release.
uteke upgrade
uteke upgrade --yes| Flag | Description |
|---|---|
--yes |
Skip confirmation prompt |
Note: Before v0.7.0 this command was called
uteke update; that name now edits a memory in place. Verifies the cosign (Sigstore, keyless) signature ofchecksums-sha256.txtagainst roots built into the binary and then the archive's SHA-256 by default; a missing or invalid signature aborts the upgrade, as does a release older than the installed version or a non-stable (pre-release) one;uteke upgradeinstalls only stable releases (see SECURITY.md). Onlyuteke upgradechecks the signature;install.sh,install.ps1and Homebrew do not. SetUTEKE_UPGRADE_SKIP_CHECKSUM=1to skip both checks (not recommended).
Store a new memory with optional tags, metadata, and contradiction detection.
# Basic
uteke remember "Deploy v2.1 to staging Friday" --tags deploy,staging
# With metadata enrichment
uteke remember "Deploy staging to AWS us-east-1" \
--tags deploy,aws \
--entity staging-server \
--category infrastructure \
--meta "source:meeting-note,confidence:0.9"
# With contradiction detection
uteke remember "Server runs on port 8080" --tags config --detect-contradiction
# With memory type
uteke remember "API rate limit is 1000/min" --type fact
# With source attribution (#348)
uteke remember "Deploy at 3pm Friday" --tags deploy --source "https://slack.com/msg/123" --source-type url
# In a specific namespace
uteke remember "User prefers dark mode" --tags pref --namespace my-agent| Flag | Description |
|---|---|
--tags <tags> |
Comma-separated tags |
--entity <name> |
Associate memory with an entity (e.g. "staging-server") |
--category <cat> |
Categorize the memory (e.g. "infrastructure") |
--meta <pairs> |
Key:value pairs, comma-separated. Auto-detects type (string/number/bool) |
--type <type> |
Memory type: fact, procedure, preference, decision, context, note, insight, reference, event |
--source <url-or-path> |
Source attribution (URL, file path, or description) |
--source-type <type> |
Source type: user, url, file, import, derived, system (default: user) |
--detect-contradiction |
Detect conflicting memories (default threshold: 0.65) |
--room <room_id> |
Link memory to a room (collaborative context) |
--author <name> |
Who wrote the memory (1 to 128 characters). Recorded on the memory with or without --room; with --room it is also the room author (default there: anonymous) |
--json |
Output stored memory as JSON |
Unified search combining vector similarity with FTS5 full-text search, ranked by Reciprocal Rank Fusion (RRF). Default strategy since v0.16.0: fusion — a weighted RRF of the vector and hybrid rankings. Searches both memories and documents by default (unified mode). Hot memories (accessed within 7 days) get a score boost.
uteke recall "What framework does the API use?"
uteke recall "deployment" --limit 10
uteke recall "database config" --namespace hermes --json
uteke recall "server" --entity staging-server --json
uteke recall "config" --category infrastructure --limit 5
# Search documents only
uteke recall "API architecture" --type doc
# Search memories only (backward compatible)
uteke recall "deployment" --type memory
# Explain mode (#1160): show the ranking signals behind each result
uteke recall "database caching" --explain
# Budgeted context pack (#1281): bounded selection for prompt injection
uteke recall "database caching" --pack --budget 4000
uteke recall "database caching" --pack --exclude-ids abc123,def456| Flag | Description |
|---|---|
--type <type> |
Search scope: all (default — memories + documents, unified via RRF), memory (memories only), doc (documents only) |
--limit <n> |
Max results (default: 10, at most 100) |
--entity <name> |
Filter results to a specific entity |
--category <cat> |
Filter results to a specific category |
--content-format <fmt> |
Content display: auto (detect), text, json (pretty-print JSON memories) |
--where <key=value> |
Filter by JSON field on structured memories (e.g. --where role=CTO) |
--explain |
Show the ranking signals behind each result (#1160): final score, strategy, vector similarity + rank, FTS rank, RRF score with per-channel fusion contributions, and jaccard/salience/recency/graph boost deltas. Memory-only — not available with --type doc |
--pack |
Return a budgeted context pack (#1281) instead of a bare ranked list: {selected, skipped, budget_used, budget_chars}. Rank-order preserving greedy fill of the character budget; deterministic and LLM-free |
--budget <chars> |
Character budget for --pack (default: 4000) |
--exclude-ids <ids> |
Memory IDs already injected this turn, comma-separated — excluded from the pack and reported as skipped[reason=excluded] |
--json |
Output as JSON array |
Keyword text search with tag filtering.
uteke search "monorepo"
uteke search "deploy" --tags staging,prod --limit 20
uteke search "api" --namespace backend --json| Flag | Description |
|---|---|
--tags <tags> |
Filter by comma-separated tags |
--limit <n> |
Max results (default: 10) |
--json |
Output as JSON |
List memories with optional tag, entity, category filter and pagination.
uteke list --limit 20
uteke list --tag deploy --offset 10 --json
uteke list --entity staging-server --json
uteke list --category infrastructure --limit 10
uteke list --namespace hermes
uteke list --at 2026-06-01T12:00:00Z # Time-travel: list at point in time| Flag | Description |
|---|---|
--tag <tag> |
Filter by single tag |
--entity <name> |
Filter by entity name |
--category <cat> |
Filter by category |
--limit <n> |
Max results (default: 10, at most 1000) |
--offset <n> |
Skip first N results |
--at <timestamp> |
Query memories at point in time (RFC3339) |
--json |
Output as JSON |
Delete memories by ID, tag, tier, or all. Supports bulk operations.
# Delete single memory
uteke forget <uuid> --confirm
# Delete all with a tag
uteke forget --tag deploy --confirm
# Delete all cold-tier memories (>30 days old)
uteke forget --cold --confirm
# Delete everything in namespace
uteke forget --all --confirm
# Preview without deleting
uteke forget --tag stale --dry-run| Flag | Description |
|---|---|
--tag <tag> |
Delete all memories with this tag |
--cold |
Delete all cold-tier memories (>30 days) |
--all |
Delete all memories in namespace |
--confirm |
Skip confirmation prompt |
--dry-run |
Preview what would be deleted |
--reason <text> |
Why the memory is forgotten (with an ID). wrong or wrong: <note> also rejects the value, see below |
Forgetting a memory does not stop the same text from being written again, by an agent, an import or a later extraction. When a memory is forgotten because it is wrong, say so:
uteke forget <id> --reason "wrong: the port is 8767" --confirm
uteke supersede <old> <new> --reason wrong # the old value is rejectedThis records a tombstone: a hash of the text after normalisation (Unicode NFKC,
letter case, whitespace and invisible characters do not matter). Every write
refuses that text from then on: remember, room remember, update, import
(the row is skipped and counted as rejected_tombstone), import --full and
consolidation. The HTTP API answers 409 {"error": "rejected_value", "reason": ...},
MCP a tool error starting with rejected_value:. The tombstone survives prune
and is carried by export --full. A paraphrase is not caught. Any other reason
(--reason outdated) is only kept on the forgotten memory.
Queue conversation turns now, turn them into memories later (#1466). Capture makes no LLM call and no network request (one SQLite insert per turn), so an agent hook can call it at the end of every session. Extraction runs when you choose, on a budget, one extractor call per session.
uteke capture --session sess-42 --role user "We moved billing to PostgreSQL"
echo "Noted." | uteke capture --session sess-42 --role assistant
uteke extract-queue status # pending / extracting / done / failed
uteke extract-queue run --budget 5 # extract up to 5 sessions now- Capture is off by default: set
enabled = trueunder[capture]in the globaluteke.toml(a project file cannot set it). See Configuration. - Roles are
user,assistantandtool; a tool result is kept as a summary (its first 2000 characters). The privacy filter runs before a turn is queued. - Capturing the same text from the same role in the same session again is a no-op.
runuses the[extraction]settings: the LLM endpoint when one is configured, otherwise the offline rules. Facts are stored like any other write (duplicate check, rejected-value tombstones), taggedcapture, with the sourcecapture:<session>:<batch>. An extractor error (rate limit, provider down) stops the run and the session is retried next time; aftermax_attemptsit is marked failed. A session left mid-run by a crash is requeued after the lease.- Done turns are deleted after
retention_days(30). uteke-serveextracts on its own everyinterval_minutes(60) when capture is on,budget_per_runsessions per run, and doubles the wait after a run the extractor stopped (up to 16 intervals). Over HTTP a turn is queued withPOST /captureand the counts read withGET /capture/status; over MCP with theuteke_capturetool. Queueing is refused while capture is off (HTTP 409); the status always answers.
Install the lifecycle hooks of an agent app (#1465): recall at session start,
capture of each prompt and reply. Supported: claude (Claude Code), codex,
cursor. For pi and hermes, whose hooks are a plugin, connect installs the
memory-provider plugin (uteke init <agent> --memory-provider) and disconnect
removes its files while they are unchanged.
uteke connect claude --dry-run # what would be added; writes nothing
uteke connect claude # install or refresh
uteke disconnect claude # remove exactly what connect addedEach hook runs uteke hook-run <event> (hidden) through a guard that is a no-op
when uteke is not on PATH; hook-run always exits 0 and logs errors to
~/.codecora/uteke/hook.log. What was added is recorded in
~/.codecora/uteke/connect/<agent>.json; the original file is backed up once to
<file>.uteke-bak. uteke doctor reports hooks that a newer uteke would install
differently, or that were removed. Capture hooks need [capture] enabled = true.
Details: Claude Code, Codex,
Cursor.
uteke tombstone list # hash prefix, date, reason and the start of the text
uteke tombstone remove <hash|id> # allow the value again (8+ hash characters or the memory id)uteke promote <id> (restoring the forgotten memory) also removes its tombstone.
Find and merge duplicate memories using cosine similarity.
# Preview duplicates (dry run)
uteke consolidate --threshold 0.60 --dry-run
# Merge duplicates
uteke consolidate --threshold 0.60
# Higher threshold = more conservative (default: 0.90)
uteke consolidate --dry-runRecommended threshold: 0.60–0.70 for small embedding models (embeddinggemma-q4). Keeps newer memory, removes older.
Remove deprecated and expired temporal memories.
# Preview what would be pruned
uteke prune --ttl 30 --dry-run
# Prune deprecated/expired memories
uteke prune --ttl 30Safe memory lifecycle management: deprecate, promote, and inspect lifecycle status.
# Show lifecycle status (active vs deprecated counts + config)
uteke lifecycle status
# Scoped to a namespace
uteke lifecycle status --namespace my-agent
# Run a lifecycle cycle (deprecate aged + prune expired)
uteke lifecycle cycle
# Scoped cycle
uteke lifecycle cycle --namespace my-agent
# Promote a deprecated memory back to active
uteke lifecycle promote <memory-id>
# Restore is an alias for promote
uteke lifecycle restore <memory-id>| Subcommand | Description |
|---|---|
status |
Show active/deprecated counts and lifecycle config |
cycle |
Run lifecycle cycle (deprecate aged memories + prune expired) |
promote <id> |
Restore a deprecated memory to active status |
restore <id> |
Alias for promote |
See Configuration → Memory Lifecycle for lifecycle config options.
Show the full provenance report for a memory (#1172) — who wrote it, from what source, its trust tier, whether the content still matches the hash recorded at write time, and the complete event chain with actor + evidence.
# Human-readable audit report
uteke provenance <memory-id>
# JSON (for tooling)
uteke provenance <memory-id> --jsonHash verdicts: ✓ matches (content unchanged since write), ✗ MISMATCH
(content modified after write — investigate), — (memory predates
schema v18; hash will be recorded on next content update).
Resolve a conflict: mark the old memory superseded by a newer one (#1053) — wires the supersession edge pair, soft-deprecates the old memory, and records the resolution in the contradiction ledger (#1172).
uteke supersede <old-memory-id> <new-memory-id> --reason "decision pivot"Inspect the contradiction resolution ledger (#1172) — memories that were superseded by conflict resolution and are not restored.
# List the resolution ledger
uteke contradictions list
# Filter by namespace, cap entries
uteke contradictions list --namespace ops --limit 20
# JSON (for tooling)
uteke contradictions list --json
# Restore a superseded memory (full UUID or unambiguous prefix)
uteke contradictions undo <memory-id>Manage namespaces — list, inspect, switch defaults, and manage members (#1181).
# List all namespaces with counts
uteke namespace list
# Show stats for a namespace
uteke namespace stats my-agent
# Switch default namespace (saved to config)
uteke namespace switch my-agent
# Move a memory to another namespace (#1181 — no re-embed)
uteke namespace move <memory-id> other-ns
# Rename a namespace — merges into an existing target (#1181)
uteke namespace rename old-ns new-ns
# Delete a namespace with an explicit strategy for its memories (#1181)
uteke namespace delete temp-ns --strategy merge --target archive --confirm
uteke namespace delete ghost-ns --strategy deprecate --confirmDelete strategies: refuse (default — refuses while any memory references the
name), merge (move all memories to --target, the name vanishes), or
deprecate (soft-delete — restorable via uteke lifecycle/promote, never
hard-deleted). --confirm is required for delete.
Moves whole namespaces into default, carrying each namespace's meaning over to
a room, a tag, an author and/or a source (namespaces are deprecated, see
Namespaces are deprecated).
# map.toml: one table per namespace
[map."research-x"]
room = "research-x" # created when it does not exist
author = "agent-a" # targets compose: room, tag, author, source
[map."hermes"]
tag = "agent:hermes"
[map."scratch"]
drop = true # soft-delete; needs --allow-droputeke namespace migrate --map map.toml # dry run: report only
uteke namespace migrate --map map.toml --apply # export first, then migrate
uteke namespace migrate --map map.toml --apply --allow-drop- The dry run writes nothing.
--applyfirst writes a full export (namespace-migrate-<UTC time>.ndjsonnext to the database) and only then migrates, one transaction per namespace. Restore it withuteke import --fullinto a fresh store. Run it on a copy of the database first. defaultcannot be named in the map. Namespaces the map does not name are listed and left alone; a mapped namespace with no live memories is reported and skipped, so re-running the same map changes nothing.- Only live memories move. Soft-deleted ones stay in their namespace (an export does not carry them).
- A memory that already has a different
authororsourcekeeps it; the report counts it as a conflict. A tag already present is not added twice.
Namespace resolution order: --namespace flag → UTEKE_NAMESPACE env → uteke.toml → "default"
Manage tags across all memories.
# List all tags with counts
uteke tags list --by-count
# Rename a tag
uteke tags rename old-tag new-tag
# Delete a tag from all memories
uteke tags delete unused-tagAdditional flags not shown in the basic example above:
# Minimum similarity score filter
uteke recall "database config" --min 0.7
uteke recall "database config" --strict # uses min_score_strict (default 0.5)
uteke recall "database config" --min 0.25 # opt-in similarity threshold (default 0.0 since #1223: fusion scores are rank-based)
# Time-travel: query memories at specific point in time
uteke recall "deployment process" --at 2026-06-01T12:00:00Z
# Relationship graph traversal
uteke recall "auth" --related --depth 2
# Recall strategy (fusion | vector | fts5 | hybrid | graph)
uteke recall "auth" --strategy fusion # default since 0.16.0 — weighted RRF of vector + hybrid rankings
uteke recall "auth" --strategy hybrid # vector + FTS5 fused via RRF (k=60)
uteke recall "auth" --strategy vector # vector similarity only
uteke recall "auth" --strategy fts5 # full-text search only
uteke recall "auth" --strategy graph # hybrid + graph-signal reranking (#378)The graph strategy runs the hybrid (RRF) pipeline, then fuses graph
signals from the memory_edges table into each result's score. A memory
that is well-connected in the graph (referenced by many others, high edge
density) drifts upward; isolated memories are untouched.
The boost is additive and log-scaled, so it saturates quickly and never
lets a single hub dominate. Configure the weights under [recall] in
uteke.toml (see Configuration):
# Subtle boost (default): well-connected memories nudge up slightly
uteke recall "architecture" --strategy graph
# Stronger authority boost via env var
UTEKE_GRAPH_AUTHORITY_WEIGHT=0.3 uteke recall "architecture" --strategy graphCold start (no edges yet): graph behaves identically to hybrid — the
boost is zero when there are no signals.
uteke recall "api design" --context| Flag | Description |
|---|---|
--min <score> |
Minimum score (default 0.0 since 0.17.x, #1223: fusion scores are rank-based, not cosine). --min-score is accepted as an alias (#1593) |
--strict |
Use strict threshold (min_score_strict, default 0.5) |
--at <timestamp> |
Query memories at point in time (RFC3339) |
--related |
Follow relationship edges |
--depth <n> |
Traversal depth for --related |
--context |
AI-prompt formatted output |
--salience <true|false> |
Without the flag the salience boost is on with weight 0.1. --salience true uses the configured [recall] salience_weight (default 0.15); --salience false turns it off |
--recency <true|false> |
Without the flag the recency boost is on with weight 0.1. --recency true uses the configured [recall] recency_weight (default 0.15); --recency false turns it off |
The Jaccard reranking signal has no flag: set [recall] jaccard_weight above 0 to enable it.
A recall score is base_score + boosts, and the base means something
different per strategy. Scores are for ordering results within one query;
they are not a similarity percentage and are not comparable across strategies,
queries or stores.
| Strategy | base_score |
Typical range of the base |
|---|---|---|
fusion (default) |
Weighted RRF of the vector and hybrid rankings: 1.7 / (60 + rank_v + 1) + 1.0 / (60 + rank_h + 1). A function of rank, not of similarity |
at most about 0.044 (rank 1 in both) |
hybrid |
RRF of the vector and FTS5 rankings divided by the best possible sum, so a memory at the top of both rankings is about 1.0 |
up to 1.0 |
vector |
The vector similarity of the query and the memory | up to about 1.0 |
fts5 |
Normalised keyword rank (rank 1 is 1.0) |
up to 1.0 |
Boosts are added on top and are not capped, so a final score can exceed
1.0 (for example 1.1169 for a hybrid result):
salience_boost= salience score x salience weight. The salience score combines importance, access signal and pinned state.recency_boost= recency score x recency weight. A memory created just now has recency score1.0; it decays with the memory type's half-life.jaccard_boostandgraph_boostapply only when those signals are enabled.
Both weights are 0.1 by default, in the CLI and in uteke-serve alike. The
configured [recall] weights (default 0.15) are used only when
--salience / --recency are passed explicitly, and uteke-serve does not read
them yet (#1355).
The salience score includes an access signal, so scores drift up a little as a
memory is recalled: in a three-recall test on a fresh store salience_boost
went 0.025, 0.02676, 0.02977. Do not expect the same query to return
exactly the same scores twice.
Because fusion's base is so small, the boosts dominate its absolute value, and
two memories at neighbouring ranks have final scores that differ only in the
third or fourth decimal. Rounded to three decimals they can look identical even
though the order is decided. Use --explain for the exact breakdown; this is
the output for the top result of a default (fusion) recall:
{
"strategy": "fusion",
"final_score": 0.16899788,
"base_score": 0.043997884,
"vector_similarity": 0.76310307,
"vector_rank": 1,
"rrf_score": 0.043997884,
"fusion_vector_contribution": 0.027868852,
"fusion_hybrid_contribution": 0.016129032,
"salience_boost": 0.025,
"recency_boost": 0.1
}Here 0.16899788 = 0.043997884 (rrf_score) + 0.025 (salience) + 0.1 (recency).
What this means for thresholds: --min compares against the final score, so a
value that makes sense for vector (similarity scale) removes everything in
fusion (base around 0.04), and a small value keeps almost everything in
hybrid or fts5. The default is 0.0 for this reason (#1223); only set
--min after looking at --explain output for your own queries and strategy.
Room-based memory management:
# Create a room
uteke room create "project-kickoff" --title "Project Kickoff"
# List rooms (cross-namespace by default, #392)
uteke room list
uteke room list --namespace my-agent # scoped
# Show room stats and participants
uteke room stats "project-kickoff"
# Recall within a room (semantic)
uteke room recall "project-kickoff" --query "database decision"
# Change the title or description, or rename the room (#1202)
uteke room update "project-kickoff" --description "Kickoff decisions"
uteke room rename "project-kickoff" "kickoff"
# Add an existing memory to a room without copying it (#1589)
uteke room link <memory-id> "project-kickoff" --author alice
# Move a memory from one room to another (#1202)
uteke room move-memory <memory-id> --from "project-kickoff" --to "kickoff"
# Generate structured document from room
uteke room document "project-kickoff"
# Room summary (LLM-free, tag clustering)
uteke room summary "project-kickoff"
# Delete room (memories are NOT deleted, only room links)
uteke room delete "project-kickoff" --confirm
# Link a document to a room (#859, positional slug)
uteke room add-document "project-kickoff" "architecture-spec"
# Unlink a document from a room (#859)
uteke room remove-document "project-kickoff" "architecture-spec"
# List documents linked to a room (#859)
uteke room list-documents "project-kickoff"
# List rooms that reference a document (#859, positional slug)
uteke room list-rooms "architecture-spec"
# Consolidate a room's memories (#1088) — dry-run by default, no LLM calls
uteke room consolidate "project-kickoff"
# Execute consolidation (LLM calls + writes; budget-capped)
uteke room consolidate "project-kickoff" --apply --max-calls 20- Dry-run default: shows memory count, batches, and estimated LLM calls — zero API calls.
--applyrequires LLM config (same[extraction]setup asimport --extract).--max-calls(default 10) is a hard budget: failed LLM calls count too, batches beyond the cap are skipped.- Source memories are soft-deprecated (never deleted), each carrying a
consolidated into <id>reason. - New consolidated records pass a provenance policy gate (hedging language, trust tier) before being written.
Run performance benchmarks with synthetic data:
# Default: 100, 1000, 10000 memories
uteke bench
# Custom counts
uteke bench --counts 500,5000
# JSON output
uteke bench --jsonMeasures insert throughput, recall latency (avg + p95), and storage footprint.
Pin memories so they never decay:
uteke pin <id>
uteke unpin <id>Recalculate importance scores:
uteke importanceMemory aging management with auto-cleanup.
# Show hot/warm/cold breakdown
uteke aging status
# Preview memories older than 90 days
uteke aging preview --older-than-days 90
# Delete memories older than 180 days
uteke aging cleanup --older-than-days 180 --yes| Subcommand | Flags | Description |
|---|---|---|
status |
— | Show hot/warm/cold/never-accessed counts |
preview |
--older-than-days N (default 180), --max-access-count N (default 1) |
Dry-run preview of cleanup candidates |
cleanup |
--older-than-days N (default 180), --max-access-count N (default 1), --yes |
Delete aged memories (--yes skips confirmation) |
Import memories from a file (or stdin with -). Format is auto-detected from
the extension and content; override with --format.
# Import JSONL exported by `uteke export`
uteke import memories.jsonl
# Import markdown/plain text (split into chunks)
uteke import notes.md --tags imported,notesuteke export --full bundle.ndjson # on the source: memories, rooms, graph, documents, ...
uteke import --full bundle.ndjson # on the targetThe bundle restores documents with their slug, title, parent (hierarchy), path and content,
plus rooms (with each member's role), edges, the graph and the timeline, keeping the original
ids. Memories keep their author, author type, provenance hash and recall count, and timeline
events keep their actor and evidence. Deprecated memories are left out of the bundle, and a
bundle row marked deprecated is restored deleted, never live. A bundle written by
0.22.1 or earlier lacks these fields: import applies the defaults and rebuilds document paths
from the parent chain. It carries no vectors: import
regenerates them (memories are marked for uteke repair --reembed, document chunks are
re-embedded right away). --full makes any other file an error instead of a plain import. The
bundle is a file, so a large document does not pass through a tool response; POST /import
stays JSONL-only.
A JSONL export carries each memory's room ids. Import links the memory to every room that
exists in the target store, also for a duplicate of a stored memory, and reports the new
links (room_links) and the rooms the target lacks (rooms_missing). Create the missing
rooms (uteke room create <ID>) and import the file again to finish the links; nothing is
copied.
A JSONL row keeps its identity: import stores it under its id and keeps its
memory_type, importance, pinned, content_type and slug. A missing or invalid value
falls back to the old default (a new id, fact, 0.5, not pinned, text, no slug), so files
from older versions import as before. Importing the same file again adds nothing. A copy into
another namespace (--namespace) gets new ids, since an id is unique across the store. The result
counts what was left out, apart from skipped (invalid or rejected rows):
duplicates_skipped: the row is already stored (same id and content, the same content in the namespace, or for a row without an id a near-identical memory). Its rooms are linked to the stored memory.id_conflicts_skipped: the id is stored with other content. The stored memory is not changed.soft_deleted_skipped: the content (or id) was deleted in this store. Importing an old export does not bring it back.
A row marked "deprecated": true (a Uteke Cloud export carries deleted memories) is stored
deleted, without a vector.
A Cloud export (GET /export on Uteke Cloud) imports with its documents and rooms:
uteke import cloud-export.ndjson # or --defer-embed for a large one- The manifest (first line) is skipped.
"type": "document"rows become documents: slug, title, content, tags and the parent (a slug, or the parent's id), whatever the order of the rows. A document with the same slug is updated in place when it changed and left alone when it did not. A parent that is neither in the file nor stored is counted inparent_unresolvedand the document goes to the root."type": "room"rows create the rooms that do not exist (title, description; an existing room is not changed) and link theirdoc_slugs. A slug that is not stored is counted inroom_documents_missing.- Documents and rooms are stored before the memories, so each memory's
roomsfind the rooms of the same file.
The result adds documents_imported, documents_updated, documents_unchanged,
parent_unresolved, rooms_imported, rooms_existing, room_documents_linked and
room_documents_missing (each only when non-zero). With --defer-embed the document chunks
are stored without vectors as well. Over HTTP, POST /import takes a body of up to 64 MiB
(UTEKE_MAX_IMPORT_SIZE, in bytes; the other routes keep 10 MB). A larger file gets a 413
that names the limit: split it into several calls (with "defer_embedding": true each returns
in seconds), raise the limit on the server, or run uteke import on the server host, which has
no limit.
A JSON/JSONL import embeds every row while it imports. With the local model that
keeps the CPU busy for the whole file, and an embedding backend that is down stops
the import at that row. --defer-embed stores the rows without a vector instead:
the import does not wait on the embedder, the rows are found by keyword search at
once, and the vectors are added later in portions you choose:
uteke import big-export.jsonl --defer-embed
uteke repair --reembed --limit 500 --pause-ms 20 # repeat until nothing is leftrepair --reembed only picks rows that have no vector, so each run continues where
the last one stopped and reports how many it did not try. --limit N stops after N
rows were embedded; a row that fails does not count, so rows the backend keeps
rejecting cannot hold back the rest. Rows embedded this way also get
the cosine links remember makes. Without vectors the cosine duplicate check
(similarity of 0.95 or more) cannot run during the import, so only exact copies of
a stored memory, or of an earlier row in the same file, are skipped; near-duplicates
stay. --defer-embed works with JSON/JSONL input (not --full, --extract or
--batch-dir).
Over HTTP the same switch is "defer_embedding": true in the POST /import body; the
response then adds deferred_embedding. That is the bulk-import runbook for a server: send
the file with defer_embedding (each call returns in seconds because no row is embedded in
the request, so a file larger than the body limit can be split into several calls), then run
uteke repair --reembed --limit N on the server until nothing is left.
Raw source material (chat transcripts, long notes, exported dumps) is noisy:
greetings, filler, boilerplate. Importing it verbatim pollutes recall. With
--extract, uteke first sends the text to an OpenAI-compatible chat-completions
endpoint, asks the model to distill it into atomic facts, and stores one memory
per fact.
This is opt-in. Without --extract, import makes no network calls and stays
fully offline.
# Distill a transcript into atomic facts before storing
uteke import session.txt --extract \
--extract-model gpt-4o-mini \
--extract-base-url https://api.openai.com/v1 \
--extract-api-key sk-...
# Use a local Ollama model
uteke import notes.md --extract \
--extract-model llama3.1 \
--extract-base-url http://localhost:11434/v1Settings resolve in this order: CLI flag > UTEKE_EXTRACTION_* env var >
[extraction] config section > built-in default. The API key falls back to the
embedding / OPENAI_API_KEY credential, so an existing OpenAI-compatible setup
needs no duplicate key.
| Flag | Description |
|---|---|
--extract |
Enable LLM extraction (off by default) |
--extract-model <M> |
Override the chat model |
--extract-base-url <U> |
Override the endpoint base URL |
--extract-api-key <K> |
Override the API key |
--extract-max-facts <N> |
Cap facts kept per document (0 = default) |
See configuration for the [extraction] config block and
UTEKE_EXTRACTION_* environment variables.
When the LLM extracts facts, it groups them by topic (scene) and assigns a priority score (0.0–1.0) to each. This means:
- Scene tags — each fact gets a
scene:<topic>tag automatically, so you can filter by topic during recall. - Priority — important decisions get higher
importance(0.7–0.9), routine facts get lower (0.3–0.5). - Type — facts are tagged with a semantic type (
decision,fact,preference, etc.) when the model provides one.
Offline extraction (no LLM) is unaffected — it continues to produce flat strings with default importance.
Import all files from a directory in one command. Each file is processed according to its type:
| Extension | Strategy | Description |
|---|---|---|
.md / .markdown |
Document (default) | Full content → auto-chunk → embed. No LLM. |
.md + --extract |
Memory extract | LLM fact extraction → atomic facts → embed. |
.txt / .jsonl |
Memory extract | LLM fact extraction (requires --extract). |
.txt / .jsonl + --as-doc |
Document override | Import as document, skip LLM. |
# Dry run — preview what would be imported
uteke import --batch-dir ./knowledge --dry-run
# Import all markdown as documents (no LLM, fully offline)
uteke import --batch-dir ./docs --recursive --tags docs
# Import with LLM fact extraction
uteke import --batch-dir ./notes --extract \
--extract-model gpt-4o-mini \
--extract-base-url https://api.openai.com/v1 \
--tags imported
# Force all files as documents (skip extraction)
uteke import --batch-dir ./raw --as-doc --recursive
# Limit file size (default: 1MB)
uteke import --batch-dir ./large-docs --max-size 500000| Flag | Description |
|---|---|
--batch-dir <PATH> |
Directory to import (enables batch mode) |
--recursive |
Recurse into subdirectories |
--as-doc |
Force all files as documents (skip LLM extraction) |
--as-memory |
Force all files through LLM extraction |
--max-size <BYTES> |
Skip files larger than N bytes (default: 1,000,000) |
--dry-run |
Preview files and strategies without importing |
Knowledge graph operations (v0.2.0). Nodes and edges stored in SQLite (graph_nodes, graph_edges tables, schema v7).
# List all nodes (optionally filter by entity type)
uteke graph nodes
uteke graph nodes --entity-type person
# List all edges (optionally filter by relation)
uteke graph edges --relation owns
# Find neighbors of a node via BFS
uteke graph neighbors alice --depth 2
# Shortest path between two nodes
uteke graph path alice "project-x" --max-depth 5
# Query edges by relation type
uteke graph query part_of
# Show graph statistics
uteke graph stats| Subcommand | Flags | Description |
|---|---|---|
nodes |
--entity-type <t> |
List graph nodes |
edges |
--relation <r> |
List graph edges |
neighbors <label> |
--depth N (default 1) |
BFS neighbors of a node |
path <source> <target> |
--max-depth N (default 5) |
BFS shortest path |
query <relation> |
— | Query edges by relation type |
stats |
— | Show graph statistics |
List auto-wired edges for a memory (v0.2.1, #346). Edges are auto-extracted from content on every remember() call using pure pattern matching — no LLM.
| Pattern | Edge type | Resolved via |
|---|---|---|
[[slug]] |
references |
memories.slug lookup |
@tag |
tagged_as |
most recent memory with that tag |
^<uuid> |
supersedes |
direct memory UUID |
><uuid> |
replies_to |
direct memory UUID |
rel:<type>:<uuid> in --meta |
<type> |
direct memory UUID (legacy compat) |
# List direct edges (both directions)
uteke edges <memory-id>
# Multi-hop BFS across the edge table
uteke edges <memory-id> --deep 2
# Only show incoming edges (backlinks)
uteke edges <memory-id> --direction incoming
# JSON output
uteke edges <memory-id> --jsonWith --deep N, returns memory ids reachable within N hops (cycles detected, start excluded).
--direction accepts incoming, outgoing, or both (default both).
Rebuild referenced_by backlinks from existing forward edges (v0.2.1, #350).
Every forward edge (references, tagged_as, supersedes, replies_to)
automatically gets an inverse referenced_by edge on remember(). This
command repairs stores that pre-date #350, or were written to via the
low-level edge API. Idempotent.
# Rebuild and print a summary
uteke rebuild-backlinks
# Print only the count of new backlinks (script-friendly)
uteke rebuild-backlinks --quiet
# JSON output
uteke rebuild-backlinks --jsonRun the full maintenance pipeline in one command (v0.2.1, #353).
Executes phases in dependency order: lint → backlinks → dedup → contradict → orphans → compact → verify. Each phase records its status. Errors in individual phases are recorded but do not abort the pipeline.
# Run all phases
uteke dream
# Run specific phases only
uteke dream --phases lint,orphans
# Dry-run (preview what would change)
uteke dream --dry-run
# Scoped to a namespace
uteke dream --namespace my-agent
# Run only contradiction detection
uteke dream --phases contradict| Flag | Description |
|---|---|
--phases <list> |
Comma-separated subset: lint, backlinks, dedup, contradict, orphans, compact, verify |
--dry-run |
Preview without making changes |
--namespace <ns> |
Run scoped to a specific namespace (backlinks and verify are global) |
--json |
JSON output |
| Phase | Description |
|---|---|
lint |
Check for invalid memory types, missing slugs, stale deprecated flags |
backlinks |
Rebuild referenced_by edges (same as rebuild-backlinks) |
dedup |
Find and merge near-duplicate memories (cosine ≥ 0.90) |
contradict |
Detect contradictory memories (threshold 0.65) and flag for review |
orphans |
Find disconnected, low-importance memories |
compact |
Apply auto-prune to cold-tier and deprecated memories |
verify |
Verify DB and index consistency |
Record feedback on a memory's usefulness (v0.8.0, #718). Adjusts importance score: +0.05 for helpful, -0.10 for unhelpful.
uteke feedback helpful <memory-id>
uteke feedback unhelpful <memory-id>With --json flag, outputs structured JSON with id, feedback type, delta, and new importance value.
Find orphan memories — disconnected nodes with low importance and few accesses (v0.2.1, #351).
# Find orphans with default thresholds
uteke orphans
# Custom threshold and result count
uteke orphans --threshold 0.2 --limit 100
# JSON output for scripting
uteke orphans --json| Flag | Description |
|---|---|
--threshold <n> |
Importance below which a memory is a candidate (default: 0.3) |
--limit <n> |
Max results, 0 = all (default: 50) |
--namespace <ns> |
Scope to namespace |
--json |
JSON output |
View chronological event log for a memory (v0.2.1, #347).
Every memory has an audit trail: creation, updates, type changes, supersession, edge additions, and pin/unpin events.
# Show timeline for a memory
uteke timeline <memory-id>
# Limit to last N events
uteke timeline <memory-id> --limit 10
# JSON output
uteke timeline <memory-id> --json| Flag | Description |
|---|---|
--limit <n> |
Max events, 0 = all (default: 20) |
--json |
JSON output |
| Command | Description |
|---|---|
uteke get <id> |
Retrieve a single memory by UUID |
uteke forget <id> |
Delete a memory by UUID |
uteke forget --tag <tag> |
Delete all memories with a tag |
uteke forget --cold |
Delete all cold-tier memories |
uteke forget --all |
Delete all memories in namespace |
uteke consolidate |
Find and merge duplicate memories |
uteke prune |
Remove deprecated/expired memories |
uteke stats |
Show store statistics with tier breakdown |
uteke export |
Export memories to JSONL (no embeddings) · --full = structural export: manifest + rooms/graph/edges/documents/chunks/timeline (round-trips the whole store, format structural-v1) |
uteke import <file> |
Import memories from JSONL/Markdown/text (--extract distills with an LLM) — auto-detects structural exports (manifest first line) and restores the full store; restored memories re-embed via uteke repair --reembed |
uteke doctor |
Health check (DB, index, model, consistency) |
uteke verify |
Verify DB and index consistency |
uteke verify-checksums --binary <path> |
Verify binary integrity against SHA256 checksums |
uteke repair |
Rebuild index from SQLite |
uteke repair --rebuild |
Rebuild index from SQLite (explicit) |
uteke repair --reembed |
Regenerate missing embeddings for memories without vectors (#906); --limit N stops after N rows were embedded and --pause-ms MS sleeps between rows (#1608) |
uteke namespace list |
List all namespaces with memory counts |
uteke namespace stats <name> |
Show stats for a namespace |
uteke namespace switch <name> |
Set default namespace in config |
uteke namespace move <id> <ns> |
Move a memory to another namespace, no re-embed (#1181) |
uteke namespace rename <old> <new> |
Rename a namespace; existing target = merge (#1181) |
uteke namespace delete <ns> --confirm |
Delete a namespace (--strategy refuse|merge|deprecate, #1181) |
uteke init --agent <type> |
Initialize integration (opencode, pi, claude, cursor, hermes) |
uteke init --agent hermes --memory-provider |
Install uteke as Hermes's default memory provider (auto recall + extraction). See Hermes integration, Mode B. Note: Hermes Mode B deprecated — see integrations/hermes.md for migration. |
uteke init --agent pi --memory-provider |
Install uteke as pi's default memory provider (auto recall + extraction, #575/#577) |
uteke init --agent claude --memory-provider |
Install uteke as Claude Code's default memory provider (auto recall + extraction, #575/#577) |
uteke init --agent cursor --memory-provider |
Install uteke as Cursor's default memory provider (auto recall + extraction, #575/#577) |
uteke init --agent opencode |
Generate AGENTS.md with uteke instructions for OpenCode (#612) |
uteke completions <shell> |
Generate shell completions |
Start a persistent HTTP server for fast AI agent access. Eliminates cold start (~980ms → ~21ms per operation).
# Start server on default port (8767)
uteke-serve
# Custom port
uteke-serve --port 9000
# With logging
RUST_LOG=info uteke-serve --port 8767When [server] enabled = true is set in config, the CLI auto-routes commands through the server. Falls back to local store if server is not running.
See the HTTP API Reference for the complete list of 50+ endpoints, request/response schemas, and examples.
Two MCP transport modes are available (v0.2.1, #381):
# stdio transport (for Claude Desktop, Cursor, etc.)
uteke-mcp
# HTTP transport (POST /mcp on uteke-serve)
curl -X POST http://127.0.0.1:8767/mcp \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2025-06-18" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}'Protocol version: 2025-06-18 (Streamable HTTP spec).
Wiki/knowledge base engine — hierarchical documents with auto-chunking, tree operations, and hybrid search.
Create or update a document from file, content, or stdin.
# From file
uteke doc create architecture --file guide.md --tags wiki,tech
# From inline content
uteke doc create notes --content "# Notes\n\nQuick notes" --title "My Notes"
# From stdin
cat README.md | uteke doc create readme --file -
# As child of another document
uteke doc create chapter1 --parent book --file ch1.md| Flag | Description |
|---|---|
--title <title> |
Document title (auto-derived from first # heading if omitted) |
--file <path> |
Read content from file (- for stdin) |
--content <text> |
Inline content (alternative to --file) |
--tags <tags> |
Comma-separated tags |
--parent <slug> |
Parent document slug (creates as child, #438) |
Get a document by slug or ID.
uteke doc get architecture
uteke doc get architecture --jsonList all documents (global — not namespace-scoped, v0.7.0).
uteke doc list --limit 20
uteke doc list --tree # Indented tree view| Flag | Description |
|---|---|
--limit <n> |
Max results (default: 20) |
--tree |
Show as indented tree (recursive children) |
Search documents using hybrid, semantic, or FTS5 search (#440).
uteke doc search "authentication flow"
uteke doc search "database" --mode semantic
uteke doc search "API reference" --mode fts --limit 5| Flag | Description |
|---|---|
--mode <mode> |
hybrid (default), semantic, or fts |
--limit <n> |
Max results (default: 5) |
Partially update a document — only provided fields are changed (#589). Content changes trigger chunk rebuild; metadata-only or title-only updates skip it.
# Update title only (no chunk rebuild)
uteke doc update architecture --title "New Architecture Guide"
# Update content from file (triggers chunk rebuild)
uteke doc update architecture --file updated-guide.md
# Update content from stdin
echo "# New content" | uteke doc update architecture --file -
# Replace tags
uteke doc update architecture --tags wiki,tech,v2
# Replace metadata
uteke doc update architecture --metadata '{"draft": false, "reviewer": "CTO"}'
# Multiple fields at once
uteke doc update architecture --title "Final Guide" --tags wiki,published| Flag | Description |
|---|---|
--title <title> |
New title (no chunk rebuild) |
--content <text> |
New content (triggers chunk rebuild) |
--file <path> |
Read new content from file (- for stdin; triggers chunk rebuild) |
--tags <tags> |
Replace tags (comma-separated) |
--metadata <json> |
Replace metadata (JSON string) |
At least one field is required. Omitted fields are left unchanged.
Move a document to a new parent or root (#438).
uteke doc move chapter1 --parent new-book
uteke doc move orphan-doc # Move to rootDelete a document by ID or slug (cascades to children and chunks).
uteke doc delete architecture
uteke doc delete <id>Export all documents as JSON or markdown.
uteke doc export # markdown to stdout
uteke doc export --json # JSON to stdout
uteke doc export --front-matter # markdown, each document with YAML front-matter
uteke doc export --front-matter --output docs.md--front-matter (off by default, so the plain output is unchanged) puts a YAML
block before each document body, so a vault or static-site import keeps the
hierarchy:
---
slug: "chapter-1"
title: "Chapter 1: \"Getting started\""
tags: ["guide", "draft"]
parent: "book"
---parent is the parent document's slug, or "" for a root document. Values are
written as double-quoted strings, so titles with :, #, quotes or newlines
stay valid YAML. The body after the closing --- is byte-for-byte what the
export prints without the flag. With --json the flag is ignored, since each
JSON document already carries these fields.
There is no uteke doc import that reads this front-matter back:
uteke import --batch-dir <dir> --as-doc stores a file's whole content,
front-matter included, under a slug taken from the file path. For a lossless
round trip of documents (slug, title, hierarchy, content) use
uteke export --full and uteke import --full.
# All nodes + edges + stats
curl http://127.0.0.1:8767/graph
# Response: { nodes: [...], edges: [...], stats: {...} }# Create a typed edge
curl -X POST http://127.0.0.1:8767/graph/edge \
-H "Content-Type: application/json" \
-d '{"from": "<uuid>", "to": "<uuid>", "edge_type": "references"}'
# Delete an edge by ID
curl -X DELETE "http://127.0.0.1:8767/graph/edge?id=<edge-uuid>"Dual-role API token model:
| Flag / Env | Role | Access |
|---|---|---|
--auth-token / UTEKE_AUTH_TOKEN |
Admin | All endpoints (GET, POST, DELETE) |
--read-only-token / UTEKE_READ_ONLY_TOKEN |
ReadOnly | All read endpoints (GET + POST search/list/graph). 403 on writes. |
# Start with dual tokens
uteke-serve --auth-token admin-secret --read-only-token viewer-key
# Read-only client (GET only)
curl -H "Authorization: Bearer viewer-key" http://127.0.0.1:8767/stats
# Write attempt fails
curl -X POST -H "Authorization: Bearer viewer-key" ... # 403 ForbiddenThe input limits are fixed in this release:
| Limit | Value |
|---|---|
| Memory content | 100,000 characters |
| Tags per memory | 20 |
| Tag length | 50 characters |
| Server request body | 10,485,760 bytes (10 MB) |
A [limits] section and the UTEKE_MAX_* variables are parsed but not applied
yet, so changing them has no effect. The default --limit for recall, search and
list is 10 on every surface.
For the history of every command, see the CHANGELOG.