Linux systemd setup¶
Two approaches, watcher-first. Since v1.1 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 FSEvents/inotify can't observe (SMB, some NFS setups) or you prefer a fixed schedule, skip to the timer fallback.
No root, no system-wide install — everything lives under ~/.config/systemd/user/.
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.