Project-Scoped vs Global Configuration in oh-my-claudecode: Precedence Rules Explained
Project-scoped configuration in oh-my-claudecode takes precedence over global user settings, while environment variables override both file-based configurations according to the merge logic in src/config/loader.ts.
Understanding how oh-my-claudecode resolves conflicting settings between your global preferences and project-specific requirements is essential for effective CLI workflow management. This open-source tool loads configuration from multiple sources and resolves them through a deterministic merge strategy defined in the TypeScript source code.
Configuration Sources and File Locations
oh-my-claudecode recognizes three distinct configuration sources, each targeting different scopes of operation. The system identifies these locations through the getConfigPaths() utility and loads them sequentially.
- Global User Config: Stored at
<user-config-dir>/claude-omc/config.jsonc(typically~/.config/claude-omc/config.jsonc), this file contains your machine-wide default preferences. - Project Config: Located at
<cwd>/.claude/omc.jsoncrelative to your current working directory, this file defines repository-specific overrides. - Environment Variables: Any variable prefixed with
OMC_that maps to a configuration key, providing temporary, session-based overrides.
The Configuration Precedence Hierarchy
The resolution follows a cascading override pattern where later sources overwrite earlier ones. As implemented in the loadConfig() function within src/config/loader.ts, the effective precedence from highest to lowest is:
- Environment variables
- Project-scoped configuration (
.claude/omc.jsonc) - Global user configuration (
~/.config/claude-omc/config.jsonc) - Built-in defaults
Built-in Defaults (Base Layer)
The loader initializes every configuration object using buildDefaultConfig(), which establishes safe fallback values for all settings. These defaults persist unless explicitly overridden by higher-precedence sources.
Global User Configuration
The global config file applies across all projects on your machine. During initialization, the loader calls loadJsoncFile(paths.user) to parse this file and merges it into the defaults using deepMerge().
Project-Scoped Configuration
Settings defined in ./.claude/omc.jsonc take precedence over matching keys in your global configuration. The loader executes deepMerge(config, projectConfig) after processing the user config, ensuring project-specific requirements override personal defaults.
Environment Variables (Highest Precedence)
Variables such as OMC_PARALLEL_EXECUTION trump both configuration files. The loadEnvConfig() function captures these values and performs a final deepMerge(), allowing temporary overrides without modifying files.
How the Merge Logic Works in src/config/loader.ts
The actual implementation in src/config/loader.ts demonstrates this precedence through an explicit four-step sequence:
// 1. defaults (already in `config`)
let config = buildDefaultConfig();
// 2. user (global) config – lower precedence
const userConfig = loadJsoncFile(paths.user);
if (userConfig) {
config = deepMerge(config, userConfig);
}
// 3. project config – *higher* precedence than user config
const projectConfig = loadJsoncFile(paths.project);
if (projectConfig) {
config = deepMerge(config, projectConfig);
}
// 4. environment variables – highest precedence
const envConfig = loadEnvConfig();
config = deepMerge(config, envConfig);
This sequential merging ensures that each layer can only override what came before it, never reverting to defaults unless explicitly undefined in the new layer.
Practical Configuration Examples
Project Settings Overriding Global Preferences
Consider a scenario where you disable parallel execution globally but enable it for a specific repository:
// ~/.config/claude-omc/config.jsonc
{
"features": {
"parallelExecution": false
}
}
// ./.claude/omc.jsonc (project-scoped)
{
"features": {
"parallelExecution": true
}
}
When loadConfig() executes, the project file's true value replaces the global false setting.
Environment Variables Overriding Files
To temporarily disable the feature regardless of file configurations:
export OMC_PARALLEL_EXECUTION=false
This environment variable forces the setting to false, overriding both the project and global configurations.
Summary
- Project-scoped configuration in
.claude/omc.jsonctakes precedence over global user settings in~/.config/claude-omc/config.jsonc. - Environment variables with the
OMC_prefix override all file-based configurations. - The merge logic in
src/config/loader.tsprocesses sources sequentially: defaults → global → project → environment. - Missing keys in higher-precedence sources fall back to values defined in lower-precedence layers.
Frequently Asked Questions
Can I disable project-scoped configuration entirely?
No, the loader always checks for ./.claude/omc.jsonc if it exists in your current working directory. However, you can prevent overrides by ensuring the project file contains only empty objects or keys you don't mind being overridden.
What happens if the project config file is malformed?
If loadJsoncFile(paths.project) encounters invalid JSONC syntax, the loader typically skips that layer and falls back to the global user configuration or defaults, depending on the error handling implemented in src/utils/jsonc.ts.
Do environment variables support nested configuration keys?
Yes, variables like OMC_FEATURES_PARALLEL_EXECUTION map to nested objects (features.parallelExecution) during the loadEnvConfig() processing, allowing you to override deeply nested settings without creating config files.
Where does oh-my-claudecode store its built-in defaults?
The default configuration values are defined in the buildDefaultConfig() function within src/config/loader.ts, supplemented by model defaults in src/config/models.ts.
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 →