Skip to main content

Persistent, queryable memory for AI coding agents

Project description

Enyal

Persistent, queryable memory for AI coding agents.

Enyal gives AI agents like Claude Code durable context that survives session restarts. Every conversation becomes accumulated institutional knowledge—facts, preferences, decisions, and conventions that persist and grow.

Features

  • Persistent Memory: Context survives restarts, crashes, and process termination
  • Semantic Search: Find relevant context using natural language queries (384-dim embeddings via all-MiniLM-L6-v2)
  • Hierarchical Scoping: Global → workspace → project → file context inheritance
  • Fully Offline: Zero network calls during operation
  • Cross-Platform: macOS (Intel + Apple Silicon) and Windows 10/11
  • MCP Compatible: Works with Claude Code, Cursor, Windsurf, Kiro, and any MCP client

Quick Start

Get up and running in under 2 minutes:

1. Install

pip install enyal

2. Configure Your IDE

Create a configuration file for your IDE (all use the same format):

Claude Code — Create .mcp.json in your project root:

{
  "mcpServers": {
    "enyal": {
      "command": "python",
      "args": ["-m", "enyal.mcp"]
    }
  }
}

3. Start Using

You: Remember that this project uses pytest for all testing
Assistant: [calls enyal_remember] ✓ Stored context about testing framework

You: What testing framework should I use?
Assistant: [calls enyal_recall] Based on the stored context, this project uses pytest for all testing.

Installation

# Using uv (recommended)
uv add enyal

# Using pip
pip install enyal

# Using pipx (CLI only)
pipx install enyal

MCP Integration

Enyal works with any MCP-compatible client. Configuration is similar across platforms—only the file location differs.

Claude Code

File locations:

  • Project: .mcp.json (in project root)
  • User: ~/.claude/.mcp.json

Configuration:

{
  "mcpServers": {
    "enyal": {
      "command": "python",
      "args": ["-m", "enyal.mcp"],
      "env": {
        "ENYAL_DB_PATH": "~/.enyal/context.db"
      }
    }
  }
}

CLI setup:

claude mcp add-json enyal '{"command":"python","args":["-m","enyal.mcp"]}'

Claude Desktop

File locations:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Configuration:

{
  "mcpServers": {
    "enyal": {
      "command": "python",
      "args": ["-m", "enyal.mcp"],
      "env": {
        "ENYAL_DB_PATH": "~/.enyal/context.db"
      }
    }
  }
}

Cursor

File locations:

  • Global: ~/.cursor/mcp.json
  • Project: .cursor/mcp.json

Configuration:

{
  "mcpServers": {
    "enyal": {
      "command": "python",
      "args": ["-m", "enyal.mcp"],
      "env": {
        "ENYAL_DB_PATH": "~/.enyal/context.db"
      }
    }
  }
}

UI setup: File → Preferences → Cursor Settings → MCP

Windsurf

File location: ~/.codeium/windsurf/mcp_config.json

Configuration:

{
  "mcpServers": {
    "enyal": {
      "command": "python",
      "args": ["-m", "enyal.mcp"],
      "env": {
        "ENYAL_DB_PATH": "~/.enyal/context.db"
      }
    }
  }
}

UI setup: Windsurf Settings → Cascade → MCP, or use the Plugin Store

Kiro

File locations:

  • Global: ~/.kiro/settings/mcp.json
  • Project: .kiro/settings/mcp.json

Configuration:

{
  "mcpServers": {
    "enyal": {
      "command": "python",
      "args": ["-m", "enyal.mcp"],
      "env": {
        "ENYAL_DB_PATH": "~/.enyal/context.db"
      },
      "autoApprove": ["enyal_recall", "enyal_stats", "enyal_get"]
    }
  }
}

UI setup: Click the Kiro ghost tab → MCP Servers → "+"

See docs/INTEGRATIONS.md for detailed platform-specific guides.

Available Tools

Tool Description
enyal_remember Store new context with metadata (facts, preferences, decisions, conventions, patterns)
enyal_recall Semantic search for relevant context with filtering by scope and type
enyal_forget Remove or deprecate context (soft-delete by default, hard-delete optional)
enyal_update Update existing entries (content, confidence, tags)
enyal_get Retrieve a specific entry by ID with full metadata
enyal_stats Get usage statistics and health metrics

Content Types

Type Use For Example
fact Objective information "The database uses PostgreSQL 15"
preference User/team preferences "Prefer tabs over spaces"
decision Recorded decisions "Chose React over Vue for frontend"
convention Coding standards "All API endpoints follow REST naming"
pattern Code patterns "Error handling uses Result<T, E> pattern"

Scope Levels

Scope Applies To Example Path
global All projects (none)
workspace Directory of projects /Users/dev/projects
project Single project /Users/dev/myproject
file Specific file /Users/dev/myproject/src/auth.py

CLI Usage

Enyal provides a command-line interface for direct interaction:

# Store context
enyal remember "Always use pytest for testing" --type convention --scope project

# Search context
enyal recall "testing framework" --limit 5

# Get entry details
enyal get <entry-id>

# View statistics
enyal stats

# Remove context
enyal forget <entry-id>

# Run MCP server
enyal serve --preload

Options:

  • --db PATH — Custom database path
  • --json — Output in JSON format

