Metadata-Version: 2.4
Name: kairos-memory
Version: 1.0.1
Summary: Graph-Based Persistent Memory for AI Agents
Author-email: Anjang Kusuma Netra <medtosys@gmail.com>
License: BSL-1.1
Project-URL: Homepage, https://github.com/mlengse/kairos
Project-URL: Repository, https://github.com/mlengse/kairos
Keywords: ai,memory,knowledge-graph,mcp,agent
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: LICENSE-AGPL-3.0.txt
License-File: LICENSE-POLYFORM-NC-1.0.0.md
License-File: NOTICE
Requires-Dist: numpy>=1.24.0
Provides-Extra: portalocker
Requires-Dist: portalocker>=3.2.0; extra == "portalocker"
Provides-Extra: embed
Requires-Dist: fastembed>=0.3.0; extra == "embed"
Provides-Extra: embed-server
Requires-Dist: sentence-transformers; extra == "embed-server"
Requires-Dist: torch; extra == "embed-server"
Provides-Extra: redis
Requires-Dist: redis>=7.1.0; extra == "redis"
Provides-Extra: dream
Requires-Dist: networkx; extra == "dream"
Provides-Extra: llm
Requires-Dist: httpx; extra == "llm"
Requires-Dist: PyYAML>=5.1; extra == "llm"
Provides-Extra: dashboard
Requires-Dist: fastapi; extra == "dashboard"
Requires-Dist: uvicorn; extra == "dashboard"
Provides-Extra: metadata
Requires-Dist: google-cloud-bigquery; extra == "metadata"
Requires-Dist: sqlglot; extra == "metadata"
Requires-Dist: pandas; extra == "metadata"
Requires-Dist: pyyaml; extra == "metadata"
Provides-Extra: all
Requires-Dist: akar>=0.1.4; extra == "all"
Requires-Dist: fastembed>=0.3.0; extra == "all"
Requires-Dist: redis>=7.1.0; extra == "all"
Requires-Dist: networkx; extra == "all"
Requires-Dist: httpx; extra == "all"
Requires-Dist: PyYAML>=5.1; extra == "all"
Dynamic: license-file

# Kairos — Graph-Based Persistent Memory for AI Agents

> **Your agents die every conversation. Kairos keeps them alive.**

The persistent layer your LLMs run on top of. Memory formation, not retrieval.
Background consolidation while they sleep. Conflict supersession when your mind changes.
A knowledge-graph filesystem your agent walks instead of searches.

---

## What this is

Most AI "memory" systems are retrieval wrappers.

They store chunks. Embed text. Run cosine similarity. Return vaguely related paragraphs.

Kairos is built around a different thesis:

> **Memory is not retrieval. Memory is formation, consolidation, synthesis, and evolving structure.**

The engine continuously transforms raw conversations into a living cognitive graph, backed by **Akar** (pure-Rust embedded graph database, drop-in replacement for KuzuDB):

- atomic facts,
- semantic links,
- supersession chains,
- synthesized abstractions,
- bridge memories,
- latent preference structures,
- temporal trajectories.

It does this locally.
It works as a Hermes **MemoryProvider adapter plugin** (daemon-first).
It survives across sessions.

---

## Architecture — Daemon-First + Hermes Adapter

Kairos runs in **daemon-first mode**: a single `akar_server` process holds the exclusive graph DB lock on `vela.db` (directory format). All clients — Hermes plugin, MCP server, CLI, tests — connect via TCP loopback (JSON IPC) to this daemon. The graph backend is **Akar** (pure Rust, `import kuzu` aliased to `import akar` via `kairos/kuzu.py`).

