Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ffc3e74
wip: daily notes root folder
aliasunder Oct 16, 2026
8781515
fix(daily-notes): regenerate the tool surface and pin the new descrip…
aliasunder Oct 16, 2026
0f7861f
fix(review): document blank and root daily-notes folders in README an…
aliasunder Oct 16, 2026
4af6d6f
fix(daily-notes): scope the shared-folder wording to a root or blank …
aliasunder Oct 16, 2026
e43f2d4
style: clarify daily-notes config readers and root/blank folder docs
aliasunder Oct 16, 2026
549e7dc
fix(daily-notes): say the orphan-hint folder differs when the daily s…
aliasunder Oct 16, 2026
e55a42a
test(daily-notes): cover blank-folder resolution in the prompts and o…
aliasunder Oct 16, 2026
4aef3f4
refactor(daily-notes): take a resolved config through its own setting…
aliasunder Oct 16, 2026
af2f3e3
fix(daily-notes): normalize the folder setting like Obsidian's normal…
aliasunder Oct 16, 2026
6b4a1c6
fix(daily-notes): trim the formatted date in the daily note filename
aliasunder Oct 16, 2026
6c20959
fix(docs): describe root and empty daily folders in env comments and …
aliasunder Oct 16, 2026
37487cd
fix(daily-notes): name the daily notes folder in the new tool-text cl…
aliasunder Oct 16, 2026
34eec2a
fix(daily-notes): key the forward-ref exception on the folder setting
aliasunder Oct 16, 2026
a2e0502
docs(daily-notes): describe the empty and vault-root folder settings …
aliasunder Oct 16, 2026
71bcc11
feat(daily-notes): accept / in DAILY_NOTES_FOLDER as the vault root
aliasunder Oct 16, 2026
ad26904
style(daily-notes): clarify vault-root folder comments and rewrap doc…
aliasunder Oct 16, 2026
6384c82
fix(cli): accept / as the vault root in the daily notes folder prompt
aliasunder Oct 16, 2026
17651c6
docs(daily-notes): scope the folder normalization note to daily-notes…
aliasunder Oct 16, 2026
cee88ee
fix(daily-notes): finish the tool text for root and blank folder sett…
aliasunder Oct 16, 2026
6ce1ab7
fix(daily-notes): give delete and move their own filesystem-error ent…
aliasunder Oct 16, 2026
ff15a31
fix(daily-notes): name the referents in the orphan hint and the unrea…
aliasunder Oct 16, 2026
5e08b88
test(tool-surface): raise the per-tool allowance to 4,263 after rebas…
aliasunder Oct 16, 2026
5d1c435
fix(move): list the could-not-write error with its shorter-name remedy
aliasunder Oct 16, 2026
8c1a53a
docs(daily-notes): name each new-note location setting in readNewNote…
aliasunder Oct 16, 2026
5e5ee1a
docs(daily-notes): say when the server reads app.json, and why the cu…
aliasunder Oct 16, 2026
444d720
docs(daily-notes): say why the tolerant readers' fallbacks are safe
aliasunder Oct 17, 2026
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
25 changes: 15 additions & 10 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ GHCR_USER=
# default list) and turn on "Sync all other types" on the uploading device.
# SYNC_FILE_TYPES=
# Obsidian settings categories to sync into the server's .obsidian/ folder
# (default: the two the server reads — daily notes settings and community
# plugin settings such as the Tasks plugin's format; "none" disables).
# (default: daily notes settings and community plugin settings such as the
# Tasks plugin's format; "none" disables).
# A category only syncs after your desktop pushes it: Settings → Sync →
# "Vault configuration sync". Some community plugins keep API keys in their
# settings — server tools never read .obsidian/, but synced settings do
Expand Down Expand Up @@ -220,22 +220,27 @@ GHCR_USER=
# DISABLED_TOOLS=vault_delete_note,vault_move_note
# Memory folder name in your vault (default: "About Me")
# MEMORY_DIR=About Me
# Daily notes folder and filename format (default: read from the
# vault's .obsidian/daily-notes.json, synced to the server via SYNC_CONFIGS
# above; falls back to "Daily Notes" and YYYY-MM-DD). Folder is any
# vault-relative path (Journal, Planner/Daily); format takes the same tokens
# as Obsidian's date format setting.
# Daily notes folder and filename format. Default: read from the vault's
# .obsidian/daily-notes.json, synced to the server via SYNC_CONFIGS above, or
# "Daily Notes" and YYYY-MM-DD when that file is missing or unreadable. An
# empty folder in that file means Obsidian's location for new notes, which
# syncs only when SYNC_CONFIGS includes app; without it, the server uses the
# vault root. Folder is any vault-relative path (Journal, Planner/Daily), or
# / for the vault root; format takes the same tokens as Obsidian's date format
# setting.
# DAILY_NOTES_FOLDER=Journal
# DAILY_NOTES_FORMAT=YYYY-MM-DD
# 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"). When set, replaces the whole default — include the
# daily notes folder in your list if needed.
# (default "Daily Notes"; none when that setting is the vault root or empty).
# 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, 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.
# on each query, falling back to "Daily Notes". A vault-root or empty folder
# setting adds no daily folder, so those 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.
Expand Down
12 changes: 8 additions & 4 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ Unlike a read that parses the block, such as `vault_read_note` with `properties_

`vault_delete_note` and `vault_move_note` refuse paths under protected folders as a server-side guardrail:

- **Default set:** the memory dir plus the daily notes folder, resolved on every delete and move as [Daily notes](#property-discovery--daily-notes) describes
- **Default set:** the memory dir plus the daily notes folder, resolved on every delete and move as [Daily notes](#property-discovery--daily-notes) describes; a vault-root or blank folder setting adds no folder
- **Unreadable `daily-notes.json`:** a file that exists but cannot be read or parsed refuses the delete or move, because the folder to protect is unknown; setting `DAILY_NOTES_FOLDER` skips the file
- **Override:** `PROTECTED_PATHS` replaces the default set entirely, and `daily-notes.json` is not read

Expand Down Expand Up @@ -246,8 +246,11 @@ Every tag input (`tag` on `vault_search_by_tag` and `vault_list_tasks`, the `tag
**Daily notes:** `vault_get_daily_note` resolves the vault's folder and date format, each independently: `DAILY_NOTES_FOLDER`/`DAILY_NOTES_FORMAT` env setting → `.obsidian/daily-notes.json` → fallback (`Daily Notes/YYYY-MM-DD.md`).

