Skip to content

Project Structure

The AutoMem server repository follows a hybrid Python/Node.js structure with three primary deployment targets: the core Flask API service, the MCP bridge server, and operational scripts.

graph TB
    Root["automem/\nRepository Root"]

    subgraph "Python Source"
        AppPy["app.py\nThin Flask bootstrap"]
        ConsolPy["consolidation.py\nBackground workers"]

        Root --> AppPy
        Root --> ConsolPy
    end

    subgraph "Node.js Integration"
        MCPDir["mcp-sse-server/\nMCP bridge service"]
        MCPNode["node_modules/\n(ignored)"]

        Root --> MCPDir
        MCPDir --> MCPNode
    end

    subgraph "Scripts & Tools"
        ScriptsDir["scripts/\nOperational scripts"]
        BackupScript["backup_automem.py"]
        RecoverScript["recover_from_qdrant.py"]
        MonitorScript["health_monitor.py"]

        Root --> ScriptsDir
        ScriptsDir --> BackupScript
        ScriptsDir --> RecoverScript
        ScriptsDir --> MonitorScript
    end

    subgraph "Configuration"
        Env[".env\n(ignored, contains secrets)"]
        Requirements["requirements.txt\nrequirements-dev.txt"]
        Dockerfile["Dockerfile"]
        RailwayToml["railway.toml"]

        Root --> Requirements
        Root --> Dockerfile
        Root --> RailwayToml
    end

A small entry module that creates the Flask app, registers @app.before_request auth, and delegates startup to automem/runtime_wiring.py. All business logic, routes, workers, and configuration live in the automem/ package — not in app.py.

ResponsibilityImplementation
Service startup and wiringImports from automem/runtime_wiring.py
Flask app factoryDelegates to automem/api/ route modules
Background worker launchDelegates to worker modules in automem/
Configuration loadingautomem/config.py

The main package containing all business logic, organized by domain:

automem/
├── __init__.py
├── config.py # All configuration constants
├── service_state.py # ServiceState dataclass
├── service_runtime.py # Runtime initialization helpers
├── service_runtime_bindings.py
├── runtime_wiring.py # Server startup orchestration
├── runtime_environment.py
├── app_helper_bindings.py
├── api/
│ ├── memory.py # POST/GET/PATCH/DELETE /memory routes
│ ├── recall.py # GET /recall routes
│ ├── graph.py # Graph query routes
│ ├── admin.py # Admin operations
│ ├── health.py # Health endpoint
│ ├── enrichment.py # Enrichment status/reprocess
│ ├── consolidation.py # Consolidation trigger/status
│ ├── viewer.py # Graph viewer routes
│ ├── stream.py # SSE streaming
│ ├── auth_helpers.py # Authentication middleware
│ ├── runtime_bootstrap.py
│ ├── runtime_memory_routes.py
│ └── runtime_recall_routes.py
├── classification/
│ ├── __init__.py
│ └── memory_classifier.py
├── consolidation/
│ ├── runtime_bindings.py
│ ├── runtime_helpers.py
│ ├── runtime_routes.py
│ └── runtime_scheduler.py
├── embedding/
│ ├── provider.py # Base provider class
│ ├── provider_init.py # Auto-selection logic
│ ├── openai.py
│ ├── voyage.py
│ ├── fastembed.py
│ ├── ollama.py
│ ├── placeholder.py
│ ├── runtime_pipeline.py
│ ├── runtime_bindings.py
│ └── runtime_helpers.py
├── enrichment/
│ ├── runtime_bindings.py
│ ├── runtime_helpers.py
│ ├── runtime_orchestration.py
│ ├── runtime_queue_bindings.py
│ └── runtime_worker.py
├── search/
│ ├── runtime_recall_helpers.py
│ ├── runtime_relations.py
│ └── runtime_keywords.py
├── stores/
│ ├── graph_store.py
│ ├── vector_store.py
│ └── runtime_clients.py
├── sync/
│ ├── runtime_bindings.py
│ └── runtime_worker.py
├── analytics/
│ └── runtime_helpers.py
└── utils/
├── entity_extraction.py
├── scoring.py
├── tags.py
├── time.py
├── text.py
├── graph.py
└── validation.py

