Welcome back! In the previous chapter, Configuration Registry, we created a "Menu" of all possible settings. We established what can be changed.
Now, we need to decide where those changes live.
Imagine you are a contractor working at different office buildings. You have two types of items:
In ConfigTool, we face the exact same situation:
This is the Dual-Layer Storage Strategy.
We distinguish between these two layers using a property called source.
global~/.config/claude/config.json).settings./.claude.json).
Remember the SUPPORTED_SETTINGS object from Chapter 1? That object acts as a traffic controller. When you try to save a setting, the code looks at the source property to decide which file to write to.
Here is how we define the theme. Since you want your theme to follow you, we mark it as global.
// inside supportedSettings.ts
theme: {
source: 'global', // <--- The "Backpack"
type: 'string',
description: 'Color theme for the UI',
options: ['dark', 'light'],
},
Here is autoMemoryEnabled. We might want Memory turned on for a complex project, but off for a simple scratchpad.
// inside supportedSettings.ts
autoMemoryEnabled: {
source: 'settings', // <--- The "Filing Cabinet"
type: 'boolean',
description: 'Enable auto-memory',
},
When the ConfigTool runs, it performs a lookup to decide how to handle data.
When the tool needs to know the current value of a setting, it calls a helper function. This function checks the source and routes the request.
// Simplified logic from ConfigTool.ts
function getValue(source: 'global' | 'settings', path: string[]) {
// 1. If it's global, open the "Backpack"
if (source === 'global') {
return getGlobalConfig()[path[0]]
}
// 2. Otherwise, open the "Filing Cabinet" (Project settings)
return getProjectSettings()[path[0]]
}
Explanation: The code literally switches logic branches based on the source string defined in the registry.
Writing is slightly more critical because we don't want to accidentally save project secrets into your global config file.
// Inside ConfigTool.ts -> call() method
if (config.source === 'global') {
// Save to the user's global file
saveGlobalConfig(prev => ({ ...prev, [key]: newValue }))
} else {
// Save to the project-specific file
updateSettingsForSource('userSettings', { [key]: newValue })
}
Explanation: We use different saving functions (saveGlobalConfig vs updateSettingsForSource) to ensure the data lands in the correct physical file on the hard drive.
Here is what happens when a user tries to change a setting. Note how the Registry directs the traffic to the correct storage.
Sometimes, settings are grouped together, like permissions.defaultMode.
The storage strategy handles this by using Paths. A key like permissions.defaultMode isn't just one simple label; it tells the system to look inside a folder named permissions for a file named defaultMode.
// Helper to read the path from the key
export function getPath(key: string): string[] {
const config = SUPPORTED_SETTINGS[key]
// Returns ['permissions', 'defaultMode']
return config?.path ?? key.split('.')
}
Why this matters: This allows us to organize the "Filing Cabinet" neatly, rather than throwing every single document into one big pile.
The Dual-Layer Storage Strategy ensures that ConfigTool is smart about context. It prevents your personal preferences from cluttering up shared project files, and it keeps project-specific rules from messing up your other work.
source).Now that we have a Menu (Registry) and a Kitchen (Storage), we need a Chef to actually cook the meal. In the next chapter, we will examine the main engine that processes user commands.
Next Chapter: Tool Execution Logic
Generated by Code IQ