# How to Enable and Configure Claude Code Plugins in Claudian: A Developer’s Guide

> Master Claude Code plugins with Claudian. Learn to enable and configure plugins by managing JSON files and leveraging the PluginManager for seamless integration. Your developer guide awaits.

- Repository: [YishenTu/claudian](https://github.com/YishenTu/claudian)
- Tags: how-to-guide
- Published: 2026-03-17

---

**Claudian manages Claude Code plugins by reading the Claude CLI’s [`installed_plugins.json`](https://github.com/YishenTu/claudian/blob/main/installed_plugins.json) and [`settings.json`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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:

1. **Loads** the JSON files from disk.
2. **Selects** the appropriate entry for each plugin ID using `selectInstalledPluginEntry`. A project-scoped entry always wins over a user-scoped entry when both exist.
3. **Computes** the effective `enabled` flag 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`](https://github.com/YishenTu/claudian/blob/main/src/core/storage/CCSettingsStorage.ts)). This utility writes the updated `enabledPlugins` map back to either the project or global [`settings.json`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/src/features/settings/ui/PluginSettingsManager.ts)) that renders the plugin list. When you click **Enable/Disable**, the UI executes this flow:

```typescript
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`](https://github.com/YishenTu/claudian/blob/main/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:**

```typescript
// 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:**

```typescript
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:**

```typescript
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:

```typescript
await plugin.pluginManager.loadPlugins();
await plugin.agentManager.loadAgents();
new Notice('Plugin list refreshed');

```

The `loadPlugins()` method re-reads [`installed_plugins.json`](https://github.com/YishenTu/claudian/blob/main/installed_plugins.json) and the relevant [`settings.json`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/src/main.ts)** – Instantiates `PluginManager` and `AgentManager`, storing them on the plugin instance (`this.pluginManager`, `this.agentManager`).
- **[`src/core/plugins/PluginManager.ts`](https://github.com/YishenTu/claudian/blob/main/src/core/plugins/PluginManager.ts)** – Core discovery, state handling, and toggling logic for Claude Code plugins.
- **[`src/core/storage/CCSettingsStorage.ts`](https://github.com/YishenTu/claudian/blob/main/src/core/storage/CCSettingsStorage.ts)** – Reads and writes Claude Code-compatible [`settings.json`](https://github.com/YishenTu/claudian/blob/main/settings.json); persists enable/disable flags.
- **[`src/core/types/plugins.ts`](https://github.com/YishenTu/claudian/blob/main/src/core/types/plugins.ts)** – TypeScript definitions for `InstalledPluginEntry` and related interfaces.
- **[`src/features/settings/ui/PluginSettingsManager.ts`](https://github.com/YishenTu/claudian/blob/main/src/features/settings/ui/PluginSettingsManager.ts)** – UI component that renders the plugin list and handles user toggles.
- **[`src/core/agents/AgentManager.ts`](https://github.com/YishenTu/claudian/blob/main/src/core/agents/AgentManager.ts)** – Loads agents from plugin install paths after configuration changes.
- **[`src/core/agents/AgentStorage.ts`](https://github.com/YishenTu/claudian/blob/main/src/core/agents/AgentStorage.ts)** – Persists agent metadata consulted during reload operations.

## Summary

- **Discovery**: Claudian reads `~/.claude/plugins/installed_plugins.json` and `~/.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 `CCSettingsStorage` class 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 broadcasts `ensureReady({ force: true })` to all tabs to restart Claude sessions.
- **Refresh**: Call `pluginManager.loadPlugins()` followed by `agentManager.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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/installed_plugins.json) and updates the internal plugin map without requiring an Obsidian restart.