rixct79 downloadsDetects when a server's actual configuration has diverged from what you documented in your notes. Read-only over SFTP.
English · Русский
An Obsidian plugin that detects when a server's actual configuration has diverged from what you documented in your notes — read-only, over SFTP.
Infrastructure documentation rots. You write down how a server should be configured, then a reboot, a manual fix, or someone else's script changes the real file, and your notes silently become wrong. There is no built-in way to know your documentation is out of date until something breaks in production.
You annotate a drift code block in a note with a server alias and a remote file path. The plugin connects to that server over SSH in read-only mode, fetches the current content of the file via SFTP, and compares it line by line against the code block. If they match, the block is marked in sync. If they differ, the plugin shows which lines are only in your notes and which are only on the real server, and leaves the note untouched.
The plugin never executes commands and never writes to the remote server. It only reads.
Annotate a drift code block. The first line is target: alias:/absolute/remote/path; everything after it is the documented content that gets compared against the remote file:
```drift
target: gammastack-stfox:/etc/network/interfaces
auto eth0
iface eth0 inet dhcp
iface eth0 inet6 manual
```
Important: the opening
```driftfence must start at the beginning of the line (no leading spaces). An indented code block is rendered as plain Markdown in Reading view and the plugin will not process it.
An optional ignore: directive may follow the target line to override the global ignore settings for this block only. Recognized tokens are whitespace, comments, and none:
```drift
target: gammastack-stfox:/etc/nginx/nginx.conf
ignore: whitespace comments
worker_processes auto;
```
The block renders as a card with a status badge and two actions:
| Badge | Meaning |
|---|---|
| Not checked | The block has not been compared yet this session. |
| Checking… / Reading… | A read is in progress. |
| In sync | The note and the remote file match. |
| Drift · N lines | They differ; the inline diff shows what changed. |
| Error / Unknown alias / Invalid block | Something went wrong; the message explains what. |
The comparison is plain text diffing, line by line. There is no interpretation of what a config "should" mean, no AI involved, and no awareness of any specific config format (nginx, sysctl, network interfaces, and so on are all treated as plain text). The plugin is only as correct as what you wrote in the note: if you document the wrong thing, the plugin will faithfully tell you that the wrong thing does not match reality.
Two comparison options are available in settings, to cut noise on real config files:
#, ;, //) before diffing.These can be overridden per block with an ignore: directive on the line after target: (see Usage), so a noisy file can ignore comments while a strict file compares byte for byte.
Only text files are compared. A binary remote file is detected and reported as an error rather than shown as a meaningless diff.
A trailing newline at the end of the remote file (which the code block never has) is never reported as drift.
When there is drift, long runs of unchanged lines are collapsed into an expandable placeholder so only the changes and a little context are shown (configurable, and can be turned off).
Credentials are never stored inside a note. Each alias used in a code block (for example gammastack-stfox) refers to a connection profile configured once in the plugin settings:
| Field | Description |
|---|---|
| Alias | The name referenced from notes as target: alias:/path. |
| Host | IP address or hostname of the server. |
| Port | SSH port (default 22). |
| Username | SSH user to connect as. |
| Private key path | Path to a private key on this machine (~ is expanded). |
| Key passphrase | Only if the private key is encrypted. |
Notes only ever reference the alias, which keeps them safe to sync, share, or commit to version control.
Remote files are read over SFTP rather than by executing shell commands. This is a deliberate choice: an SFTP read can only read a file, it cannot run arbitrary code on the remote host, regardless of how the path or alias is manipulated.
Authentication is key-based only. Password authentication is not supported.
This plugin connects to remote servers and handles SSH credentials. Read this before using it.
.obsidian/plugins/config-drift-watcher/data.json inside your vault. Your notes only contain the alias. If you sync or publish your vault, be aware that data.json contains this connection data — exclude it (or the whole .obsidian folder) from anything public. A key passphrase, if you set one, is stored in data.json in plain text.ssh command does. The key itself is not copied into the vault.The host key is checked in this order: ~/.ssh/known_hosts first (when the Verify against known_hosts setting is on), then a pinned fingerprint, then trust on first use. If your host is already in known_hosts (plain or hashed entries), it is verified against that; otherwise the fingerprint is learned and pinned on first connect and shown in a notice. You can also verify or pin it manually:
The plugin's fingerprint format matches OpenSSH, so you can compare it with:
ssh-keygen -lf <(ssh-keyscan -t ed25519 your.host 2>/dev/null)
To pin strictly from the start, paste a known SHA256:… fingerprint into the profile's Host key fingerprint field before the first connection.
To re-trust after a legitimate server change, press Forget next to that field; the next connection learns the new key.
main.js, manifest.json, and styles.css from the latest release.config-drift-watcher inside <vault>/.obsidian/plugins/.If you use the BRAT plugin, add this repository (rixct/config-drift-watcher) to test pre-release builds before they reach the community directory.
npm install # install dependencies
npm run dev # watch build
npm run build # type-check + production bundle
npm test # run unit tests (parser, diff, snapshot, host key, known_hosts, collapse, binary)
The plugin bundles ssh2 and diff into a single main.js via esbuild.
Issues and pull requests are welcome. Before submitting a feature, open an issue describing the use case so the scope can be discussed first, since the plugin intentionally stays read-only and minimal in what it touches on the remote server.
MIT. See LICENSE.