Unified second brain for AI agents โ 5-tier memory, HRR reasoning, 22 MCP tools, temporal queries, per-fact versioning, vector search
Project description
๐ง Eling
Unified second brain for AI agents โ 5-tier memory, HRR reasoning, 22 MCP tools, temporal queries, per-fact versioning, vector search, Zettelkasten linking, memory evolution, spec-kit verification, conditional verify-on-stop
"Eling" (Javanese): to remember, to be conscious, to be aware
โจ What is Eling?
Eling is a unified second brain for AI agents. It merges 5 memory tiers into one MCP server โ no external databases, no cloud services needed for local operation.
๐ง Tier 5: NOTION โ online brain, human-readable (optional)
๐ Tier 4: KB โ FTS5 knowledge corpus
๐ธ๏ธ Tier 3: CODE โ codegraph symbol intelligence
๐ Tier 2: FACTS โ SQLite + HRR + BM25 hybrid with trust scoring
๐ Tier 1: BUILTIN โ Hermes MEMORY.md / USER.md
All accessible via 22 MCP tools from a single stdio server:
| Tool | Purpose |
|---|---|
eling_remember |
Store content โ auto-routes to facts (short) or KB (long) |
eling_recall |
Cross-layer search with RRF fusion (BM25 + trigram + porter) |
eling_reason |
Compositional query tying multiple entities together |
eling_probe |
Get all facts about an entity |
eling_reflect |
Promote a high-trust fact to Notion as a permanent page |
eling_sync |
Bidirectional sync between memory layers |
eling_stats |
Show per-layer statistics |
eling_think |
Synthesis + gap analysis across layers |
eling_export |
Full brain export as JSON or Markdown |
eling_verify |
Query/record verification status with optional spec-kit check |
eling_verify_spec |
Run spec-kit conformance verification against project specs |
eling_link_stats |
Zettelkasten link graph statistics |
eling_linked_facts |
Get facts linked to a given fact_id |
eling_evolve |
Trigger memory evolution (merge near-duplicates) |
eling_snapshot |
Snapshot the facts database before destructive operations |
eling_list_snapshots |
List all available snapshots |
eling_rollback |
Rollback facts database to a named snapshot |
eling_search_temporal |
Search facts by time range โ "last 3 days", "kemarin" |
eling_versioned_update |
Update a fact with append-only versioning |
eling_get_version_history |
Get all versions of a fact |
eling_undo_to_version |
Rollback a fact to a previous version |
eling_versioning_stats |
Versioning statistics across the fact store |
๐ Quick Start
pip install eling
# Run MCP server (stdio โ plug into any MCP host)
python3 -m eling.mcp_server
# Or use the CLI
python3 -m eling --help
# If using OpenCode, install the lifecycle plugin:
eling-install-opencode
๐ Agent Integration
| Agent | Integration | Status |
|---|---|---|
| Hermes | MCP server + Memory Provider + Plugin | โ Tested |
| OpenCode | MCP server + Lifecycle Plugin | โ Tested |
| Others (OpenClaw, Cursor, Windsurf, Claude Code) | MCP server only | โ ๏ธ MCP only |
Non-tested agents connect exclusively via the stdio MCP server (python3 -m eling.mcp_server) โ any MCP-compatible host can use all 22 tools.
Hermes
Eling plugs into Hermes Agent at 3 levels:
1. MCP Server โ add to ~/.hermes/config.yaml:
mcp_servers:
eling:
command: python3
args: ["-m", "eling.mcp_server"]
enabled: true
2. Memory Provider โ sets default brain for remember/recall:
memory:
provider: eling
3. Plugin โ registers eling_remember + eling_recall as quick tools:
plugins:
enabled:
- eling
eling:
home: /root/.eling
OpenCode
Eling provides an OpenCode lifecycle plugin that auto-writes session memory:
# After installing eling, run this to install the plugin:
eling-install-opencode
# Or:
python3 -m eling install-opencode
This copies eling-memory.js to OpenCode's plugin directory and registers it in opencode.jsonc. The plugin hooks into:
chat.messageโ stores user prompts as factstool.execute.afterโ stores tool observations as factsevent(session.idle / session.compacted) โ pushes high-trust facts to Notion
The eling MCP server should also be configured in OpenCode (opencode.jsonc):
"mcp": {
"eling": {
"type": "local",
"command": ["python3", "-m", "eling.mcp_server"],
"enabled": true
}
}
๐ CLI Commands
python3 -m eling remember "I learned that..."
python3 -m eling recall "what did I learn about X"
python3 -m eling probe "X"
python3 -m eling reason ["X", "Y"]
python3 -m eling reflect 1 # promote fact_id 1 to Notion
python3 -m eling verify # query verification status
python3 -m eling verify-spec # run spec-kit conformance
# Memory version control (v0.5.1)
python3 -m eling snapshot --reason "pre_evolution" # snapshot facts DB
python3 -m eling list-snapshots # list all snapshots
python3 -m eling rollback <snapshot_id> # restore to snapshot
# Zettelkasten linking + evolution
python3 -m eling link-stats # link graph stats
python3 -m eling linked-facts 1 # facts linked to fact_id 1
python3 -m eling evolve # merge near-duplicate facts
python3 -m eling stats
python3 -m eling export --format markdown
python3 -m eling sync --direction push # facts โ Notion
# Agent integration
python3 -m eling install-opencode # install OpenCode lifecycle plugin
python3 -m eling init-rules # write steering rules for AI agents
# Temporal search (v0.6.0)
python3 -m eling search-temporal "last 3 days" --category testing
python3 -m eling search-temporal "kemarin" # Indonesian language support
# Per-fact versioning (v0.6.0)
python3 -m eling versioned-update 1 "Updated content" --reason "correction"
python3 -m eling version-history 1
python3 -m eling undo-to-version 1 --version-id 0
python3 -m eling versioning-stats
๐ Notion Setup (Tier 5)
Optional โ skip this if you only need local memory.
-
Create a Notion integration at https://www.notion.so/my-integrations
- Give it a name (e.g. "Eling Brain")
- Copy the Internal Integration Secret (starts with
ntn_)
-
Share a parent page with your integration
- Open the page you want as your second brain root
- Click Share โ Invite โ select your integration
- Copy the page URL and extract the page ID (the UUID in the URL, e.g.
38f7b66e-c7e0-813f-85b0-d37cef59c1f7)
-
Set environment variables:
export NOTION_API_KEY="ntn_..."
export NOTION_PARENT_PAGE_ID="38f7b66e-c7e0-813f-85b0-d37cef59c1f7"
Note-taking behavior
Once configured, eling auto-creates a ๐ Task Logs child page under your parent on first use:
๐ Hermes Vault (parent page โ your configured root)
โโโ ๐ Task Logs โ auto-created by eling
โ โโโ ๐ก Eling test โ child pages from eling_reflect / remember(layer="notion")
โ โโโ ๐ก Another note
โโโ ๐ API Keys...
โโโ ...
Two ways to add notes to Notion:
| Method | Usage | Route |
|---|---|---|
brain.reflect(fact_id) / eling_reflect |
Promote a high-trust fact to Notion | โ auto-routes by category |
brain.remember("text", layer="notion") / eling_remember with layer=notion |
Store content directly as a Notion page | โ auto-routes by category |
Auto-routing by category
Content is automatically detected and routed to the right child page:
| Category | Triggers | Child page |
|---|---|---|
project_summary |
"project done/complete/selesai", "deploy success", "summary completion" | ๐ฏ Project Summaries |
credential |
"api_key", "password", "secret", "token", "credential" | ๐ Credentials |
address |
"alamat", "address", "domicile", "tinggal di" | ๐ Addresses |
config |
"config", "setup", "setting", "environment" | โ๏ธ Configurations |
| (uncategorised) | Everything else | ๐ Task Logs |
Example:
# Auto-routes to ๐ฏ Project Summaries
b.remember("Project done, deployed to production", layer="notion")
# Auto-routes to ๐ Credentials
b.remember("DATABASE_URL = postgres://...", layer="notion")
# Auto-routes to ๐ Task Logs (no pattern match)
b.remember("General note", layer="notion")
All child pages under these category pages are full Notion pages โ you can edit, move, share, or reference them normally.
Or pass them explicitly in code:
from eling.brain import Brain
b = Brain(
notion_api_key="ntn_...",
notion_parent_id="38f7b66e-..."
)
result = b.reflect(fact_id=1)
print(result) # {"page_id": "...", "promoted": True}
# Or store directly as a note
result = b.remember("Quick note for Notion", layer="notion")
print(result) # {"layer": "notion", "page_id": "...", ...}
Note:
eling_reflectandremember(layer="notion")check availability at call time and return a clear error if any config is missing โ no silent failures.
๐ Temporal Search & Per-Fact Versioning (v0.6.0)
Eling v0.6.0 introduces time-aware fact retrieval and append-only per-fact versioning โ never lose a piece of knowledge again.
Temporal Search
Query facts by time range using natural language โ English or Indonesian:
python3 -m eling search-temporal "last 3 days"
python3 -m eling search-temporal "this week"
python3 -m eling search-temporal "kemarin" # Indonesian: yesterday
python3 -m eling search-temporal "hari ini" # today
Supported patterns:
| Language | Examples |
|---|---|
| ๐ฌ๐ง English | today, yesterday, this week, last month, last 3 days, last 7 days, last 30 days |
| ๐ฎ๐ฉ Indonesian | hari ini, kemarin, minggu ini, bulan lalu, 3 hari terakhir, 7 hari terakhir, 30 hari terakhir |
Python API:
from eling.brain import Brain
b = Brain()
# Temporal search - English
results = b.search_temporal("last 3 days", category="testing")
# Indonesian
results = b.search_temporal("kemarin")
# All facts in a time window
results = b.search_temporal("", since_days=7)
Per-Fact Versioning
Every fact update is append-only โ old versions are preserved in a fact_versions table:
# Update a fact โ previous content is versioned
result = b.versioned_update(1, "Newer content", reason="corrected typo")
# โ {"fact_id": 1, "version_id": 2, "previous": "Old content", "new": "Newer content"}
# Get version history
history = b.get_version_history(1)
# โ [{"version_id": 0, "content": "Original...", "changed_at": "...", "reason": "initial"},
# {"version_id": 1, "content": "Updated...", "changed_at": "...", "reason": "corrected typo"}]
# Undo to a specific version (also versioned!)
result = b.undo_to_version(1, version_id=0)
# โ {"fact_id": 1, "version_id": 3, "restored_from": 0}
# Versioning stats
stats = b.versioning_stats()
# โ {"versioned_facts": 42, "total_versions": 156, "version_operations": 114}
Available as MCP tools: eling_versioned_update, eling_get_version_history, eling_undo_to_version, eling_versioning_stats.
๐ง Memory Version Control (v0.5.1)
Eling provides Git-like snapshot and rollback for your facts database:
# Before destructive ops, create a snapshot
python3 -m eling snapshot --reason "pre_evolution"
# List available snapshots
python3 -m eling list-snapshots
# Rollback to a previous state (auto-backups current DB first)
python3 -m eling rollback 20260703-120000-123
Snapshots are file-level copies managed via snapshot.py. Available as MCP tools: eling_snapshot, eling_list_snapshots, eling_rollback.
๐ฏ Steering Rules (v0.5.1)
Teach your AI agent when to use eling's MCP tools. Auto-detects Cursor, Claude Code, OpenCode, Kiro, and Gemini:
cd your-project
python3 -m eling init-rules
This writes:
- Cursor:
.cursor/rules/eling-memory-*.mdc - Claude Code:
.claude/rules/eling-memory-*.md - OpenCode: Appends to
AGENTS.md - Generic:
ELING_MEMORY.mdin project root
Rules cover: when to store/retrieve memories, session lifecycle, and memory hygiene.
๐ Vector Embeddings (v0.5.1)
Optional semantic search via sentence-transformers:
pip install eling[embeddings]
# or
pip install eling[all]
Enable when creating a Brain or set ELING_EMBEDDING_MODEL:
from eling.brain import Brain
b = Brain(embedding_model="all-MiniLM-L6-v2")
Hybrid search ranking: BM25 + Jaccard + HRR + cosine similarity from embeddings. Stored in a separate fact_embeddings table.
๐ก๏ธ Verify-on-Stop (Conditional)
Eling provides verify-on-stop nudges for AI agents that lack built-in
verification (e.g., OpenCode, OpenClaw, Cursor, Windsurf). When running under
Hermes, this feature automatically skips โ because Hermes already has its
own agent/verification_stop.py.
How it works
- Auto-detection โ Eling detects the host agent from the MCP client's
initializehandshake (clientInfo.name), which is more reliable than environment variable heuristics (prevents false Hermes detection when OpenCode runs under Hermes) - File edit tracking โ When code files are edited via hooks or MCP tools, eling records them in a verification ledger
- Spec-kit conformance โ If the project has spec-kit artifacts
(
specs/*/spec.md), eling checks whether code changes cover each spec requirement and includes gaps in the nudge - Verification nudge โ If code was edited but no passing tests/verification
was recorded, eling produces a
[System: ...]nudge message - Recording โ Agents can call
eling_verifyMCP tool to record verification results (passed,failed,skipped)
Spec-kit Verification
Projects using spec-kit (Spec-Driven Development) get automatic spec conformance checking:
- Eling detects
specs/<feature>/spec.md,plan.md, andtasks.mdartifacts - Requirements are extracted from spec markdown and matched against code files
- The
eling_verify_spectool returns coverage stats + uncovered requirements - The standard
eling_verifytool includes spec-kit results whenspec_check=true - Uncovered requirements are listed in the verification nudge for the agent to address
Usage via MCP
// Query current status
{ "method": "tools/call", "params": { "name": "eling_verify", "arguments": {} } }
// Record a passing verification
{ "method": "tools/call", "params": {
"name": "eling_verify",
"arguments": { "status": "passed", "command": "pytest", "output": "364 passed" }
} }
// Run spec-kit conformance check
{ "method": "tools/call", "params": {
"name": "eling_verify_spec",
"arguments": { "changed_files": ["src/main.py"] }
} }
// Combine both: verify + spec-kit
{ "method": "tools/call", "params": {
"name": "eling_verify",
"arguments": { "spec_check": true }
} }
Config
| Key | Default | Env | Description |
|---|---|---|---|
verify_on_stop |
true |
ELING_VERIFY_ON_STOP |
Enable nudges for non-Hermes agents |
verify_on_stop_max_attempts |
2 |
ELING_VERIFY_MAX_ATTEMPTS |
Max nudges per session |
adapter |
hermes |
ELING_ADAPTER |
Force adapter type |
plugins:
eling:
adapter: auto # auto-detect from env
verify_on_stop: true
๐๏ธ Architecture
eling/
โโโ mcp_server.py โ JSON-RPC stdio server (22 tools)
โโโ brain.py โ Orchestrator: routing + RRF fusion + sync + linking
โโโ config.py โ Layered config: env โ json โ defaults
โโโ hooks.py โ 15 lifecycle hooks + HookRegistry + evolution
โโโ verify_on_stop.py โ Verification ledger + nudge builder + spec-kit wiring
โโโ spec_kit.py โ Spec-kit artifact parser + coverage analyzer
โโโ privacy.py โ PII/secret stripping (19 patterns)
โโโ compress.py โ SHA-256 dedup + length compression
โโโ cli.py โ CLI client for all 22 operations
โโโ layers/
โโโ builtin.py โ Tier 1: Hermes MEMORY.md / USER.md loader
โโโ facts.py โ Tier 2: SQLite + HRR + BM25 + trust + linking + evolution
โโโ hrr.py โ Holographic Reduced Representations (optional numpy)
โโโ code.py โ Tier 3: CodeLayer wrapper
โโโ code_index.py โ Pure-Python AST+regex code indexer
โโโ kb.py โ Tier 4: FTS5 + porter + trigram + RRF
โโโ notion.py โ Tier 5: httpx Notion API client (lazy import)
โก Performance
- Lazy imports โ numpy and httpx are imported only when their layer is first used, not at module load time
import elingtakes ~1.3s (was ~4.5s with module-level imports on Alpine)- Pure-Python fallback when numpy unavailable (BM25-only retrieval still works)
๐ Documentation
๐ค Credits
- HRR phase encoding + facts layer โ adapted from holographic plugin by dusterbloom (Hermes PR #2351, MIT)
- Spec-kit integration โ spec-driven development artifacts (spec-kit by GitHub, MIT)
๐ License
MIT ยฉ 2026 PatrickNoFilter
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file eling-0.6.0.tar.gz.
File metadata
- Download URL: eling-0.6.0.tar.gz
- Upload date:
- Size: 122.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
917f797542f9ce35eb3e696fed1b4b9461c2c5b422d24e4d353b1320fa80a0f7
|
|
| MD5 |
6c03add67faa5351163abafddb0da0d3
|
|
| BLAKE2b-256 |
29e1790cbc793545d09a4c4c5728e96a9cdde7d450ee46f92592ae080c291f49
|
File details
Details for the file eling-0.6.0-py3-none-any.whl.
File metadata
- Download URL: eling-0.6.0-py3-none-any.whl
- Upload date:
- Size: 98.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
536ee53ab0f438d23f55104cb3283a3f6aa79b284ed2eec6f58f26ade39b5f8a
|
|
| MD5 |
5aec74cff95ce20dc4a62239db1f60c2
|
|
| BLAKE2b-256 |
67d86e43e402c357e0a4bfaaedbafcba8f9aefdcba69014023515f7d4f5be0e7
|