- **Read on every call:** a folder or format change in Obsidian applies to the next call, and a config file that arrives after boot needs no restart
- **File folder normalized like Obsidian:** in `daily-notes.json`, runs of `/` or `\` become one `/` and leading and trailing slashes are dropped, so Obsidian's `"/"` is the vault root; no-break spaces become plain spaces and the name is NFC-normalized. `DAILY_NOTES_FOLDER` takes `/` for the vault root and is otherwise validated as a vault folder name
- **Blank folder in the file:** Obsidian's new-note location (`newFileLocation: "folder"` plus `newFileFolderPath` in `.obsidian/app.json`), otherwise the vault root
- **Missing file:** takes the fallbacks
- **Unparseable file:** takes the fallbacks and logs a `warn`
- **Shared folder:** a vault-root or blank folder setting puts daily notes beside other notes, so it adds no folder to the delete and move guard, the orphan exclusion, or forward-reference handling (broken links into the daily folder, flagged `daily_note_forward_ref` by `vault_get_outgoing_links` and left out of `vault-orientation`'s broken-link count)

### Memory

Expand Down Expand Up @@ -311,10 +314,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` 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.
- **Orphans:** `vault_find_orphans` and `vault-orientation` resolve default exclusions on each invocation: the daily notes folder (resolved as [Daily notes](#property-discovery--daily-notes) describes), `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.
- A vault-root, blank, or whitespace-only folder setting adds no daily-folder exclusion, so those daily notes remain eligible.

### Files

Expand Down Expand Up @@ -1254,7 +1257,8 @@ Docker hardening, and durability seatbelts above.
`join`, bypassing `resolveSafePath`'s hidden-path guard).
- **Protected paths**: `PROTECTED_PATHS` (default: `MEMORY_DIR` plus the
daily notes folder, from `DAILY_NOTES_FOLDER`, then
`.obsidian/daily-notes.json`, then `Daily Notes`) blocks deleting
`.obsidian/daily-notes.json`, then `Daily Notes`; none for a vault-root or
blank folder setting) blocks deleting
notes in, moving notes out of, and moving notes into configured
folders. The check (`isProtectedPath()`, shared by delete and move)
runs on the canonical vault-relative path with a case-folded
Expand Down
6 changes: 3 additions & 3 deletions DEPLOY.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,13 +364,13 @@ To find your stage: `cat .sst/stage` (after one-time setup).
| `READONLY_MODE` | Optional. Set `true` to hide every tool that changes the vault and skip memory folder auto-creation — read and search only. Default: `false`. |
| `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: 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. |
| `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`; none when that setting is the vault root or empty). 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 and empty settings. |
| `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. |
| `SYNC_FILE_TYPES` | Optional. Attachment types Obsidian Sync delivers, comma-separated. **Valid values:** `image`, `audio`, `video`, `pdf`, `unsupported`. **Unset (default):** `image,audio,video,pdf`. The text files Vault Cortex reads (CSV, JSON, TXT, XML, LOG, YAML) fall under `unsupported`, Obsidian Sync's name for its **Sync all other types** category; SVG syncs as `image`, and notes, canvases, and bases always sync. To read those text files, set it to `image,audio,video,pdf,unsupported` (the value replaces the default list, so keep the four defaults) and turn on **Sync all other types** in Obsidian's Sync settings on the device that has them. An invalid value is skipped with a warning in the logs, and the default types sync instead. |
| `DAILY_NOTES_FOLDER` | Optional. Sets the daily notes folder (default: read from the vault's `.obsidian/daily-notes.json`, falling back to `Daily Notes`). See [Daily notes](./README.md#daily-notes). |
| `DAILY_NOTES_FOLDER` | Optional. Sets the daily notes folder: any vault-relative path, or `/` for the vault root (default: read from the vault's `.obsidian/daily-notes.json`; `Daily Notes` when that file is missing or unreadable). See [Daily notes](./README.md#daily-notes). |
| `DAILY_NOTES_FORMAT` | Optional. Sets the daily note filename format, in the same tokens as Obsidian's daily note date format setting (default: read from the vault's config, falling back to `YYYY-MM-DD`). |
| `TZ` | Optional. Container timezone (default: `UTC`). Affects `vault_update_memory` date stamps and `vault_get_daily_note` date resolution. Set to your IANA timezone (e.g. `America/New_York`). |
| `LOG_LEVEL` | Optional. Logging verbosity: `debug`, `info`, `warn`, `error`. Default: `info`. |
Expand Down
Loading
Loading