Welcome back!
In Chapter 3: Installation Orchestrator, we acted as a "Shopping Assistant," gathering all the necessary dependencies and downloading files.
However, just having files on a hard drive isn't enough. Imagine a library where books are thrown randomly into a pile. You wouldn't know what you have, where it is, or if you have the latest edition.
We need a Librarian. In our system, this is the Installation Registry.
The Registry is the source of truth for what exists physically on your computer. It manages the inventory list (installed_plugins.json) so the system never has to guess where a plugin lives.
This is the most important concept in this chapter. There is a difference between "having" a tool and "using" it.
installedPluginsManager.tsinstalled_plugins.jsonclaude.json or settings.jsonWhy separate them? Imagine you are working on 5 different coding projects. You don't want to download the "Calculator" plugin 5 separate times.
installed_plugins.json
The Registry maintains a JSON file that acts as the "Master Inventory List." It is usually located at ~/.claude/plugins/installed_plugins.json.
Here is what it looks like (simplified):
{
"version": 2,
"plugins": {
"weather-checker@official": [
{
"scope": "user",
"version": "1.0.0",
"installPath": "/Users/me/.claude/plugins/cache/official/weather-checker/1.0.0",
"installedAt": "2023-10-27T10:00:00Z"
}
]
}
}
Beginner Explanation:
weather-checker@official).user means it's global, project means it's local to one folder).The rest of the system asks the Registry questions to avoid searching the hard drive manually.
Before downloading a plugin, the Orchestrator asks the Registry if we already have it.
// installedPluginsManager.ts (Simplified)
export function isPluginInstalled(pluginId: string): boolean {
// 1. Load the big JSON file
const data = loadInstalledPluginsV2();
// 2. Check if the ID exists in the list
const installations = data.plugins[pluginId];
// 3. Return true if we found it
return installations && installations.length > 0;
}
When the system needs to run the plugin, it asks for the path.
// installedPluginsManager.ts (Simplified)
export function getPluginPath(pluginId: string) {
const data = loadInstalledPluginsV2();
// Get the first valid installation entry
const entry = data.plugins[pluginId][0];
return entry.installPath;
// Returns: "/Users/me/.claude/plugins/cache/..."
}
How does the Registry manage this file safely? We use the installedPluginsManager.ts module.
When we modify the registry, we don't want to corrupt the file.
Here is how the code actually writes to the inventory list. Note how we handle the "V2" format, which allows lists of installations.
// installedPluginsManager.ts (Simplified)
export function addPluginInstallation(pluginId, scope, installPath, metadata) {
// 1. Load current data
const data = loadInstalledPluginsFromDisk();
// 2. Create the new entry object
const newEntry = {
scope: scope,
installPath: installPath,
version: metadata.version,
installedAt: new Date().toISOString()
};
// 3. Update the list for this specific plugin ID
const list = data.plugins[pluginId] || [];
list.push(newEntry);
data.plugins[pluginId] = list;
// 4. Save to disk
saveInstalledPluginsV2(data);
}
The Registry doesn't just track any folder. It enforces a strict structure for where files live. This is handled by pluginDirectories.ts and pluginVersioning.ts.
We organize plugins by Marketplace -> Plugin Name -> Version.
~/.claude/plugins/
โโโ installed_plugins.json <-- The Inventory List
โโโ cache/ <-- The Physical Storage
โโโ official/ <-- Marketplace
โโโ weather-checker/ <-- Plugin Name
โโโ 1.0.0/ <-- Version 1 Code
โโโ 1.0.1/ <-- Version 2 Code
This structure allows us to have Version 1.0.0 and Version 1.0.1 installed at the same time!
How do we know a folder is "1.0.0"? Ideally, the plugin.json tells us. If not, we might use a Git Commit Hash.
// pluginVersioning.ts (Simplified)
export async function calculatePluginVersion(manifest, installPath) {
// 1. Prefer explicit version in plugin.json
if (manifest.version) {
return manifest.version;
}
// 2. Fallback: Use Git Commit Hash (e.g., "a1b2c3d")
const sha = await getGitCommitSha(installPath);
if (sha) {
return sha.substring(0, 12);
}
return 'unknown';
}
You might see references to "V1" and "V2" in the code.
The Registry automatically upgrades old files to the new format when the system starts.
// installedPluginsManager.ts (Simplified)
export function migrateToSinglePluginFile() {
// If we find an old V1 file...
if (isV1Format(file)) {
// ...convert it to the new structure...
const v2Data = convertV1ToV2(file);
// ...and save it back.
saveInstalledPluginsV2(v2Data);
}
}
This ensures that users never lose their installed plugins when the software updates.
In this chapter, we learned about the Installation Registry, the librarian of our system.
installed_plugins.json) of everything on the disk..../plugin/version/).Now we have the plugin identity, we've downloaded it, and we've registered it in our inventory. The files are ready. But files don't do anything on their own. We need to load them into memory and connect them to the AI.
Next Chapter: Component Integration Layers
Generated by Code IQ