```
┌─────────────────────────────────────────────────────────────────────┐
│                        HERMES AGENT PROCESS                          │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ NeuralMemoryProvider (kairos/plugin.py)                      │   │
│  │   • MemoryProvider ABC: initialize / prefetch / sync_turn     │   │
│  │   • get_tool_schemas() → mcp_schemas.ALL_TOOL_SCHEMAS         │   │
│  │   • handle_tool_call() → _HANDLERS dict → engine methods      │   │
│  │   • 3 thread pools: _recall_pool(2) / _write_pool(1) /        │   │
│  │     _dream_pool(1) — prevent graph DB ContextVar contamination │   │
│  │   • DreamLeader (kairos/dream_leader.py): single cross-proc   │   │
│  │     leader via advisory lock on vela.db.dream.leader.lock     │   │
│  └──────────────────────────┬────────────────────────────────────┘   │
│                             │ TCP loopback :<random-port> (JSON IPC)   │
└─────────────────────────────┼────────────────────────────────────────┘
                              ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    KUZU_DAEMON PROCESS (1 per DB)                    │
│  • ThreadingTCPServer on 127.0.0.1:<random-port>                    │
│  • Owns single GraphStore + exclusive file lock (vela.db.daemon.lock)│
│  • Serialised writes (GraphStore._write_lock), concurrent reads     │
│  • Idle self-shutdown after KAIROS_KUZU_DAEMON_IDLE (default 86400s)  │
│  • Ops: execute / ping / flush / shutdown / stat / export           │
│  • Announces via sidecar: vela.db.daemon.json {port, token, pid}    │
└─────────────────────────────────────────────────────────────────────┘
                              │
                              ▼
                       vela.db/ (Akar graph directory, ~46 MB)
                         ├── data.kz           (46,352 KB) — graph data
                         ├── .wal              (115 KB)    — write-ahead log
                         ├── catalog.kz        (13 KB)     — schema metadata
                         ├── metadata.kz       (22 KB)     — storage metadata
                         ├── n-*.hindex        (~20 KB ea) — vector indexes
                         ├── .lock                          — graph DB internal lock
                         └── .shadow                        — recovery shadow
                       vela.db.daemon.json     — sidecar (host, port, token, pid)
                       vela.db.daemon.lock     — OS-level exclusive lock (msvcrt.locking)
                       vela.db.daemon.log      — daemon stdout/stderr
```

### Two Deployment Modes

| Mode | Who uses it | DB lock holder | Selected by |
|------|-------------|----------------|-------------|
| **daemon** (default for Hermes) | Hermes plugin, MCP server, CLI | Shared `akar_server` process | `KAIROS_KUZU_MODE=daemon` (forced by `plugin.py`) |
| **embedded** (explicit opt-in) | Standalone `from kairos import Kairos` | The engine's own process | `KAIROS_KUZU_MODE=embedded` (never automatic) |

> **Decided direction:** Daemon mode is the **single operational path** for multi-session Hermes. Embedded remains only as explicit opt-in for tests/CI/true single-process standalone. Automatic embedded/SQLite fallbacks **have been removed** for the daemon/kuzudb path — failures fail loud.

### Thread Pools (in Hermes plugin process)

| Pool | Threads | Used by |
|------|---------|---------|
| `_recall_pool` | 2 | recall, think, reasoning, graph, health, metadata, profile(get) |
| `_write_pool` | 1 | remember, protect, profile(set), backup, import, sync |
| `_dream_pool` | 1 | dream_control, dream_config, dream_nrem/rem/insight/afe/synthesis/dae |

Total: **4 threads** — one per pool.

### Cache

diskcache-only (Redis removed per architectural decision):

| Domain | TTL | Contents |
|--------|-----|----------|
| `recall` | 300s | Recall result cache |
| `dream` | 3600s | Dream queue + status |
| `session` | 3600s | Session buffers |

---

## Quick Start

### Via Hermes (Recommended)

```bash
# 1. Install Kairos package
pip install -e .

# 2. Deploy Hermes adapter plugin (one-time)
.\tools\deploy-kairos-provider.ps1

# 3. Configure Hermes
hermes memory setup kairos
# → prompts: db_path (default: ~/.kairos/engine/vela.db)
# → prompts: embedding_backend (auto/hash/tfidf/sentence-transformers)

# 4. Verify
hermes config get memory
# → provider: kairos
hermes kairos status
# → Backend: akar, Memories: 2895, Connections: 21, ...
```

### Standalone (Single-Process)

```bash
# Explicit embedded mode (opt-in)
KAIROS_KUZU_MODE=embedded python -c "
from kairos import Kairos
mem = Kairos()
mem.remember('The user has a dog named Lou')
results = mem.recall('What pet does the user have?')
mem.think(results[0].id)
"
```

---

## Features

### 🧠 Core Memory
| Function | Description |
|:---------|:------------|
| `remember()` | Store a fact with embedding + auto-connection to related memories |
| `recall()` | Multi-channel recall (semantic, graph, temporal, FTS) |
| `think()` | Spreading activation — explore connected memories |
| `graph()` | Connection graph summary |

### 🌙 Dream Engine (Background Consolidation)
Runs in the **leader session's** `_dream_pool`; auto-triggers on idle/new-memory thresholds (`idle=300s`, `memory_threshold=50` — source: `dream_engine.py`).