See docs/CLI.md for complete CLI reference.

Python Library

from enyal.core.store import ContextStore
from enyal.core.retrieval import RetrievalEngine
from enyal.models.context import ContextType, ScopeLevel

# Initialize store
store = ContextStore("~/.enyal/context.db")
retrieval = RetrievalEngine(store)

# Remember something
entry_id = store.remember(
    content="Always use pytest for testing in this project",
    content_type=ContextType.CONVENTION,
    scope_level=ScopeLevel.PROJECT,
    scope_path="/Users/dev/myproject",
    tags=["testing", "pytest"]
)

# Recall relevant context
results = retrieval.search(
    query="how should I write tests?",
    limit=5,
    min_confidence=0.5
)

for result in results:
    print(f"{result.score:.2f}: {result.entry.content}")

# Update context
store.update(entry_id, confidence=0.9, tags=["testing", "pytest", "unit-tests"])

# Get specific entry
entry = store.get(entry_id)

# Get statistics
stats = store.stats()
print(f"Total entries: {stats.total_entries}")

Configuration

Environment Variables

Variable Default Description
ENYAL_DB_PATH ~/.enyal/context.db Database file location
ENYAL_PRELOAD_MODEL false Pre-load embedding model at startup
ENYAL_LOG_LEVEL INFO Logging level (DEBUG, INFO, WARNING, ERROR)

Database Location

The default database is stored at ~/.enyal/context.db. This single SQLite file contains:

  • All context entries and metadata
  • Vector embeddings for semantic search
  • Full-text search index

Troubleshooting

MCP Server Not Connecting

  1. Verify Python path: Ensure python resolves to Python 3.11+

    python --version
    
  2. Check installation: Verify enyal is installed

    python -c "import enyal; print(enyal.__file__)"
    
  3. Enable debug logging:

    {
      "mcpServers": {
        "enyal": {
          "command": "python",
          "args": ["-m", "enyal.mcp"],
          "env": {
            "ENYAL_LOG_LEVEL": "DEBUG"
          }
        }
      }
    }
    
  4. Check server status:

    • Claude Code: /mcp command
    • Cursor: Settings → MCP → check status
    • Windsurf: Cascade → Plugins
    • Kiro: Ghost tab → MCP Servers

Slow First Query

The first query loads the embedding model (~80MB). This takes ~1-2 seconds. Subsequent queries are fast (~34ms).

To pre-load the model:

{
  "env": {
    "ENYAL_PRELOAD_MODEL": "true"
  }
}

Database Locked Error

If you see "database is locked" errors, ensure only one MCP server instance is running per database file. Use different ENYAL_DB_PATH values for different projects if needed.

Permission Errors

On macOS/Linux, ensure the database directory exists and is writable:

mkdir -p ~/.enyal
chmod 755 ~/.enyal

Architecture

Enyal uses a unified SQLite database with:

  • Relational storage for metadata and attributes
  • sqlite-vec for vector similarity search (384-dim embeddings)
  • FTS5 for keyword search
  • WAL mode for concurrent access

See docs/ARCHITECTURE.md for detailed design decisions.

Development

# Clone repository
git clone https://github.com/seancorkum/enyal.git
cd enyal

# Install with dev dependencies
uv sync --all-extras

# Run tests
uv run pytest

# Type checking
uv run mypy src/enyal

# Linting
uv run ruff check src/enyal

Performance

Benchmarked on Intel Mac with Python 3.12:

Metric Target (p95) Measured (p95) Status
Cold start (model load + first query) <2000ms ~1500ms
Warm query latency <50ms ~34ms
Write latency <50ms ~34ms
Concurrent reads (4 threads) <150ms ~85ms
Memory (100k entries estimated) <500MB ~35MB

Embedding model: all-MiniLM-L6-v2 (22M params, 384 dimensions)

Run benchmarks:

uv run python benchmarks/benchmark_performance.py

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

enyal-0.1.1.tar.gz (208.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

enyal-0.1.1-py3-none-any.whl (24.2 kB view details)

Uploaded Python 3

File details

Details for the file enyal-0.1.1.tar.gz.

File metadata

  • Download URL: enyal-0.1.1.tar.gz
  • Upload date:
  • Size: 208.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for enyal-0.1.1.tar.gz
Algorithm Hash digest
SHA256 f5e7d0dbd0a26018fc35af6ee0361f6d6d53d3a754a820831e5e8581a3956f94
MD5 1723997613c2e22d840783e2128ecfe7
BLAKE2b-256 d98eefb08759d98b495f70fbb53fdae0b86d12112e37ea4205ac503fa429ec5c

See more details on using hashes here.

Provenance

The following attestation bundles were made for enyal-0.1.1.tar.gz:

Publisher: publish.yml on S-Corkum/enyal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file enyal-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: enyal-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 24.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for enyal-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 08496d84b4320c9a27351905311f5441a69a62a9b6ad6aa21e960e3955c71b22
MD5 f13a4781202ae092505268b64f0f23a6
BLAKE2b-256 2b565ce4685da583008ed12b10e35435c7d0ce344ea838150afe02bf02a70eca

See more details on using hashes here.

Provenance

The following attestation bundles were made for enyal-0.1.1-py3-none-any.whl:

Publisher: publish.yml on S-Corkum/enyal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page