How to Configure External Contexts for Directories Outside the Vault in Claudian

Claudian allows you to reference files from any directory on your filesystem—outside your current Obsidian vault—by adding them as external contexts through the toolbar UI, slash commands, or direct settings manipulation.

The open-source Claudian plugin (YishenTu/claudian) extends Obsidian with AI chat capabilities, and its external context feature bridges the gap between your vault and external project folders. Whether you need to reference code repositories, shared network drives, or documentation folders located elsewhere on your machine, configuring these external directories lets their contents appear in the @‑mention dropdown alongside your vault files.

Understanding the External Context Architecture

The external context system is implemented across three distinct layers in the codebase:

Layer Purpose Source File
Settings Storage Persists paths that survive across sessions src/utils/externalContext.ts
UI Controller Handles add/remove/persist interactions src/features/chat/ui/InputToolbar.ts (class ExternalContextSelector)
File Scanner Recursively indexes files and caches results src/utils/externalContextScanner.ts

When you configure external contexts for directories outside the vault, the ExternalContextSelector class coordinates between these layers to validate paths, detect conflicts, and populate the mention dropdown with file metadata.

Adding External Contexts Outside the Vault

You can add directories external to your vault through three interfaces:

Via the Toolbar UI

Click the External Context icon in the chat input toolbar, then select Add folder. The file picker allows navigation to any absolute path on your filesystem, regardless of vault boundaries.

Via Slash Command

Type the following in the chat input:

/add-dir /absolute/path/to/folder

This invokes ExternalContextSelector.addExternalContext(), which validates the path before adding it to the active session.

Programmatically from Another Plugin

const selector = getActiveTab()?.ui.externalContextSelector;
if (selector) {
  const result = selector.addExternalContext('~/projects/shared-docs');
  if (!result.success) {
    console.error('Failed to add external context:', result.error);
  } else {
    console.log('Added:', result.normalizedPath);
  }
}

The addExternalContext method in src/utils/externalContext.ts automatically expands ~ to the home directory and normalizes the path using normalizePathForFilesystem() before validation.

Managing Persistence and Session State

External context paths exist in two states:

  • Transient (per‑session) – Stored only in memory as externalContextPaths. These disappear when you close the tab or restart Obsidian.
  • Persistent – Saved in the plugin’s JSON settings under the key externalContextPaths and loaded automatically via loadSettings in src/main.ts.

To persist a path, click the pin icon next to the directory in the dropdown list. This triggers ExternalContextSelector.togglePersistence(), which updates the persistentPaths set and invokes onPersistenceChangeCallback to write the configuration to disk:

// Persistent paths are synchronized to settings
this.onPersistenceChangeCallback?.([...this.persistentPaths]);

How the Scanner Indexes External Files

When Claudian needs to display the @‑mention dropdown, it calls externalContextScanner.scanPaths(externalContextPaths) from src/utils/externalContextScanner.ts. The scanner performs the following operations:

  1. Path Expansion – Converts user-friendly paths to filesystem-absolute paths using normalizePathForFilesystem().
  2. Recursive Walking – Traverses directories up to 10 levels deep (MAX_DEPTH), collecting files.
  3. Noise Filtering – Skips node_modules, .git, and symbolic links (entry.isSymbolicLink()).
  4. File Limits – Enforces a maximum of 1,000 files per path (MAX_FILES_PER_PATH).
  5. Caching – Results are cached for 30 seconds (CACHE_TTL_MS) to prevent repeated IO operations.

The results are transformed by buildExternalContextDisplayEntries() in externalContext.ts, which handles de-duplication and adds parent-folder labels when multiple external contexts share the same leaf directory name.

Handling Validation and Edge Cases

The system includes guards to prevent configuration errors when you configure external contexts for directories outside the vault:

Issue Prevention Mechanism
Non-existent directory validateDirectoryPath() returns "Path does not exist"
Relative paths Rejected if !path.isAbsolute()
Duplicate entries isDuplicatePath() normalizes via normalizePathForComparison() before comparing
Nested/overlapping paths findConflictingPath() detects parent/child relationships
Stale cache Entries older than 30s are discarded; call invalidateCache() to clear manually

Programmatic Integration Examples

Adding External Context from a Custom Command

// In src/main.ts command registration
this.addCommand({
  id: 'add-external-context',
  name: 'Add external context directory',
  callback: async () => {
    const input = await promptUser('Enter absolute path:');
    const selector = getActiveTab()?.ui.externalContextSelector;
    if (selector) {
      const result = selector.addExternalContext(input);
      new Notice(result.success ? 'Added' : `Error: ${result.error}`);
    }
  },
});

Manually Editing Settings (Advanced)

You can directly edit .obsidian/plugins/claudian/data.json in your vault:

{
  "externalContextPaths": [
    "/home/user/projects/docs",
    "/mnt/shared/research"
  ]
}

Reload the plugin or restart Obsidian to load these paths into conversation.externalContextPaths as defined in src/main.ts:

conversation.externalContextPaths = meta.externalContextPaths ?? conversation.externalContextPaths;

Retrieving Current External Files

import type { ExternalContextFile } from '@/utils/externalContextScanner';

function listExternalFiles(): ExternalContextFile[] {
  const selector = getActiveTab()?.ui.externalContextSelector;
  const paths = selector?.getExternalContexts() ?? [];
  return externalContextScanner.scanPaths(paths);
}

Summary

  • Configure external contexts using the toolbar UI, /add-dir slash command, or programmatically via ExternalContextSelector.addExternalContext().
  • Validate paths automatically for existence, absoluteness, and conflicts (no duplicates or nested directories allowed).
  • Persist directories using the pin icon in the dropdown, which saves to externalContextPaths in the plugin settings JSON.
  • Scanning logic walks up to 10 levels deep, skips node_modules and symlinks, and caches results for 30 seconds.
  • Key files implementing this feature are src/utils/externalContext.ts, src/utils/externalContextScanner.ts, and src/features/chat/ui/InputToolbar.ts.

Frequently Asked Questions

Can I add a relative path like ../notes as an external context?

No. The addExternalContext method explicitly requires absolute paths. According to the implementation in src/utils/externalContext.ts, any path where path.isAbsolute() returns false is rejected immediately. You must provide the full filesystem path (e.g., /home/user/projects/notes).

Why do my external context files disappear after restarting Obsidian?

Only paths marked as persistent survive restarts. Transient paths are stored in memory within externalContextPaths and are lost when the session ends. To retain a directory, click the pin icon in the external context dropdown to add it to persistentPaths, which writes to the plugin's settings file via onPersistenceChangeCallback.

Symbolic links are explicitly skipped during the scanning process. In src/utils/externalContextScanner.ts, the scanDirectory function checks entry.isSymbolicLink() and continues to the next entry if true, preventing infinite recursion and circular references when walking directory trees.

Is there a limit to how many files Claudian will index from an external directory?

Yes. The scanner enforces a limit of 1,000 files per external context path defined by MAX_FILES_PER_PATH. Beyond this threshold, additional files are silently ignored to prevent performance degradation. The system also limits recursion depth to 10 levels (MAX_DEPTH) to avoid excessive filesystem traversal.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →