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
externalContextPathsand loaded automatically vialoadSettingsinsrc/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:
- Path Expansion – Converts user-friendly paths to filesystem-absolute paths using
normalizePathForFilesystem(). - Recursive Walking – Traverses directories up to 10 levels deep (
MAX_DEPTH), collecting files. - Noise Filtering – Skips
node_modules,.git, and symbolic links (entry.isSymbolicLink()). - File Limits – Enforces a maximum of 1,000 files per path (
MAX_FILES_PER_PATH). - 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-dirslash command, or programmatically viaExternalContextSelector.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
externalContextPathsin the plugin settings JSON. - Scanning logic walks up to 10 levels deep, skips
node_modulesand symlinks, and caches results for 30 seconds. - Key files implementing this feature are
src/utils/externalContext.ts,src/utils/externalContextScanner.ts, andsrc/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.
How does Claudian handle symlinks inside external directories?
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →