Scheduled indexing (Linux)¶
Most users don't need this
obsidian-brain server auto-watches the vault when running from any MCP client — the index stays live as you edit, no scheduled job required. Use scheduled indexing only when you can't keep server running continuously, or when the watcher can't observe changes reliably (SMB, some NFS setups).
Two approaches for keeping the index fresh on Linux outside of an active MCP client session: a persistent watch daemon via a systemd user service, or a timer-driven index job that runs every 30 minutes. No root, no system-wide install — everything lives under ~/.config/systemd/user/.
obsidian-brain server already watches the vault whenever it's running, so most users who launch obsidian-brain from an MCP client don't need anything here. If you want a dedicated daemon that keeps the index fresh even when no MCP client is running, use the watcher service below. If your vault lives somewhere inotify can't observe (SMB, some NFS setups) or you prefer a fixed schedule, skip to the timer fallback.
Recommended: run the watcher instead¶
Run the watch subcommand as a systemd user service — useful on a server, a headless box, or any machine where you want the index live even when no MCP client is running. Create ~/.config/systemd/user/obsidian-brain-watch.service:
[Unit]
Description=obsidian-brain live vault watcher
After=network.target
[Service]
Type=simple
Environment=VAULT_PATH=/absolute/path/to/your/vault
ExecStart=/usr/bin/obsidian-brain watch
Restart=always
RestartSec=5
StandardOutput=append:%h/.local/state/obsidian-brain-watch.log
StandardError=append:%h/.local/state/obsidian-brain-watch.err
[Install]
WantedBy=default.target
Then:
mkdir -p ~/.local/state
systemctl --user daemon-reload
systemctl --user enable --now obsidian-brain-watch.service
systemctl --user status obsidian-brain-watch.service
Adjust /usr/bin/obsidian-brain to match which obsidian-brain. If you want the service to survive logout, run sudo loginctl enable-linger $USER once. The timer-based flow below is the fallback if you set OBSIDIAN_BRAIN_NO_WATCH=1 or your vault lives on a filesystem where inotify doesn't fire (SMB, some NFS setups).
What it does (scheduled fallback)¶
A systemd user timer runs obsidian-brain index every 30 minutes as your user account. Because everything lives under ~/.config/systemd/user/, there is no sudo required and nothing is installed system-wide. The timer is tied to your login session and will stop when you log out — unless you enable linger (see the optional step below).
Prerequisites¶
npm install -g obsidian-brain— puts theobsidian-brainbinary on yourPATH. Confirm withwhich obsidian-brainand note the path (commonly/usr/bin/obsidian-brain,/usr/local/bin/obsidian-brain, or an nvm-scoped variant).- You know the absolute path to your Obsidian vault (
VAULT_PATH). - A systemd-based Linux distribution (most modern distros: Ubuntu, Debian, Fedora, Arch, openSUSE, etc.).
If you're running from a local source clone instead of npm, see the source install variant at the bottom of this file.
1. Create the service unit¶
Create ~/.config/systemd/user/obsidian-brain.service:
[Unit]
Description=obsidian-brain vault reindex
After=network.target
[Service]
Type=oneshot
Environment=VAULT_PATH=/absolute/path/to/your/vault
ExecStart=/usr/bin/obsidian-brain index
StandardOutput=append:%h/.local/state/obsidian-brain-index.log
StandardError=append:%h/.local/state/obsidian-brain-index.err
Notes:
%his expanded by systemd to your$HOMEdirectory.- Adjust
/usr/bin/obsidian-brainto match whereverwhich obsidian-brainreports on your system. If you installed node vianvm, the binary will be under/absolute/path/to/.nvm/versions/node/vXX.Y.Z/bin/obsidian-brain— use that full path; systemd does not expand~insideExecStart. Type=oneshotis correct here: the reindex runs to completion and exits; the timer will trigger the next run.
2. Create the timer unit¶
Create ~/.config/systemd/user/obsidian-brain.timer:
[Unit]
Description=Run obsidian-brain reindex every 30 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=30min
Unit=obsidian-brain.service
Persistent=true
[Install]
WantedBy=timers.target
What these fields mean:
OnBootSec=5min— wait 5 minutes after the user manager starts before the first run, so login isn't slowed by indexing.OnUnitActiveSec=30min— after each run finishes, wait 30 minutes before firing the next one.Persistent=true— if the machine was off or asleep when a run was supposed to fire, systemd will run it as soon as possible after resume / boot. Without this, missed runs are simply skipped.
3. Enable and start¶
mkdir -p ~/.local/state
systemctl --user daemon-reload
systemctl --user enable --now obsidian-brain.timer
systemctl --user list-timers --all | grep obsidian-brain
The last command should print a row showing obsidian-brain.timer along with its NEXT and LEFT columns.
4. Optional — survive logout¶
By default, user services stop when you log out. On a desktop that's usually fine. On a server, or if you want indexing to continue after logging out of a graphical session, enable linger for your user:
This is the one step in the whole guide that needs sudo, and it's optional.
5. Check status and logs¶
systemctl --user status obsidian-brain.service
systemctl --user status obsidian-brain.timer
journalctl --user -u obsidian-brain.service -n 50
tail -f ~/.local/state/obsidian-brain-index.log
journalctl shows systemd's view of every execution (exit codes, timings). The log file captures the indexer's stdout; the .err file captures stderr.
6. Trigger a run manually¶
Useful for verifying the unit works without waiting for the timer:
Then check the log file or journalctl to confirm it ran.
7. Adjust the interval¶
Edit ~/.config/systemd/user/obsidian-brain.timer, change OnUnitActiveSec to whatever you want (for example 15min, 1h, 6h), then reload:
8. Disable and uninstall¶
systemctl --user disable --now obsidian-brain.timer
rm ~/.config/systemd/user/obsidian-brain.service
rm ~/.config/systemd/user/obsidian-brain.timer
systemctl --user daemon-reload
Log files under ~/.local/state/ are left in place — remove them manually if you want.
9. Troubleshooting¶
status=203/EXEC— systemd could not execute the binary. Usually the path inExecStartis wrong. Runwhich obsidian-brainand put that exact absolute path into the unit file, thensystemctl --user daemon-reloadand try again.- nvm users — always use the fully expanded absolute path (for example
/absolute/path/to/.nvm/versions/node/v20.11.1/bin/obsidian-brain). systemd does not expand~insideExecStart, so paths like~/.nvm/...will fail with 203/EXEC. - Timer not firing —
systemctl --user list-timersmust showobsidian-brain.timerwith a realNEXTtime. If it doesn't appear, re-runsystemctl --user enable --now obsidian-brain.timer. IfNEXTisn/a, double-check the[Timer]section syntax. better-sqlite3native-module errors — the native binding must be built against the same node version systemd will invoke. Rebuild it with that node on yourPATH:
- Environment looks empty — systemd user services start with a minimal environment. If your indexer needs extra variables beyond
VAULT_PATH, add moreEnvironment=KEY=VALUElines to the[Service]section, one per line.
Variant: running from a local clone¶
If you're developing obsidian-brain from a source clone rather than the npm package, your [Service] section needs both a WorkingDirectory and a node dist/cli/index.js index invocation:
[Service]
Type=oneshot
WorkingDirectory=/absolute/path/to/obsidian-brain
Environment=VAULT_PATH=/absolute/path/to/your/vault
ExecStart=/usr/bin/node dist/cli/index.js index
StandardOutput=append:%h/.local/state/obsidian-brain-index.log
StandardError=append:%h/.local/state/obsidian-brain-index.err
Everything else (timer unit, enable/start flow, troubleshooting) stays identical.