| Phase | What it does | Notes / caveats |
|:------|:-------------|-----------------|
| **NREM** | Replay & strengthen active edges, prune weak (`<0.05`) | Batch writes chunked (see §9.1) |
| **Supersedes** | Directed "older→newer" edge for value-changed facts | Only pairs with numeric tokens **and** differing tokens **and** cosine ≥ 0.85 (hardcoded, `dream_engine.py:1310`). Does **not** dedup exact duplicates. |
| **REM** | Bridge discovery for isolated memories | Up to `max_isolated` |
| **Insight** | Louvain community detection → `derived:cluster` nodes | |
| **AFE** | Atomic Fact Extraction: Stage A/B = **regex** (`afe.py`), Stage C = LLM user-state (`KAIROS_AFE_LLM_FALLBACK=1`) | Stage A/B have no LLM prompt; fragment quality governed by regex filters |
| **Synthesis** | Stage S crystallization, grouped by source memory | LLM mode via `KAIROS_SYNTHESIS_LLM=1` |
| **DAE** | Graph-weighted second embedding recompute | Every N NREM cycles; batch chunked |

### 🔧 Tools (MemoryProvider)
Kairos registers 38+ tools via Hermes MemoryProvider:
`kairos_remember`, `kairos_recall`, `kairos_think`, `kairos_graph`, `kairos_reasoning`, `kairos_profile`, `kairos_dream_*`, metadata catalog tools, and more.

### 📊 Metadata Catalog
Semantic search over database schemas, tables, columns, and business terms — imported from BigQuery, SQL databases, or YAML definitions.

---

## Dream Engine Auto-Trigger

Dream daemon runs automatically as background thread in the leader session. Auto-trigger based on:

- `idle_threshold` — seconds without activity before trigger (default: **300**, from `dream_engine.py`)
- `memory_threshold` — new memories before trigger (default: **50**, from `dream_engine.py`)

Configure via `kairos_dream_config()`:

```python
kairos_dream_config(action="set", idle_threshold=7200, memory_threshold=10)
```

**No cron job, no SSE server, no external process.** Single daemon holds the lock; all sessions share it.

---

 ## Storage Backends

| Backend | Type | Status |
|:--------|:-----|:-------|
| **Akar** | Embedded graph (pure Rust; `import kuzu` → `import akar`) | **The only backend** — graph + vector index |

> SQLite and PostgreSQL/Supabase were **removed** (2026-08-21). In daemon
> mode, graph DB failure **fails loud** — no silent fallback to an empty store.

---

## Project Structure

```
kairos/
├── kairos/                        # Python package utama
│   ├── plugin.py                  # NeuralMemoryProvider — Hermes adapter (daemon mode)
│   ├── __init__.py                # Re-export ringan (Kairos, Memory, NeuralMemoryProvider)
│   ├── engine.py                  # Kairos API — unified entry point
│   ├── cache.py                  # Cache via diskcache (Redis dihapus — diskcache only)
│   ├── disk_fallback.py           # DiskCacheDomain wrapper
│   ├── mcp_schemas.py             # Tool schemas — single source of truth
│   ├── kuzu_client.py             # KuzuClientStore + daemon IPC (daemon mode)
│   ├── kuzu_ipc.py                # JSON framing (u32-LE length prefix)
│   ├── kuzu.py                    # Shim: `import kuzu` → `import akar`
│   ├── akar_store.py              # GraphStore (Akar) embedded mode
│   ├── dream_engine.py            # 7-phase dream consolidation
│   ├── dream_akar_store.py        # Akar dream backend
│   ├── dream_leader.py            # Cross-process leader election (advisory lock)
│   ├── config.py                  # Config helpers
│   ├── afe.py                     # Atomic Fact Extraction
│   ├── dae.py                     # Dream-Augmented Embeddings
│   ├── synthesis.py               # LLM synthesis (reasoning)
│   ├── profile_extractor.py       # User profile management
│   ├── sync_store.py              # Cross-backend sync
│   ├── embed_provider.py          # Embedding backends
│   └── ...                        # Other support files
├── hermes-plugin/                 # Hermes skin plugin (TUI display) — NOT memory provider
│   ├── __init__.py                # import + register dari kairos.plugin
│   ├── plugin.yaml                # Plugin manifest (name: kairos)
│   └── neural_skin.yaml           # Hermes UI skin
├── docs/                          # Documentation
│   ├── ARCHITECTURE.md            # Canonical architecture (this is the source of truth)
│   └── references/                # Historical/reference notes
├── tools/
│   ├── deploy-kairos-provider.ps1 # One-command Hermes adapter deployment
│   └── kairos_doctor.py           # Read-only triage: sidecar, daemon, locks, backups
├── tests/
│   └── test_suite.py              # Test suite
└── pyproject.toml                 # Package metadata + dependencies
```

---

## Hermes Adapter Plugin

