Kioku Lite — Agent Memory Skill
Kioku Lite is a long-term personal memory engine running fully local. Zero Docker, zero server. All data in SQLite. You (the agent) extract entities → call kg-index.
1. Language Handling
- Detect the user's language automatically. Always respond in the same language the user is writing in.
- Entity names: Extract AS-IS in the user's original language — do NOT translate.
- Entity types & relation types: ALWAYS use the predefined English labels (PERSON, EMOTION, TRIGGERED_BY, etc.).
- Evidence & saved text: Write in the user's original language.
Example (Vietnamese):
"Hôm nay cãi nhau với sếp, cảm thấy rất căng thẳng"
→ entities: [{"name":"sếp","type":"PERSON"}, {"name":"Căng thẳng","type":"EMOTION"}]
→ relationships: [{"source":"Căng thẳng","rel_type":"TRIGGERED_BY","target":"Cãi nhau","evidence":"cãi nhau với sếp, cảm thấy rất căng thẳng"}]
Example (English):
"Had an argument with my boss, feeling very stressed"
→ entities: [{"name":"boss","type":"PERSON"}, {"name":"Stress","type":"EMOTION"}]
→ relationships: [{"source":"Stress","rel_type":"TRIGGERED_BY","target":"Argument with boss","evidence":"had an argument with my boss, feeling very stressed"}]
2. Installation & Setup
Check if installed
kioku-lite --help
Install (if not found)
pipx install "kioku-lite[cli]" # Global — recommended
# OR: pip install "kioku-lite[cli]" # Inside a venv
(Optional) Pre-download embedding model (~1.1GB)
kioku-lite setup
Inject SKILL.md for agent discovery
kioku-lite init --global # Global: works in ALL projects
# OR: kioku-lite init # Per-project: creates ./AGENTS.md + .agents/skills/
3. Session Start — Run EVERY Session
Step A — Check active profile:
kioku-lite users
Step B — Ask user which profile to use (if multiple exist), then activate:
kioku-lite users --use <profile_name>
# To create a new profile: kioku-lite users --create <name>
Step C — Load context:
kioku-lite search "profile background goals recent" --limit 10
users --useonly needs to run once per session. All subsequent commands use it automatically.
4. Command Reference
Write Commands
| Command | When to use |
|---|---|
kioku-lite save "TEXT" --mood MOOD --event-time YYYY-MM-DD |
User shares new information |
kioku-lite kg-index HASH --entities '[…]' --relationships '[…]' --event-time YYYY-MM-DD |
Right after save — index entities you extracted |
kioku-lite kg-invalidate --source X --target Y --date YYYY-MM-DD --reason "..." |
Mark a fact as superseded/outdated |
Query Commands
| Command | When to use |
|---|---|
kioku-lite search "QUERY" --entities "E1,E2" --limit 10 |
Recall with entity context; use PPR for better multi-hop |
kioku-lite search "QUERY" --include-historical |
Include superseded facts in results |
kioku-lite recall "ENTITY" --hops 2 --limit 15 |
All memories + graph around one entity (BFS) |
kioku-lite connect "A" "B" --include-historical |
Explain relationship between two entities |
kioku-lite entities --limit 50 |
View known entity vocabulary |
kioku-lite timeline --limit 20 |
Chronological memory list |
Dedup & Entity Management
| Command | When to use |
|---|---|
kioku-lite dedup-scan |
Find near-duplicate entities (vec sim ≥ 0.98 + name sim ≥ 0.85) |
kioku-lite dedup-scan --auto |
Auto-merge duplicate pairs that meet thresholds |
kioku-lite merge "source" "target" |
Manually consolidate two entities (source merged into target) |
kioku-lite kg-alias "CANONICAL" --aliases '["alias1"]' |
Register entity aliases (SAME_AS) |
Consolidation & Analysis
| Command | When to use |
|---|---|
kioku-lite consolidate --half-life 90 --older-than 30 |
Periodic maintenance: detect stale edges, old memories, merge candidates |
kioku-lite consolidate --auto-merge |
Auto-merge duplicates found during consolidation |
kioku-lite clusters |
List all detected entity clusters with suggested labels |
kioku-lite cluster PERSON |
Show entities and memories in a specific cluster |
5. save — Store a Memory
kioku-lite save "TEXT" --mood MOOD --tags "tag1,tag2" --event-time "YYYY-MM-DD"
Output: JSON with content_hash → use immediately with kg-index.
Rules:
- ✅ Preserve full original text — do not summarize or paraphrase
- ✅
--event-timeis REQUIRED whenever the event is not today. Search filters use this field. Parse relative dates: "hồi tháng 3 năm ngoái" →2025-03-01, "yesterday" → yesterday's date, "năm 2019" →2019-01-01. Omit only if the event is happening today or timing is truly unclear. - ✅ Use the same
--event-timeon bothsaveANDkg-indexfor consistency. - ✅ Mood values:
happy|sad|excited|anxious|grateful|proud|reflective|neutral|work|curious - ❌ Do not add editorial comments — save raw information
Entry Splitting Strategy
SPLIT into multiple entries if ANY of these are true:
- ≥3 distinct topics (e.g. career + family + hobbies)
- ≥10 entities would be needed in
kg-index - ≥2 time phases with different contexts (e.g. "worked in Japan 5 years, then moved back")
- >300 words AND covers multiple topics
Keep as 1 entry if ALL of these are true:
- Single topic with single emotional arc
- <5 entities total
- Single time point or tight narrative
How to split: Group by phase → topic → emotion. Each entry should have 5–8 focused entities.
❌ BAD: 1 mega-entry (1500 words, 28 entities, 14 topics)
→ KG becomes tangled, search returns noise
✅ GOOD: 14 focused entries (~100-150 words, 5-8 entities each)
→ Clean KG, each entry is independently searchable
→ Use relationships to LINK entries across topics
6. kg-index — Index Entities & Relationships
After every save, you must: (1) disambiguate, (2) extract, (3) index.
Step 1 — Disambiguate: check existing entities
kioku-lite entities --limit 50
Compare extracted names against the returned list. Reuse existing canonical names instead of creating duplicates:
- If
"Phúc"exists with 12 mentions, use"Phúc"— not"anh Phúc"or"Nguyễn Trọng Phúc" - If
"TechBase Vietnam"exists, use it — not"TBV"or"công ty" - For true aliases, register them:
kioku-lite kg-alias "Phúc" --aliases '["anh Phúc","Nguyễn Trọng Phúc"]'
Step 2 — Extract entities & relationships from the saved text
Entity types (generic): PERSON | PROJECT | PLACE | TOOL | CONCEPT | ORGANIZATION | EVENT
Relationship types (generic): KNOWS | WORKS_ON | WORKS_AT | CONTRIBUTED_TO | USED_BY | LOCATED_AT | INVOLVES | MENTIONS
Profile-specific types: If a persona profile (companion/mentor) is active, use the entity & relationship types from that profile's SKILL.md INSTEAD of the generic ones above.
Extraction rules:
- ✅ Use short, canonical name form:
"Alice"not"my friend Alice" - ✅ Prefer proper names over generic labels:
"Phong"not"Con trai","Sato"not"manager". Generic labels makerecallfail. - ✅ Entity names in the user's original language — do NOT translate
- ✅
evidence= exact quote from the saved text that supports the relationship - ❌ Skip generic words:
"I","we","they","team","everyone" - ❌ Only add relationships explicitly stated in the text — do NOT infer
- ✅ No specific entities → skip
kg-indexentirely
Step 3 — Call kg-index with --event-time
kioku-lite kg-index <content_hash> \
--entities '[{"name":"Alice","type":"PERSON"},{"name":"Project X","type":"PROJECT"}]' \
--relationships '[
{"source":"Alice","rel_type":"WORKS_ON","target":"Project X","evidence":"had a meeting with Alice about Project X"}
]' \
--event-time "2024-06-15"
--event-time is critical for temporal accuracy. It sets the date on graph edges.
Parse relative time expressions to YYYY-MM-DD relative to today's date:
| Expression | Today = 2026-03-03 | Result |
|---|---|---|
| "hôm qua" / "yesterday" | 2026-03-02 |
|
| "tuần trước" / "last week" | 2026-02-24 |
|
| "tháng 3 năm ngoái" / "last March" | 2025-03-01 |
|
| "năm 2019" / "in 2019" | 2019-01-01 |
|
| "lúc 22 tuổi" (user born 1993) | 2015-01-01 |
|
| Today or unclear | Omit --event-time (defaults to today) |
7. search — Enriched Search Workflow
Never call search with the raw user query. Always enrich first.
Step 1 — Analyze intent and enrich
| Signal | Action |
|---|---|
| Pronouns: "he", "she", "it" | Replace with entity name from context |
| Implicit subject: "the project" | Map to specific entity name |
| Temporal: "yesterday", "last month" | Add --from DATE --to DATE |
| Relational: "who does X work with?" | Use recall "X" or connect "X" "Y" |
| Thematic: general topic query | Use semantic search with domain keywords |
Step 2 — Extract entities and build enriched query
🚨 ALWAYS pass
--entitieswhen the query mentions or implies specific people, places, or topics. This activates the graph search backend — without it, only vector+BM25 are used and relationship-based results are lost.
How: Identify entity names from the user's question, match them against known entities (kioku-lite entities), and pass as --entities.
--entities rules (Task 2H):
- ✅ Pass 2–3 specific entities relevant to the topic (other people, places, organizations)
- ❌ Do NOT add the user's own name — it connects to everything, dilutes results, and is auto-excluded by the engine
- ❌ Do NOT pass a single entity — use
recall "Entity"instead for a more focused graph traversal
# Multi-topic: pass the relevant NON-user entities
kioku-lite search "công việc dạo này" --entities "Techbase,Brain,Sato" --limit 15
# ❌ Wrong: adding user name adds noise
kioku-lite search "..." --entities "Phúc,Techbase,Brain,Sato"
# Single entity → recall, not search
kioku-lite recall "Alice" --hops 2 --limit 15
# Connection between two entities
kioku-lite connect "Alice" "Bob"
# Temporal slice
kioku-lite search "events" --from 2026-02-01 --to 2026-02-28
# Recent timeline
kioku-lite timeline --limit 20
Step 3 — Interpret results
- Results contain
content_hash— can be used for additionalkg-indexif needed - 0 results → be honest, don't invent memories
- Low confidence (score < 0.02) → say "possibly related, but not certain"
8. Full Workflow Example
User: "Năm 2019, tôi quyết định quay lại đọc sách nghiêm túc."
─── Step 1: Save ───
kioku-lite save "Năm 2019, tôi quyết định quay lại đọc sách nghiêm túc." \
--mood reflective --event-time 2019-01-01
→ {"content_hash": "a1b2c3..."}
─── Step 2: Disambiguate ───
kioku-lite entities --limit 50
→ Check: "Phúc" exists (12 mentions) — reuse it
─── Step 3: Extract & Index ───
kioku-lite kg-index a1b2c3 \
--entities '[{"name":"Phúc","type":"PERSON"},{"name":"Đọc sách","type":"COPING_MECHANISM"},{"name":"Quyết định quay lại đọc sách","type":"LIFE_EVENT"}]' \
--relationships '[
{"source":"Phúc","rel_type":"TRIGGERED_BY","target":"Quyết định quay lại đọc sách","evidence":"quyết định quay lại đọc sách nghiêm túc"},
{"source":"Quyết định quay lại đọc sách","rel_type":"REDUCED_BY","target":"Đọc sách","evidence":"quay lại đọc sách nghiêm túc"}
]' \
--event-time 2019-01-01
8A. Temporal Facts Workflow (NEW)
Facts age. When a user's status changes (job, relationship, location), mark the old fact as superseded:
When to invalidate
- Job change: "I left LINE" → mark
WORKS_AT "LINE"with--date 2026-03-31 - Relationship: "We broke up" → mark relevant edges as obsolete
- Project completion: "We shipped it" → mark
WORKS_ONif active phase ended - Resolved issue: "Finally fixed the bug" → mark
BLOCKED_BYrelationship
Command
kioku-lite kg-invalidate --source "Phuc" --target "LINE" --rel-type WORKS_AT \
--date 2026-03-31 --reason "Changed jobs to Techbase"
Querying with temporal context
kioku-lite search "where does Phuc work?"
# Returns current job only (superseded edges excluded)
kioku-lite search "where does Phuc work?" --include-historical
# Returns ALL jobs (including LINE)
Rule: Always set --date to when the fact became obsolete, not today. This preserves accurate historical context.
8B. Consolidation Workflow (NEW)
Periodic maintenance: detect stale edges, old memories, and duplicates. Agent reviews and acts:
Step 1 — Run consolidation
kioku-lite consolidate --half-life 90 --older-than 30
Output: JSON report with 3 sections:
{
"decay": [
{"source":"Phuc","target":"Techbase","current_weight":0.25,"reason":"Not reinforced 120 days"}
],
"merge_suggestions": [
{"entity1":"Phuc","entity2":"Phúc","sim":0.99}
],
"stale_memories": [
{"hash":"abc123...","content":"...","last_updated":"2025-06-01"}
]
}
Step 2 — Agent reviews and acts
On decayed edges:
- If still relevant → reinforce via new
kg-indexwith same relationship - If obsolete →
kg-invalidateto supersede
On merge suggestions:
- Verify the pairs →
merge "Phuc" "Phúc"to consolidate - Or
dedup-scan --autoto merge all qualifying pairs at once
On stale memories:
- Summarize old entries into weekly/monthly recap
- Save recap with
save "Weekly summary: ..." --event-time 2025-12-31 - Delete originals if appropriate
Step 3 — Cleanup (optional)
# Auto-merge all detected duplicates
kioku-lite consolidate --auto-merge
# Or scan then auto-merge separately
kioku-lite dedup-scan --auto
Frequency: Run monthly or quarterly depending on memory growth (≥100 new edges/month).
8C. Entity Deduplication (NEW)
Agents may extract "Phuc" and "Phúc" as separate entities. Auto-dedup finds and merges them:
Scan for duplicates
kioku-lite dedup-scan
# Output: candidates with similarity scores
Automatic merge (recommended)
kioku-lite dedup-scan --auto
# Merges pairs where vector_sim ≥ 0.98 AND jaro_winkler ≥ 0.85
Manual merge (when auto is too strict)
kioku-lite merge "Phuc" "Phúc"
# source "Phuc" absorbed into target "Phúc"
# All edges re-pointed, "Phuc" added as alias
Rule: Dual-threshold (vector + name) prevents false merges. If merge fails, check name similarity manually.
8D. Cluster Analysis (NEW)
KGs fragment into communities (friend groups, work teams, interest clusters). View structure:
List all clusters
kioku-lite clusters
# Output: [{"label":"PERSON","entity_count":42}, {"label":"PROJECT","entity_count":8}, ...]
Inspect a cluster
kioku-lite cluster PERSON
# Shows all entities + connected memories in PERSON cluster
Use case
- Understand your KG structure (how many friend groups? work domains?)
- During consolidation, merge duplicates within clusters (more likely to be true duplicates)
- Identify isolated clusters that may need integration
12. Decision Tree
Session start?
└─ users → search to load context
User shares info / "remember this":
└─ Check splitting criteria → save (split if needed)
→ entities (disambiguate) → extract → kg-index each
User reports life change (job, breakup, move):
└─ kg-invalidate to mark old facts as obsolete
User asks a question:
└─ ENRICH query → search / recall / connect
└─ Use --entities for multi-hop PPR search
└─ Use --include-historical to include superseded facts
Periodic maintenance (monthly):
└─ consolidate → review decay/merge/stale → act
"What happened on [date]?":
└─ search --from DATE --to DATE
"Tell me about X":
└─ recall "X" --hops 2
"How are X and Y related?":
└─ connect "X" "Y"
Critical rules:
- 🚫 Never invent memories. 0 results → be honest.
- ✅ Always
savewhen user shares valuable information. - ✅ Always
kg-indexaftersaveif entities are present (with--event-time!). - ✅ Always disambiguate against existing entities before indexing.
- ✅ Always
kg-invalidatewhen facts become obsolete (job change, breakup, etc.). - ✅ Run
consolidatemonthly to surface stale edges and duplicates. - ✅ Enrich queries — replace pronouns with real entity names.
13. Config & Data Locations
~/.kioku-lite/
└── users/<user_id>/ ← default user_id = "personal"
├── memory/ # Markdown backup (source of truth)
└── data/
└── kioku.db # SQLite: FTS5 + sqlite-vec + KG tables + temporal + merge_log
Optional ~/.kioku-lite/config.env — only needed to change embedding provider or default user_id.
Per-project override: echo "KIOKU_LITE_USER_ID=project-x" > .env
14. Troubleshooting
| Issue | Solution |
|---|---|
kioku-lite: command not found |
pipx install "kioku-lite[cli]" or source .venv/bin/activate |
| Search is slow on first run (~5s) | Model warming up — faster afterward |
| Model download interrupted | Run kioku-lite setup again |
No module named sqlite_vec |
pip install --upgrade "kioku-lite[cli]" |
| Duplicate entities keep appearing | Run kioku-lite dedup-scan --auto to auto-merge |
| Search feels stale | Run kioku-lite consolidate to decay and reinforce edges |