P3-3: Wails v3 shell, system tray and sync daemon lifecycle #32

Open
opened 2026-09-10 17:43:41 +00:00 by Cordy · 0 comments
Owner

Depends on P3-2.

Goal

The application skeleton: a tray-resident process that runs the sync loop and opens a window on demand.

Files

  • Create: cmd/cairn-desktop/main.go, internal/app/app.go, internal/app/tray.go, frontend/ (index.html, CSS, TS)

Framework

Wails v3. Go backend, web frontend, native systray and menus, no bundled Chromium. Beta since 2026-08-02 with a stable desktop API.

Containment rule — this is the important part. Wails types must not leak past cmd/cairn-desktop/ and internal/app/. The engine, remote, vfs, state and config packages must remain framework-agnostic. If v3's GA slips or disappoints, swapping to Fyne or a plain systray-plus-webview must cost weeks, not the project. internal/sync/arch_test.go already forbids Wails there; keep it that way.

Behaviour

  • Tray-first. The app lives in the tray/menu bar. Closing the window hides it; it does not quit the process. Quitting is an explicit menu item. Every sync client works this way and users expect it.
  • Tray icon reflects state: idle · syncing · error · paused. Four distinct icons, legible at 16×16 in both light and dark menu bars.
  • Tray menu: status line ("Up to date" / "Syncing 3 of 12" / "2 conflicts"), Open folder, Open Cairn in browser, Pause/Resume, Settings, Quit.
  • Single instance. A second launch focuses the existing one instead of starting a second sync loop over the same folder. Two engines on one folder is a data-integrity hazard, not a UI annoyance — enforce it with a lockfile in the config directory.

Frontend styling

Reuse Cairn's existing design tokens so the client and the web UI look like one product:

--snow #f6f7f5   --surface #ffffff   --slate-900 #23272b
--slate-700 #3d444b   --slate-400 #8a939c   --lichen #e8ebe4
--glacier #2f7f8f   --glacier-deep #235f6b   --danger #a8543f   --ok #4a7a4e

Support light and dark, following the OS preference.

Steps

  • Scaffold the Wails v3 app; confirm it builds and runs on Linux.
  • Implement the tray with all four state icons and the menu.
  • Wire the engine into a background loop: watcher events (P3-2) plus periodic rescan, with pause/resume.
  • Implement single-instance locking, with a test for the second-launch path.
  • Commit: git commit -s -m "feat(app): Wails shell, tray, sync daemon lifecycle"

Acceptance criteria

  • The app runs from the tray; closing the window does not quit.
  • Icon state tracks the engine.
  • A second launch cannot start a second sync loop.
  • grep -r wails internal/sync internal/remote internal/vfs internal/state returns nothing.
Depends on P3-2. ## Goal The application skeleton: a tray-resident process that runs the sync loop and opens a window on demand. ## Files - Create: `cmd/cairn-desktop/main.go`, `internal/app/app.go`, `internal/app/tray.go`, `frontend/` (index.html, CSS, TS) ## Framework **Wails v3.** Go backend, web frontend, native systray and menus, no bundled Chromium. Beta since 2026-08-02 with a stable desktop API. **Containment rule — this is the important part.** Wails types must not leak past `cmd/cairn-desktop/` and `internal/app/`. The engine, remote, vfs, state and config packages must remain framework-agnostic. If v3's GA slips or disappoints, swapping to Fyne or a plain systray-plus-webview must cost weeks, not the project. `internal/sync/arch_test.go` already forbids Wails there; keep it that way. ## Behaviour - **Tray-first.** The app lives in the tray/menu bar. Closing the window hides it; it does not quit the process. Quitting is an explicit menu item. Every sync client works this way and users expect it. - **Tray icon reflects state:** idle · syncing · error · paused. Four distinct icons, legible at 16×16 in both light and dark menu bars. - **Tray menu:** status line ("Up to date" / "Syncing 3 of 12" / "2 conflicts"), Open folder, Open Cairn in browser, Pause/Resume, Settings, Quit. - **Single instance.** A second launch focuses the existing one instead of starting a second sync loop over the same folder. Two engines on one folder is a data-integrity hazard, not a UI annoyance — enforce it with a lockfile in the config directory. ## Frontend styling Reuse Cairn's existing design tokens so the client and the web UI look like one product: ``` --snow #f6f7f5 --surface #ffffff --slate-900 #23272b --slate-700 #3d444b --slate-400 #8a939c --lichen #e8ebe4 --glacier #2f7f8f --glacier-deep #235f6b --danger #a8543f --ok #4a7a4e ``` Support light and dark, following the OS preference. ## Steps - [ ] Scaffold the Wails v3 app; confirm it builds and runs on Linux. - [ ] Implement the tray with all four state icons and the menu. - [ ] Wire the engine into a background loop: watcher events (P3-2) plus periodic rescan, with pause/resume. - [ ] Implement single-instance locking, with a test for the second-launch path. - [ ] Commit: `git commit -s -m "feat(app): Wails shell, tray, sync daemon lifecycle"` ## Acceptance criteria - The app runs from the tray; closing the window does not quit. - Icon state tracks the engine. - A second launch cannot start a second sync loop. - `grep -r wails internal/sync internal/remote internal/vfs internal/state` returns nothing.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/cairn-desktop#32
No description provided.