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

> Learn how to configure external contexts for directories outside your Claudian vault. Easily reference files from any filesystem directory directly within your notes. Add external contexts via UI, commands, or settings.

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

---

**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`](https://github.com/YishenTu/claudian/blob/main/src/utils/externalContext.ts) |
| **UI Controller** | Handles add/remove/persist interactions | [`src/features/chat/ui/InputToolbar.ts`](https://github.com/YishenTu/claudian/blob/main/src/features/chat/ui/InputToolbar.ts) (class `ExternalContextSelector`) |
| **File Scanner** | Recursively indexes files and caches results | [`src/utils/externalContextScanner.ts`](https://github.com/YishenTu/claudian/blob/main/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:

```text
/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

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

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

```typescript
// 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`](https://github.com/YishenTu/claudian/blob/main/.obsidian/plugins/claudian/data.json) in your vault:

```json
{
  "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`](https://github.com/YishenTu/claudian/blob/main/src/main.ts):

```typescript
conversation.externalContextPaths = meta.externalContextPaths ?? conversation.externalContextPaths;

```

### Retrieving Current External Files

```typescript
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`](https://github.com/YishenTu/claudian/blob/main/src/utils/externalContext.ts), [`src/utils/externalContextScanner.ts`](https://github.com/YishenTu/claudian/blob/main/src/utils/externalContextScanner.ts), and [`src/features/chat/ui/InputToolbar.ts`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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`](https://github.com/YishenTu/claudian/blob/main/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.