Merge branch 'master' into feat/quickshell-dense-bar

This commit is contained in:
2026-09-18 20:43:46 +02:00
13 changed files with 552 additions and 4 deletions
+87
View File
@@ -430,6 +430,93 @@ another way in.
(via the `/mnt/jupiter` samba mount) before the first switch if you want
it preserved instead of starting clean.
### Obsidian vaults (jupiter CouchDB + mars bridge)
CouchDB itself is fully declarative (`services/dev/obsidian-livesync.nix`), but
three things are runtime state it cannot own.
**1. Each vault's database is created by the plugin.** Point Self-hosted
LiveSync at `https://notes.mgaction.town` (URI field) with the database name in
its own field — *not* as a path on the URI. Turn on End-to-End Encryption and
Obfuscate Properties **before the first sync**; both are remote-format
decisions and changing them later means converting or rebuilding the database.
The passphrase lives in the HomeLab Proton Pass vault, never in sops — it is
what keeps a publicly reachable database from being a readable one.
Database names must start with a lowercase letter (`a-z0-9_$()+-` after that).
An illegal name is rejected by neptun's matcher rather than CouchDB, and shows
up in Obsidian as a connection failure with **no error message at all**.
**2. luna's vault credentials on mars.** `hosts/mars/secrets.nix` needs two
values before mars will activate: `couchdb_luna_password` and
`obsidian_luna_passphrase`.
```
sops --set '["couchdb_luna_password"] "<password>"' secrets/mars.yaml
sops --set '["obsidian_luna_passphrase"] "<passphrase>"' secrets/mars.yaml
```
Keep both alphanumeric. sops substitutes into already-rendered JSON, so a `"`
or `\` in either produces an invalid `config.json`; the bridge logs
`Could not parse configuration!` and then runs on with **zero peers** instead
of exiting, which looks exactly like a bridge that is simply idle.
As set up today these are the `obsidian` admin password and the same
passphrase as the personal vault, which means mars — the box running an
autonomous agent — can decrypt and read every vault database. Optional
hardening, either half independently:
```
# password comes straight out of sops; never echo it
LUNA_PW=$(sops --decrypt --extract '["couchdb_luna_password"]' secrets/mars.yaml)
ADMIN=obsidian # prompts for the admin password
curl -u "$ADMIN" -X PUT http://jupiter.orbit.sol:5984/_users/org.couchdb.user:luna \
-H 'Content-Type: application/json' \
-d "{\"name\":\"luna\",\"type\":\"user\",\"roles\":[],\"password\":\"$LUNA_PW\"}"
curl -u "$ADMIN" -X PUT http://jupiter.orbit.sol:5984/luna_wiki/_security \
-H 'Content-Type: application/json' \
-d '{"admins":{"names":[],"roles":[]},"members":{"names":["luna"],"roles":[]}}'
unset LUNA_PW
```
then set `username` in `hosts/mars/livesync-bridge.nix` to `luna` and put that
account's password in `couchdb_luna_password`. Run it against jupiter over the
tailnet — `/_users` is blocked on the public vhost on purpose. A vault-specific
passphrase is the other half, changed in the plugin and mirrored into sops.
**3. The database name must match.** `database` in
`hosts/mars/livesync-bridge.nix` has to be exactly the name entered in the
plugin. A mismatch does not error — with an admin credential PouchDB simply
creates the misnamed database and replicates an empty vault into it.
Order matters: set the vault up from Obsidian first so the database exists and
carries the plugin's own tweaks, then deploy mars. Afterwards:
```
systemctl status livesync-bridge # on mars
cat /var/lib/livesync-bridge/health.json # per-peer ok/backendUp/detail
ls /var/lib/livesync-bridge/vault # her notes, as real markdown
```
The vault is mounted into the agent container at `/opt/data/vault`, inside
`HERMES_WRITE_SAFE_ROOT`, so luna can write as well as read.
A note luna writes reaches CouchDB as soon as the bridge sees it, but whether
it then reaches your devices depends on that vault's **Sync Mode** in the
plugin. Only "LiveSync (real-time)" pulls continuously; the periodic/on-save
presets need their timer or a manual **Replicate**. A file that appears only
after clicking Replicate is the client waiting, not the bridge failing — the
database already had it. Check the bridge's own side in the journal:
```
journalctl -u livesync-bridge | grep -- '--> luna-remote'
```
⚠️ **Verify her writes actually land before trusting this.** Upstream has three
open issues on the storage→CouchDB direction (#50, #23, #46) and all fail
silently — the log reports the upload and the database never updates. Create a
note as luna, confirm it appears on a phone, and re-check after any input bump.
### mercury (Raspberry Pi 3B+)
- `./deploy flash mercury /dev/sdX` writes the dedicated age key to the root