How to Enable and Configure Claude Code Plugins in Claudian: A Developer’s Guide
Claudian manages Claude Code plugins by reading the Claude CLI’s installed_plugins.json and settings.json files, then uses the PluginManager class to merge project and global configurations while persisting state changes via CCSettingsStorage.
Claudian is an Obsidian plugin that integrates Claude Code into your vault workflow, allowing you to leverage custom agents and extensions directly inside your notes. To activate these capabilities, you must enable and configure Claude Code plugins through Claudian’s settings interface or its programmatic API. This guide explains the discovery mechanism, state management logic, and exact source code paths—drawn from the YishenTu/claudian repository—that control plugin availability.
Where Claudian Discovers Claude Code Plugins
Claudian discovers Claude Code plugins (also called Claude Code agents) by inspecting two JSON sources maintained by the Claude Code CLI. The PluginManager class, defined in src/core/plugins/PluginManager.ts, reads these files during initialization to build a unified view of available extensions.
| Source File | Location | Contents |
|---|---|---|
installed_plugins.json |
~/.claude/plugins/installed_plugins.json |
A map of plugin IDs to arrays of InstalledPluginEntry objects that specify where each plugin resides on disk. |
settings.json |
~/.claude/settings.json (global) and <vault>/.claude/settings.json (project) |
The enabledPlugins map that stores whether each plugin is active or inactive. |
When Claudian starts, the PluginManager loads both files using internal readJsonFile utilities and merges their data to determine the effective plugin list.
How Plugin State Is Computed and Stored
The PluginManager does not simply read the configuration files; it applies a precedence logic to resolve conflicts between global and project-level settings.
Loading and Merging Configuration
During initialization, the manager executes a three-step process:
- Loads the JSON files from disk.
- Selects the appropriate entry for each plugin ID using
selectInstalledPluginEntry. A project-scoped entry always wins over a user-scoped entry when both exist. - Computes the effective
enabledflag using the formula:projectEnabled ?? globalEnabled ?? true. This means plugins are enabled by default unless explicitly disabled in either scope.
The resulting state is exposed through getPlugins(), hasEnabledPlugins(), and getPluginsKey()—the latter being used to trigger restarts of the persistent Claude query when the plugin set changes.
Persisting Changes to Disk
When you toggle a plugin, the PluginManager delegates persistence to CCSettingsStorage (src/core/storage/CCSettingsStorage.ts). This utility writes the updated enabledPlugins map back to either the project or global settings.json, ensuring the Claude Code CLI sees the same state as Claudian.
Enabling and Disabling Plugins
You can control plugin state through the Obsidian settings UI or programmatically via the plugin API.
Using the Settings Interface
The settings pane creates a PluginSettingsManager instance (src/features/settings/ui/PluginSettingsManager.ts) that renders the plugin list. When you click Enable/Disable, the UI executes this flow:
await this.plugin.pluginManager.togglePlugin(pluginId);
await this.plugin.agentManager.loadAgents();
await tabManager.broadcastToAllTabs(
async (svc) => await svc.ensureReady({ force: true })
);
The togglePlugin method (lines 61–73 in PluginManager.ts) flips the flag in memory and calls CCSettingsStorage.setPluginEnabled. Then AgentManager.loadAgents() reloads agents from disk, and broadcastToAllTabs forces every open tab to restart its Claude session so the change takes effect immediately.
Programmatic Plugin Control
For automation or custom scripts, you can interact with the PluginManager directly from the Obsidian developer console or your own plugin code.
List all discovered plugins:
// Assuming `plugin` is the ClaudianPlugin instance
const plugins = plugin.pluginManager.getPlugins();
plugins.forEach(p => {
console.log(`${p.id} (${p.scope}) – ${p.enabled ? 'enabled' : 'disabled'}`);
});
Programmatically enable a plugin:
async function enableMyPlugin(plugin: ClaudianPlugin, id: string) {
await plugin.pluginManager.enablePlugin(id);
await plugin.agentManager.loadAgents();
const view = plugin.getView();
const tabMgr = view?.getTabManager();
await tabMgr?.broadcastToAllTabs(svc => svc.ensureReady({ force: true }));
}
Programmatically disable a plugin:
async function disableMyPlugin(plugin: ClaudianPlugin, id: string) {
await plugin.pluginManager.disablePlugin(id);
await plugin.agentManager.loadAgents();
const view = plugin.getView();
const tm = view?.getTabManager();
await tm?.broadcastToAllTabs(svc => svc.ensureReady({ force: true }));
}
Refreshing the Plugin List After CLI Installation
When you install a new plugin via the Claude Code CLI (claude plugin install …), Claudian’s cached list becomes stale. To update the UI without restarting Obsidian, trigger a refresh:
await plugin.pluginManager.loadPlugins();
await plugin.agentManager.loadAgents();
new Notice('Plugin list refreshed');
The loadPlugins() method re-reads installed_plugins.json and the relevant settings.json files, then rebuilds the internal plugin map. This is the same operation executed by the Refresh button in the Claudian settings pane.
Core Architecture and Key Files
Understanding the source layout helps when debugging or extending plugin functionality:
src/main.ts– InstantiatesPluginManagerandAgentManager, storing them on the plugin instance (this.pluginManager,this.agentManager).src/core/plugins/PluginManager.ts– Core discovery, state handling, and toggling logic for Claude Code plugins.src/core/storage/CCSettingsStorage.ts– Reads and writes Claude Code-compatiblesettings.json; persists enable/disable flags.src/core/types/plugins.ts– TypeScript definitions forInstalledPluginEntryand related interfaces.src/features/settings/ui/PluginSettingsManager.ts– UI component that renders the plugin list and handles user toggles.src/core/agents/AgentManager.ts– Loads agents from plugin install paths after configuration changes.src/core/agents/AgentStorage.ts– Persists agent metadata consulted during reload operations.
Summary
- Discovery: Claudian reads
~/.claude/plugins/installed_plugins.jsonand~/.claude/settings.json(plus vault-scoped variants) to find Claude Code plugins. - Precedence: Project-level settings override global settings; plugins default to enabled unless explicitly disabled.
- Persistence: The
CCSettingsStorageclass writes state changes back to JSON files so the Claude CLI remains synchronized. - Activation: Toggling a plugin updates disk state, reloads agents via
AgentManager, and broadcastsensureReady({ force: true })to all tabs to restart Claude sessions. - Refresh: Call
pluginManager.loadPlugins()followed byagentManager.loadAgents()to pick up newly installed CLI plugins without restarting Obsidian.
Frequently Asked Questions
Where does Claudian store plugin enable settings?
Claudian writes the enabledPlugins map to <vault>/.claude/settings.json for project-specific toggles, or ~/.claude/settings.json for global defaults. The CCSettingsStorage class in src/core/storage/CCSettingsStorage.ts handles these read/write operations to maintain compatibility with the Claude Code CLI.
Why do I need to restart tabs after toggling a plugin?
Claudian maintains persistent Claude sessions per tab. When you enable or disable a plugin, the AgentManager reloads agent definitions from disk, but active sessions retain the old plugin set. The broadcastToAllTabs call with ensureReady({ force: true }) forces every tab to recreate its Claude process, ensuring the new plugin availability is respected immediately.
Can I enable plugins for specific vaults only?
Yes. Because Claudian checks projectEnabled ?? globalEnabled ?? true, placing an enabledPlugins entry in <vault>/.claude/settings.json overrides the global setting for that specific vault. This allows you to maintain different agent configurations across multiple Obsidian vaults.
How do I refresh the plugin list after installing via the CLI?
Click the Refresh button in the Claudian settings pane, or programmatically call await plugin.pluginManager.loadPlugins() followed by await plugin.agentManager.loadAgents(). This re-reads installed_plugins.json and updates the internal plugin map without requiring an Obsidian restart.
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 →