The **memory provider adapter** lives at `$HERMES_HOME/plugins/kairos/` (NOT under `plugins/memory/`):

```
$HERMES_HOME/plugins/kairos/
├── __init__.py          # Thin entry: from kairos.plugin import NeuralMemoryProvider; register()
├── plugin.yaml          # Metadata + pip_dependencies: [kairos-memory]
└── cli.py               # CLI: hermes kairos status|stats|dream
```

### Deployment

```powershell
# One-command deploy (installs package, creates adapter, cleans legacy)
.\tools\deploy-kairos-provider.ps1
```

### CLI Commands

```bash
hermes kairos status          # Engine summary (backend, memories, connections, embedding, dream phase)
hermes kairos stats [--pretty|--no-pretty]  # Full JSON engine stats
hermes kairos dream status|pause|resume|force-nrem|force-rem  # Dream Engine control
```

All CLI commands use **daemon RPC** (via `kuzu_ipc`) — they never spawn an engine or touch the DB directly.

### Desktop UI Config

Kairos appears in Hermes Desktop → Settings → Memory Provider with fields:
- `db_path` (text, default: `~/.kairos/engine/vela.db`)
- `embedding_backend` (select: `auto`, `hash`, `tfidf`, `sentence-transformers`)

---

## MCP Server (stdio)

Separate stdio MCP server at `kairos_mcp_stdio.py` — runs as independent process, also uses daemon mode:

```python
# kairos_mcp_stdio.py initialize():
os.environ["KAIROS_KUZU_MODE"] = "daemon"
os.environ["KAIROS_NO_FALLBACK"] = "1"
```

Tools exposed: `kairos_remember`, `kairos_recall`, `kairos_think`, `kairos_graph`, `kairos_reasoning`, `kairos_profile`, `kairos_dream_*`, metadata catalog tools.

> **Backup:** Supabase/Postgres sync removed (2026-08-21). For version-safe
> backup use `kairos_backup_local` (daemon `EXPORT DATABASE` op) — see
> `docs/ARCHITECTURE.md` §8.

---

## Observability & Troubleshooting

### Health Check

```bash
# Via tool (plugin)
kairos_health
# → {status, backend, memories, connections, embedding_dim, storage: {daemon_pid, sidecar_age, ...}}

# Via CLI (daemon RPC)
hermes kairos stats
```

### Daemon Status

```powershell
# Cek proses daemon
Get-CimInstance Win32_Process -Filter "Name LIKE 'akar_server%'"

# Cek sidecar
Get-Content "$env:USERPROFILE\.kairos\engine\vela.db.daemon.json" | ConvertFrom-Json

# Cek log daemon
Get-Content "$env:USERPROFILE\.kairos\engine\vela.db.daemon.log" -Tail 50
```

### Doctor Script (Comprehensive Triage)

```bash
python tools/kairos_doctor.py
# → healthy  OR  "1 issue(s) found: UNREACHABLE/STALE/LOCK_HELD"
```

Checks: sidecar liveness, daemon reachability, spawn/leader locks, backup freshness.

### Common Issues

| Symptom | Cause | Fix |
|---------|-------|-----|
| `memories: 0` but DB 40MB | graph DB version mismatch | Use logical export/import; check `kairos_doctor.py` |
| `Could not set lock on file` | Stale lock / zombie daemon | `Remove-Item vela.db.daemon.lock -Force`; kill zombie python; restart |
| `hermes kairos status` → 0 memories | DB path not configured correctly | Check `~/.hermes/config.yaml` → `memory.kairos.db_path` |
| Dream not running | Leader election stuck | Check `vela.db.dream.leader.lock`; `kairos_dream_control resume` |

---

## License

**Business Source License 1.1** — [View License](LICENSE)

- Non-commercial use: free
- Commercial use: requires a paid license
- After 2030-01-01: automatically converts to Apache 2.0

---

## Forks & Attribution

Kairos was forked from [Mazemaker](https://github.com/nousresearch/mazemaker) and evolved independently with:

- Akar (pure Rust) as the primary backend (embedded, no Docker)
- Complete Dream Backend for all store types
- **Daemon-first architecture** — single `akar_server` holds exclusive lock
- Hermes MemoryProvider **adapter plugin** (thin, imports from package)
- Auto-trigger dream daemon (no cron job)
- **Storage hardening**: bounded retries, no silent fallbacks, backup-as-daemon-op, WAL crash fix, observability (`stat` op, `kairos_health` storage section, `kairos_doctor`)
- Cleaned architecture, no license gates

Built with ❤️ for the Indonesian AI ecosystem.
