Turn the desktop client into a system tray application

Started without a command, keeporg now shows a padlock in the system tray
with a menu like midi-webhook's: a status line, the mirror folder, each
database with its state, Sync Now, browser sign-in and sign-out, the web
interface, the configuration, the log, Start at Login, About and Quit. The
commands are unchanged.

config.json now carries every client setting (device_label,
request_timeout_seconds, ca_file, log_file, notifications), is written in
full on first start and is reloaded by the tray when saved.

A lock in the mirror directory admits one agent at a time, since the tray,
`keeporg run` and a service unit could otherwise race each other.

The tray uses fyne.io/systray: pure Go on Linux, BSD and Windows, cgo on
macOS only. The server keeps no third-party dependencies.

Desktop versions go to 0.5.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Reactorcoremeltdown
2026-11-02 12:30:28 +01:00
co-authored by Claude Opus 5.5
parent d314188247
commit ead82dc777
37 changed files with 2301 additions and 108 deletions
+51 -8
View File
@@ -18,15 +18,18 @@ keep their key off the server entirely, exactly as before.
with a tree of user groups, accepts registrations by invite link or OIDC,
merges concurrent edits, and pushes updates to connected clients. Its web
page at `/web` is for creating a vault and setting its password.
- **Desktop client** (`keeporg`, Linux, macOS, Windows, BSD): mirrors every
assigned database into one directory as a real file, pushes each save and
applies what others push.
- **Desktop client** (`keeporg`, Linux, macOS, Windows, BSD): a system tray
application that mirrors every assigned database into one directory as a
real file, pushes each save and applies what others push. The same binary
is the command line for administration and for headless machines.
- **Android client**: the same, published to every file picker as a storage
provider.
No third-party dependencies, no cgo, no FUSE. The KDBX 4 codec, including
ChaCha20, BLAKE2b and Argon2, is part of the repository and is tested against
both the relevant RFCs and a real KeePassXC.
No FUSE, and the server has no third-party dependencies and no cgo. The
KDBX 4 codec, including ChaCha20, BLAKE2b and Argon2, is part of the
repository and is tested against both the relevant RFCs and a real
KeePassXC. The desktop client's one dependency is `fyne.io/systray`, for the
tray icon.
## Quick start
@@ -41,13 +44,53 @@ KEEPORG_ADMIN_PASSWORD=dev-password-1 make run-server
build/linux-arm64/keeporg login -server http://127.0.0.1:8765 -user admin
build/linux-arm64/keeporg groups
build/linux-arm64/keeporg vault -create "Team Vault" -group <group-id>
build/linux-arm64/keeporg run
build/linux-arm64/keeporg # the tray; `keeporg run` without a desktop
```
`Team Vault.kdbx` appears in `~/KeepOrg`; open it in KeePassXC with the vault
password you just set. Every save is pushed, and a save that races with a
colleague's is merged rather than refused.
## The tray
Started without a command — from the applications menu, the DMG's
`KeepOrg.app`, or `keeporg-tray.exe` on Windows — the client puts a padlock
in the system tray:
| Item | What it does |
| --- | --- |
| *status line* | signed-in account and whether everything is up to date, or what needs attention |
| **Open Mirror Folder** | the directory holding the `.kdbx` files |
| **Databases ▶** | each database with its state; choosing one opens it in your KeePass application |
| **Sync Now** | reconcile immediately instead of at the next rescan |
| **Sign In… / Sign Out** | sign in by approving a code in the browser (password, second factor or SSO); sign out revokes the session and leaves the files |
| **Open Web Interface** | `/web` on the server, for creating vaults and managing access |
| **Open Config** | the settings file; a saved edit applies at once |
| **Open Log** | the agent's log |
| **Start at Login** | LaunchAgent on macOS, XDG autostart on Linux and BSD, the Run key on Windows |
| **About**, **Quit** | |
Conflicts, merges and failures raise a desktop notification.
## Configuration
`config.json` in the user configuration directory
(`~/.config/keeporg`, `~/Library/Application Support/keeporg`,
`%AppData%\keeporg`) holds every client setting. The first start writes it
in full, and the tray reloads it when it is saved.
| Key | Default | Meaning |
| --- | --- | --- |
| `server_url` | | the server's base URL, as a browser sees it |
| `username`, `token` | | written by signing in |
| `device_label` | host name | this device in the server's session list |
| `mirror_dir` | `~/KeepOrg` | where the `.kdbx` files are kept; `~` is expanded |
| `poll_seconds` | `2` | how often local saves are looked for |
| `request_timeout_seconds` | `60` | the limit on one API request (the event stream is exempt) |
| `ca_file` | | a PEM bundle trusted besides the system roots, for a private CA |
| `log_file` | | the log; empty means `keeporg.log` beside the config for the tray, standard error for `keeporg run` |
| `notifications` | `true` | desktop notifications from the tray |
Or open `http://127.0.0.1:8765/web` and create the vault from the browser.
## Packaging
@@ -56,7 +99,7 @@ Or open `http://127.0.0.1:8765/web` and create the vault from the browser.
make deb # Debian packages for the client and the server
make docker # server container image, scratch-based, about 9 MB
make dmg # macOS disk image with an /Applications symlink (on macOS)
make windows # Windows zip with a Task Scheduler job
make windows # Windows zip: keeporg-tray.exe, keeporg.exe and a Task Scheduler job
make android # unsigned release APK (needs the Android SDK)
make help # every target
```