consolidation.py — Dream-Inspired Maintenance

Section titled “consolidation.py — Dream-Inspired Maintenance”

Self-contained consolidation engine with no Flask dependencies. Designed for both scheduled background execution and manual CLI invocation.

ClassPurposeKey Methods
MemoryConsolidatorExecute consolidation tasksconsolidate(), calculate_relevance_score(), discover_creative_associations(), cluster_similar_memories(), apply_controlled_forgetting()
ConsolidationSchedulerManage task intervalsrun_scheduled_tasks(), should_run(), get_next_runs()
GraphLike (Protocol)Database abstractionquery() method only
VectorStoreProtocol (Protocol)Vector store abstractiondelete() method only

Caching optimization: Relationship count queries use @lru_cache with hourly invalidation (consolidation.py:201-216).

Translates Model Context Protocol (MCP) tool calls into AutoMem REST API requests. Enables ChatGPT, ElevenLabs, and other SSE-compatible AI platforms to access AutoMem.

  • Port: 8080 (configurable via PORT environment variable)
  • Connects to Flask API at AUTOMEM_URL (default: http://localhost:8001)
  • Key files: server.js (SSE endpoint handlers, JSON-RPC to REST translation), package.json

Production-ready Python scripts for data protection and disaster recovery.

ScriptPurposeDependencies
backup_automem.pyExport FalkorDB + Qdrant to S3/localboto3, falkordb, qdrant-client
recover_from_qdrant.pyRebuild FalkorDB graph from Qdrant payloadsfalkordb, qdrant-client
restore_from_backup.pyRestore from compressed JSON backupsfalkordb, qdrant-client
health_monitor.pyDetect count drift between databasesrequests, optional webhook client

All scripts connect directly to FalkorDB and Qdrant, bypassing the Flask API. They read the same environment variables as app.py. The backup_automem.py script runs every 6 hours via a GitHub Actions workflow.

Environment Variable Load Order (automem/config.py)

Section titled “Environment Variable Load Order (automem/config.py)”

automem/config.py calls load_dotenv twice and never sets override=True, so a value that is already set is never replaced. In order of precedence, highest first:

  1. Variables already in the process environment, for example secrets that Railway injects
  2. The project .env, loaded first by load_dotenv() with no path (in a normal, non-interactive run python-dotenv searches upward from the automem/ package directory)
  3. ~/.config/automem/.env, loaded second; it only fills in variables that are still unset
CategoryExample VariablesDefined In
Database ConnectionsFALKORDB_HOST, QDRANT_URLautomem/config.py
AuthenticationAUTOMEM_API_TOKEN, ADMIN_API_TOKENautomem/config.py
Consolidation IntervalsCONSOLIDATION_DECAY_INTERVAL_SECONDSautomem/config.py
Enrichment TuningENRICHMENT_MAX_ATTEMPTS, ENRICHMENT_SIMILARITY_THRESHOLDautomem/config.py
Embedding BatchingEMBEDDING_BATCH_SIZE, EMBEDDING_BATCH_TIMEOUT_SECONDSautomem/config.py
Search WeightsSEARCH_WEIGHT_VECTOR, SEARCH_WEIGHT_KEYWORDautomem/config.py
FilePurposeKey Settings
DockerfileContainer image definitionPython 3.11, installs spaCy model
docker-compose.ymlLocal development stackOrchestrates Flask + FalkorDB + Qdrant
railway.jsonRailway deployment configService definitions, port mappings

Docker Compose services:

  • flask-api: Flask API (port 8001)
  • falkordb: Graph database (port 6379)
  • qdrant: Vector database (port 6333)

The test suite covers consolidation, API endpoints, enrichment, embedding providers, and integration flows:

tests/
├── conftest.py
├── test_consolidation_engine.py
├── test_api_endpoints.py
├── test_app.py
├── test_enrichment.py
├── test_embedding_providers.py
├── test_integration.py
├── test_content_size.py
├── test_vector_size_safety.py
├── test_recall_entity_extraction.py
├── support/
├── contracts/
└── benchmarks/

Tests use pytest markers to separate execution tiers: unit (no external services, runs with make test, which then runs the MCP bridge’s Node tests through make test-node), integration (requires Docker stack, runs with make test-integration), and live (runs against a deployed Railway instance).

Mock objects (defined in tests/test_consolidation_engine.py and tests/support/):

Test philosophy: Consolidation tests use deterministic mocks and frozen time to ensure reproducible relevance score calculations.

PatternPurposeExamples
*.pyPython modulesapp.py, consolidation.py
test_*.pyPytest test filestest_consolidation_engine.py
*_automem.pyOperational scriptsbackup_automem.py, restore_from_backup.py
*.mdMarkdown documentationREADME.md, OPTIMIZATIONS.md
*.shShell scriptstest-optimizations.sh
.envEnvironment configuration.env, ~/.config/automem/.env
*.ymlYAML configurationdocker-compose.yml

Gitignored patterns: __pycache__/, venv/, .venv/, backups/, node_modules/, .env

Different deployment scenarios use different subsets of the repository:

  1. Railway (Production): Single container running app.py (which imports the automem/ package), consolidation runs in background thread
  2. Docker Compose (Local): Multi-container with separate database services
  3. Bare Metal (Development): Python process + external databases
  4. MCP Bridge: Optional Node.js service for AI platform integration
  5. Scripts: Standalone utilities connecting directly to databases

The mcp-automem package uses a TypeScript project structure with distinct directories for source code, templates, build artifacts, and configuration files.

This is a selected layout, not an exhaustive listing. src/ and src/cli/ contain further helper modules, and templates/ also holds shared root-level files.

graph TB
    ROOT["."]

    ROOT --> SRC["src/"]
    ROOT --> TEMPLATES["templates/"]
    ROOT --> PLUGINS["plugins/"]
    ROOT --> DIST["dist/"]
    ROOT --> GITHUB[".github/"]
    ROOT --> HUSKY[".husky/"]

    SRC --> INDEX["index.ts\n(MCP server entry point)"]
    SRC --> CLIENT["automem-client.ts\n(HTTP client)"]
    SRC --> TYPES["types.ts\n(TypeScript interfaces)"]
    SRC --> CLI["cli/"]

    CLI --> SETUP["setup.ts"]
    CLI --> INSTALL["install.ts"]
    CLI --> CLIENTS["clients.ts"]
    CLI --> CLAUDECODE["claude-code.ts"]
    CLI --> CURSOR["cursor.ts"]
    CLI --> CODEX["codex.ts"]
    CLI --> COPILOT["copilot.ts"]
    CLI --> HERMES["hermes.ts"]
    CLI --> GROK["grok.ts"]
    CLI --> OPENCLAW["openclaw.ts"]
    CLI --> QUEUE["queue.ts"]
    CLI --> MIGRATE["migrate.ts"]
    CLI --> UNINSTALL["uninstall.ts"]
    CLI --> CLOUD["cloud/"]

    TEMPLATES --> TCCLI["claude-code/\nhooks, settings"]
    TEMPLATES --> TCUR["cursor/\n.mdc rule template, user rules"]
    TEMPLATES --> TCODEX["codex/\nconfig.toml, memory-rules.md"]
    TEMPLATES --> TCOPILOT["copilot/\ninstructions, hooks, profiles, scripts"]
    TEMPLATES --> THERMES["hermes/\nmemory-rules.md, provider/"]
    TEMPLATES --> TGROK["grok/\nconfig.toml, memory-rules.md"]
    TEMPLATES --> TOCLAW["openclaw/\nSKILL.md variants, setup guide"]
    TEMPLATES --> TANTI["antigravity/\nmcp_config.json"]

    PLUGINS --> PAUTOMEM["automem/"]
    PAUTOMEM --> PCCLI[".claude-plugin/\nplugin.json"]
    PAUTOMEM --> PCOMMANDS["commands/"]
    PAUTOMEM --> PHOOKS["hooks/"]
    PAUTOMEM --> PSCRIPTS["scripts/"]
    PAUTOMEM --> PSKILLS["skills/\nmemory-management/"]
    ROOT --> ROOTPLUGIN[".claude-plugin/\nmarketplace.json"]

    GITHUB --> WORKFLOWS["workflows/\nCI/CD YAML files"]

    DIST --> DISTJS["*.js\n(Compiled code)"]
    DIST --> DISTDTS["*.d.ts\n(Type definitions)"]
    DIST --> DISTMAP["*.js.map\n(Source maps)"]

The src/index.ts file serves dual purposes based on command-line arguments:

  1. Server Mode (no arguments): Launches an MCP server using StdioServerTransport from @modelcontextprotocol/sdk
  2. CLI Mode (with arguments): Routes commands to appropriate CLI handlers in src/cli/

The src/automem-client.ts file implements the AutoMemClient class, providing a typed HTTP interface to the AutoMem backend service.

MethodHTTP EndpointPurpose
storeMemory()POST /memoryStore new memory with content, tags, metadata
recallMemory()GET /recall, or GET /memory/by-tag internally when called with tags + exhaustive: trueHybrid search (vector + keyword + tags), or tag-only filtering
associateMemories()POST /associateCreate typed relationships
updateMemory()PATCH /memory/:idUpdate existing memory fields
deleteMemory()DELETE /memory/:idRemove memory and embedding
checkHealth()GET /healthDatabase connectivity status

Configuration resolution (priority order):

  1. Constructor parameters (if provided)
  2. Environment variables (AUTOMEM_API_URL, AUTOMEM_API_KEY) — AUTOMEM_ENDPOINT is accepted as a deprecated alias for AUTOMEM_API_URL
  3. .env file (loaded via dotenv)

The src/types.ts file defines the client’s shared TypeScript types:

  • Configuration types: AutoMemConfig
  • Memory operation arguments: StoreMemoryArgs, RecallMemoryArgs, AssociateMemoryArgs, UpdateMemoryArgs, DeleteMemoryArgs
  • API response types: RecallResult, StoreMemoryResult, AssociateMemoryResult, DeleteMemoryResult, HealthStatus
  • Value types: MemoryType, RelationType

Each CLI command is implemented as a separate module with a main run*() function. CLI handlers follow a consistent pattern: --dry-run flag for safe preview, template rendering from templates/ directory, filesystem operations with error handling, and user-friendly output with next-step instructions.

The templates/ directory contains platform-specific integration files that are copied to user systems during installation. These files are included in the published npm package.

Selected layout of templates/ (not exhaustive: the root-level Markdown files are omitted, and the contents of the copilot/ subdirectories and hermes/provider/ are summarized):

templates/
├── antigravity/
│ └── mcp_config.json
├── claude-code/
│ ├── hooks/ # Shell scripts triggered by Claude events
│ │ ├── automem-session-start.sh # SessionStart recall
│ │ ├── automem-track-store.sh # PostToolUse store tracking
│ │ └── automem-stop-nudge.sh # Optional Stop nudge (--profile nudged)
│ ├── settings.json # Base hook configuration (default silent profile)
│ └── settings.stop-nudge.json # Adds Stop nudge hook registration
├── codex/
│ ├── config.toml
│ └── memory-rules.md
├── copilot/
│ ├── automem.instructions.md
│ ├── hooks/ # JSON hook definitions
│ ├── profiles/ # full.json, lean.json
│ └── scripts/ # .sh and .ps1 hook scripts
├── cursor/
│ ├── automem.mdc.template # Cursor rule template
│ ├── rule-evals.md
│ └── user-rules.md
├── grok/
│ ├── config.toml
│ └── memory-rules.md
├── hermes/
│ ├── memory-rules.md
│ └── provider/ # Python provider files and plugin.yaml
├── openclaw/
│ ├── OPENCLAW_SETUP.md
│ ├── skill/ # SKILL.md
│ ├── skill-legacy/ # SKILL.md
│ └── skill-mcp/ # SKILL.md
├── claude_desktop_config.json
└── cursor_mcp.json

Template file types:

TypeExtensionPurposeTarget Platform
Hook Scripts.sh, .ps1Event-driven automationClaude Code (.sh), Copilot (.sh, .ps1)
Rule Files.md, .mdc.templateAI assistant instructionsClaude Code, Claude Desktop, Cursor, Codex, Copilot, Grok, Hermes, OpenClaw
Config Snippets.json, .tomlMCP server configurationClaude Desktop, Cursor, Antigravity, Codex, Grok
Settings.jsonHook permissions & matchersClaude Code

The dist/ directory is generated by TypeScript compilation (tsc) and contains:

  1. JavaScript files (.js) — Compiled from TypeScript source
  2. Type declarations (.d.ts) — For TypeScript consumers
  3. Source maps (.js.map) — For debugging compiled code

TypeScript configuration (tsconfig.json):

  • outDir: "dist" — Output location
  • declaration: true — Generate .d.ts files
  • sourceMap: true — Generate source maps
  • module: "NodeNext" — Node.js module format; package.json sets "type": "module", so the output is ES modules
  • target: "ES2022" — JavaScript target version

Build scripts:

ScriptCommandPurpose
prebuildnode scripts/sync-template-versions.mjsSync template versions before compile
buildtscCompile TypeScript source
postbuildnode scripts/build-openclaw-plugin-package.mjs && chmod +x dist/index.jsPackage OpenClaw plugin + make executable
devtsx watch src/index.tsHot-reload development
typechecktsc --noEmitValidate types without building

plugins/automem/ packages AutoMem as an installable Claude Code plugin: .claude-plugin/plugin.json (plugin manifest), plus commands/, hooks/, scripts/, and skills/memory-management/. A separate top-level .claude-plugin/marketplace.json registers the plugin in the Claude Code plugin marketplace. There is no server/ subdirectory — this is a Claude Code plugin bundle, not a packaged MCP server.

The repository root contains multiple configuration files:

FilePurpose
package.jsonnpm scripts, dependencies, package metadata
tsconfig.jsonTypeScript compiler options
eslint.config.mjsESLint flat config (ESLint 9+)
.commitlintrc.cjsConventional commit message validation
.prettierrcCode formatting rules
release-please-config.jsonAutomated release configuration
.release-please-manifest.jsonCurrent version tracking
env.exampleTemplate for required environment variables

Five files must maintain version consistency (managed by release-please):

  1. package.json — e.g. "version": "0.16.0" (at mcp-automem 0.16.0)
  2. server.json (repo root) — same version string
  3. manifest.json — same version string
  4. plugins/automem/.claude-plugin/plugin.json — same version string
  5. .claude-plugin/marketplace.json — same version string

The release-please.yml workflow automatically updates all five files when creating releases based on conventional commits.

WorkflowTriggerPurpose
ci.ymlPR, push to mainLint, build, test, coverage
security.ymlPR, push, scheduleCodeQL, npm audit
release-please.ymlPush to mainVersion bump, changelog, publish
semantic-pr-title.ymlPR open/editValidate PR title format

The .husky/commit-msg hook runs commitlint to validate commit messages against Conventional Commits format before allowing the commit.

Accepted types: fix, feat, chore, docs, refactor, test, ci, build, perf, revert

The files array in package.json specifies what gets included in the npm package:

What’s included: dist/, templates/, plugins/, env.example, README.md, CHANGELOG.md

What’s excluded: Source code (src/), tests, development configs, CI/CD files, .tsbuildinfo

TaskFiles to Modify
Add a new MCP toolsrc/index.ts (schema + handler), src/automem-client.ts (client method), src/types.ts
Add a new CLI commandCreate src/cli/new-command.ts, import and route in src/index.ts
Modify platform integrationEdit templates/<platform>/, update src/cli/<platform>.ts, sync to plugins/
Change build outputModify tsconfig.json, update package.json main and types fields
Add release automationEdit .github/workflows/release-please.yml, update .release-please-manifest.json