How ModeManager Loads and Applies Different Operational Modes in Claude-Mem
The ModeManager singleton discovers JSON mode definitions from the file system, resolves inheritance relationships using a parent--override syntax, and exposes the merged configuration to Claude-Mem agents for context-aware prompt generation.
Claude-Mem uses the ModeManager to switch between operational contexts such as code, email-investigation, or language-specific variants. Located in src/services/domain/ModeManager.ts, this singleton handles the full lifecycle of mode loading—from directory discovery and inheritance resolution to deep merging and runtime access.
Singleton Pattern and Mode Directory Discovery
Initializing the ModeManager Instance
The ModeManager follows the singleton pattern to ensure consistent state across the application. Calling ModeManager.getInstance() instantiates the manager if it does not exist, storing the instance in a private static variable. This guarantees that all agents and services reference the same active mode configuration throughout the session.
Locating the Modes Directory
During construction, the manager determines where mode JSON files reside by checking two possible paths: plugin/modes for production builds and ../plugin/modes for development checkouts. The first existing path is stored in this.modesDir, enabling the manager to locate profile definitions like code.json or email-investigation.json regardless of the execution environment.
Loading Operational Modes with Inheritance Support
Parsing Mode Inheritance Patterns
Claude-Mem supports mode inheritance through a double-dash syntax (parent--override). When loadMode(modeId) receives an identifier like code--es, the private parseInheritance method splits the string to detect whether a parent mode exists. This pattern allows developers to create specialized variants that extend base configurations without duplicating entire JSON files.
Handling Parent and Override Configurations
The loading sequence proceeds based on inheritance detection:
- No inheritance: If the mode ID contains no parent reference,
loadModeFilereads the corresponding JSON directly and assigns it toactiveMode. - Inheritance present: The manager recursively loads the parent mode first, then reads the override file. The two configurations are merged using
deepMerge, with override values taking precedence. The result becomes the newactiveMode.
Deep Merging Strategy
The private deepMerge method implements recursive object merging to combine parent and child configurations. When encountering plain objects, it merges keys recursively. For arrays and primitive values, the override completely replaces the parent value rather than attempting to concatenate or blend them. This strategy ensures predictable behavior when a specialized mode overrides specific observation types or prompt templates while inheriting the bulk of the base configuration.
Fallback Handling and Error Resilience
If loadMode cannot locate the requested JSON file, the manager logs a warning and automatically falls back to the default code mode. This resilience ensures that the system remains operational even when configuration files are missing or when an invalid mode identifier is passed via the CLAUDE_MEM_MODE environment variable.
Accessing Active Mode Configuration
Retrieving Mode Metadata
Once loaded, the active mode configuration is accessible through several getter methods. getActiveMode() returns the complete ModeConfig object, while getObservationTypes() and getObservationConcepts() provide convenient access to the arrays defining which observation types and semantic concepts are enabled for the current session.
Utility Methods for Observation Types
The manager exposes helper methods that translate observation type identifiers into UI assets and validation rules. Methods like getTypeIcon(), getWorkEmoji(), validateType(), and getTypeLabel() query the active mode configuration to provide context-specific metadata. These utilities ensure that agents and user interfaces present consistent terminology and visual indicators based on the operational mode.
Integration with Claude-Mem Agents
Worker Service Initialization
The integration point occurs during worker service startup in src/services/worker-service.ts. The service reads the CLAUDE_MEM_MODE environment variable (defaulting to code) and invokes ModeManager.getInstance().loadMode() to initialize the operational context. This single call configures the entire system before any agent processing begins.
Agent Prompt Construction
Every agent implementation—including SDKAgent, OpenRouterAgent, and GeminiAgent—retrieves the active mode via ModeManager.getInstance().getActiveMode() when constructing prompts. The mode configuration influences which observation types the agent should prioritize, which concepts to track, and which prompt templates to apply. This architecture ensures that switching from code mode to email-investigation mode automatically adjusts agent behavior without requiring code changes in the agent implementations themselves.
Summary
- ModeManager is a singleton that discovers mode JSON files from
plugin/modesor../plugin/modesdirectories. - It supports inheritance using the
parent--overridesyntax, merging configurations recursively viadeepMerge. - Missing mode files trigger an automatic fallback to the default
codemode with logged warnings. - The active mode exposes observation types, concepts, and UI metadata through getter methods like
getActiveMode()andgetObservationTypes(). - Worker service initialization loads the mode from the
CLAUDE_MEM_MODEenvironment variable, and all agents consume the configuration when building prompts.
Frequently Asked Questions
What is the default operational mode in Claude-Mem?
The default operational mode is code. If the CLAUDE_MEM_MODE environment variable is not set, or if the requested mode file cannot be found in the modes directory, the ModeManager automatically falls back to loading the code mode configuration.
How does ModeManager handle missing mode files?
When loadMode() cannot locate the requested JSON file, it logs a warning message and recursively calls itself with the default code mode identifier. This ensures the system remains operational even when configuration files are missing or corrupted, preventing startup failures due to invalid mode specifications.
Can I create custom operational modes with inheritance?
Yes, Claude-Mem supports custom modes through the inheritance pattern. Create a base mode JSON file (e.g., code.json) and an override file (e.g., code--custom.json). Use the double-dash syntax code--custom when loading, and the ModeManager will merge the parent configuration with your overrides using deep merging, allowing you to modify specific observation types or prompts while inheriting the base structure.
Which agents use the ModeManager configuration?
All agent implementations in Claude-Mem consume the ModeManager configuration, including SDKAgent (for Claude), OpenRouterAgent, and GeminiAgent. Each agent retrieves the active mode via ModeManager.getInstance().getActiveMode() during prompt construction to ensure consistent observation types, concepts, and prompt templates across different LLM providers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →