Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .devin/wiki.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"content": "Vault Cortex is a remote MCP (Model Context Protocol) server that exposes an Obsidian vault over HTTPS — vault CRUD, hybrid search, task management, structured memory, link-graph queries, and non-markdown file reading (images, PDFs, canvases, data files), plus user-initiated prompts. It runs headless in Docker, working directly with .md files on disk using its own Obsidian-parity parsers and search index. README.md is the authoritative feature description and ARCHITECTURE.md the authoritative design document — derive capability details, defaults, and security specifics from those and the code rather than restating them. The repo also ships a CLI (cli/, published as the vault-cortex npm package) that scaffolds a deployment: npx vault-cortex@latest init."
},
{
"content": "The codebase is organized into four internal layers under src/vault-mcp/: (1) obsidian-markdown/ — pure Obsidian/Markdown parsers with no I/O (links, lines/fences, frontmatter, callouts, headings, tasks, memory entries, canvas, plaintext). (2) vault-operations/ — filesystem I/O for vault content (vault-filesystem, vault-patcher, note-mover, memory-store, daily-notes, task-mutations, task-format-config, trash-sweeper, asset-operations). (3) search/ — the SQLite FTS5 + sqlite-vec index, embedding pipeline, and chokidar file watcher. (4) mcp-core/ — the MCP protocol surface: streamable-http transport, tool group modules under mcp-core/tools/, and prompt group modules under mcp-core/prompts/. Authentication lives in src/vault-mcp/oauth/ (OAuth 2.1) and src/functions/authorizer.ts (AWS Lambda, path-aware). The :remote image's setup mode — the browser sign-in served before an Obsidian Sync token exists — lives in src/vault-mcp/setup/. Infrastructure-as-code (sst.config.ts) is specific to the AWS reference deployment and should not be documented as the primary deployment path."
"content": "The codebase is organized into four internal layers under src/vault-mcp/: (1) obsidian-markdown/ — pure Obsidian/Markdown parsers with no I/O (links, lines/fences, frontmatter, callouts, headings, tasks, memory entries, canvas, plaintext). (2) vault-operations/ — filesystem I/O for vault content (vault-filesystem, vault-patcher, note-mover, memory-store, daily-notes, vault-folder-config, task-mutations, task-format-config, trash-sweeper, asset-operations). (3) search/ — the SQLite FTS5 + sqlite-vec index, embedding pipeline, and chokidar file watcher. (4) mcp-core/ — the MCP protocol surface: streamable-http transport, tool group modules under mcp-core/tools/, and prompt group modules under mcp-core/prompts/. Authentication lives in src/vault-mcp/oauth/ (OAuth 2.1) and src/functions/authorizer.ts (AWS Lambda, path-aware). The :remote image's setup mode — the browser sign-in served before an Obsidian Sync token exists — lives in src/vault-mcp/setup/. Infrastructure-as-code (sst.config.ts) is specific to the AWS reference deployment and should not be documented as the primary deployment path."
}
],
"pages": [
Expand All @@ -22,7 +22,7 @@
},
{
"title": "Configuration Reference",
"purpose": "All environment variables as defined in config.ts and the .env.example files, the ServerConfig type, and how configuration differs across the deployment modes. Enumerate the variables from the source at index time."
"purpose": "All environment variables as defined in config.ts and the .env.example files, the VaultConfig type, and how configuration differs across the deployment modes. Enumerate the variables from the source at index time."
},
{
"title": "Architecture",
Expand All @@ -45,7 +45,7 @@
},
{
"title": "Vault Operations",
"purpose": "The filesystem I/O layer in vault-operations/: vault-filesystem.ts (base primitives including atomic writes and path safety), vault-patcher.ts, note-mover.ts, memory-store.ts, daily-notes.ts, task-mutations.ts, task-format-config.ts, trash-sweeper.ts (boot-time orphan-row purge + daily retention sweep over recorded .trash/ entries), and asset-operations.ts (the use-case behind vault_read_file and vault_list_files). Derive the safety mechanisms (locking modes, TOCTOU guards, protected paths) from ARCHITECTURE.md's Data integrity section.",
"purpose": "The filesystem I/O layer in vault-operations/: vault-filesystem.ts (base primitives including atomic writes and path safety), vault-patcher.ts, note-mover.ts, memory-store.ts, daily-notes.ts, vault-folder-config.ts (protected folders and orphan exclusion defaults), task-mutations.ts, task-format-config.ts, trash-sweeper.ts (boot-time orphan-row purge + daily retention sweep over recorded .trash/ entries), and asset-operations.ts (the use-case behind vault_read_file and vault_list_files). Derive the safety mechanisms (locking modes, TOCTOU guards, protected paths) from ARCHITECTURE.md's Data integrity section.",
"parent": "Architecture"
},
{
Expand Down
10 changes: 7 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,13 @@ GHCR_USER=
# (default "Daily Notes"). When set, replaces the whole default — include the
# daily notes folder in your list if needed.
# PROTECTED_PATHS=About Me,Daily Notes
# Comma-separated folders excluded from orphan detection (default: the daily
# notes folder — DAILY_NOTES_FOLDER when set, otherwise "Daily Notes" — plus
# Templates and MEMORY_DIR).
# Comma-separated folders excluded from orphan detection.
# Default: the daily notes folder, Templates, and MEMORY_DIR.
# DAILY_NOTES_FOLDER wins; otherwise .obsidian/daily-notes.json is reread
# on each query, falling back to "Daily Notes". Root-level daily notes remain eligible.
# When set, replaces the whole default — include every folder to keep excluded.
# Set ORPHAN_EXCLUDE_FOLDERS=, to exclude nothing; an empty value uses the defaults.
# Apply env changes by redeploying; synced Obsidian settings apply on the next query.
# ORPHAN_EXCLUDE_FOLDERS=Daily Notes,Templates,About Me
Comment thread
aliasunder marked this conversation as resolved.
# URL shown in OAuth discovery metadata (default: https://github.com/aliasunder/vault-cortex)
# SERVICE_DOCUMENTATION_URL=https://github.com/youruser/your-fork
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ src/
authorizer.ts # Lambda: path-aware auth (OAuth pass-through, JWT + static)
vault-mcp/
server.ts # Entry point — config, mount routes, listen
config.ts # Env-var loader + ServerConfig type (loadConfig)
config.ts # Env-var loader + VaultConfig type (loadConfig)
obsidian-markdown/ # Pure Obsidian/Markdown parsers + transforms (no I/O)
lines.ts # splitIntoLines (CRLF) + fence state machine + classifyLines + pageTextByLines (line paging)
frontmatter.ts # gray-matter parse/stringify + frontmatter merge
Expand All @@ -167,6 +167,7 @@ src/
note-mover.ts # Move/rename a note + rewrite every vault-wide link to it
memory-store.ts # About Me/ heading-aware read/append/delete
daily-notes.ts # Daily note config reader + path resolver (env settings > daily-notes.json)
vault-folder-config.ts # Protected folders + live orphan exclusion defaults
task-mutations.ts # Task create + state mutations (status, priority, heading moves, sub-tasks)
task-format-config.ts # Tasks-plugin format config reader (emoji vs Dataview) + status registry
trash-config.ts # Obsidian "Deleted files" config reader (trashOption from .obsidian/app.json)
Expand Down
7 changes: 5 additions & 2 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,10 @@ Link queries use a `links` table populated during indexing:
3. Basename (shortest-path-first for ambiguous basenames)
- **Non-markdown files:** Targets that don't resolve to a note are checked against a `non_md_files` table (populated during rebuild, maintained by the file watcher). Both wikilinks and markdown-style links to `.canvas`, `.base`, images, PDFs, and other non-markdown files resolve as `kind: "file"` instead of being counted as broken.
- **Outgoing links:** `vault_get_outgoing_links` returns a `kind` discriminator (`"note"` or `"file"`) plus each target's byte size (`bytes` — from the notes table for notes, from `non_md_files` for files), so clients can route notes to `vault_read_note` and files to `vault_read_file` with size awareness.
- **Orphans:** `vault_find_orphans` excludes folders listed in `ORPHAN_EXCLUDE_FOLDERS` (default: the daily notes folder — `DAILY_NOTES_FOLDER` or `Daily Notes` — plus `Templates` and the memory dir).
- **Orphans:** `vault_find_orphans` and `vault-orientation` resolve default exclusions on each invocation: the daily notes folder (`DAILY_NOTES_FOLDER` → `.obsidian/daily-notes.json` → `Daily Notes`), `Templates`, and the memory dir.
- `ORPHAN_EXCLUDE_FOLDERS` replaces that list; a tool call's `exclude_folders` replaces it for that call.
- An unreadable or malformed config logs a warning and uses `Daily Notes`; a missing file uses that fallback without a warning.
- An empty Obsidian folder setting uses the `Daily Notes` fallback. A whitespace-only folder adds no daily-folder exclusion. Neither excludes the whole vault, so root-level daily notes remain eligible.

### Files

Expand Down Expand Up @@ -1100,7 +1103,7 @@ The runtime image (`Dockerfile`) minimizes the attack surface:
| Debian security fixes | `apt-get upgrade` at build time covers the node-image rebuild window |
| Log rotation (Compose) | `max-size: 10m`, `max-file: 3` — prevents disk exhaustion |
| Explicit proxy trust (Express) | `trust proxy` = `TRUST_PROXY_HOPS` (default 0 — direct exposure); the `Forwarded` header is honored only under a non-zero `TRUST_FORWARDED_HOPS` — injected forwarding headers can't spoof the client IP (OAuth rate-limit bucket key, request logs) |
| `Object.freeze` on config | Prevents accidental mutation of the loaded `ServerConfig` — defense against programming errors |
| `Object.freeze` on config | Prevents accidental mutation of the loaded `VaultConfig` — defense against programming errors |

### Durability

Expand Down
2 changes: 1 addition & 1 deletion DEPLOY.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ To find your stage: `cat .sst/stage` (after one-time setup).
| `DISABLED_TOOLS` | Optional. Hide individual tools by name, comma-separated. Names match the Tool column in the [README tools table](./README.md#tools). Subtractive only; an unknown tool name stops the server at startup. Default: none hidden. |
| `MEMORY_DIR` | Optional. Memory folder name in the vault (default: `About Me`). See the [Configuration](./README.md#configuration) section. |
| `PROTECTED_PATHS` | Optional. Comma-separated folders protected from deletion and moves (default: `MEMORY_DIR` plus the daily notes folder, read from `DAILY_NOTES_FOLDER` or `.obsidian/daily-notes.json`, default `Daily Notes`). Overrides the default entirely when set. |
| `ORPHAN_EXCLUDE_FOLDERS` | Optional. Comma-separated folders excluded from orphan detection (default: `DAILY_NOTES_FOLDER, Templates, MEMORY_DIR`). Overrides the default entirely when set. |
| `ORPHAN_EXCLUDE_FOLDERS` | Optional. Comma-separated folders excluded from orphan detection (default: the daily notes folder, `Templates`, and `MEMORY_DIR`). The `DAILY_NOTES_FOLDER` variable wins; otherwise synced `.obsidian/daily-notes.json` is reread per query (fallback `Daily Notes`). Overrides the default entirely when set. Use `,` to exclude nothing; an empty value uses the defaults. Apply variable changes with Force Deploy; synced Obsidian changes need no redeploy. See [Daily notes](./README.md#daily-notes) for root-level notes. |
| `SERVICE_DOCUMENTATION_URL` | Optional. URL in OAuth discovery metadata (default: `https://github.com/aliasunder/vault-cortex`). Set to your fork's URL. |
| `SYNC_CONFIGS` | Optional. Obsidian settings categories synced to the server, comma-separated (default: `core-plugin-data,community-plugin-data` — daily-notes settings and the Tasks plugin's format). Set `none` to disable. See [Daily notes](./README.md#daily-notes). |
| `SYNC_EXCLUDED_FOLDERS` | Optional. Folders to leave out of Obsidian Sync, comma-separated — the same list as Obsidian's Sync → Excluded folders. Unset syncs everything. |
Expand Down
Loading
Loading