Skip to content

Desktop application

Terminal retirement — local implementation, 2026-10-20

Section titled “Terminal retirement — local implementation, 2026-10-20”

The current working tree removes interactive terminals and Redis while preserving command/script Remote Actions and authorized session/transcript history with existing retention. Admin has a read-only history viewer; Core advertises no terminal capability and legacy terminal operations cannot create work. This implementation is local and awaits user testing; older published implementation descriptions below remain historical. See the retirement plan and evidence.1

Since ADR-024 MonStaff ships one desktop application built from three Rust and TypeScript parts.23

  • apps/monstaff-core: the single-instance per-user runtime. It owns the protected session and installation identity, backend transport, timer and collector-lease ownership, monitoring collectors, durable encrypted queues, agent telemetry sidecar, Device Compliance, Local AI pack lifecycle and gated command/script Remote Actions capability. It exposes an authenticated, versioned local protocol defined in crates/monstaff-core-protocol.
  • apps/desktop (Tauri 2, React, shadcn/ui): a presentation adapter. Its Rust side exposes presentation commands that start, discover and bridge the Core; every domain state transition is a Core command.
  • apps/monstaff-cli (monstaff): an interchangeable command-line client over the same protocol through crates/monstaff-core-client.

Hiding the GUI window or exiting the CLI is not Core shutdown: active timers, collectors, delivery queues and agent sessions survive the disconnect. Quitting the GUI (tray “Quit MonStaff”, Cmd+Q, Dock “Quit”) is different: the Tauri exit handler stops the running timer through the Core and then requests a Core shutdown, bounded in time and without ever starting a Core. Without a pending update, the Core keeps its safe-stop rule and stays alive when agent capture, remote actions are active or when the backend cannot confirm the timer state. Pending updates can first quiesce MonStaff telemetry as described below.45 Exactly one implementation owns each native capability.

The Electron/Svelte client and the TypeScript agent-cli were removed on 2026-09-05; their last release is tag v0.2.43.6

The native Tauri shell checks for signed app updates at startup and every 30 minutes, downloads and verifies them in the background, and retries failures after 5 minutes. The renderer only displays status and can request a check. Hiding the window does not interrupt this work.7

Full application quit installs a verified pending package after stopping the timer, preparing and shutting down the Core, waiting for its cleanup and acquiring its runtime lock. The application stays closed; the next launch runs the new version. Protected work, failed shutdown, timeout or an incomplete download defers installation. Pending bytes are held in memory, so an interrupted session downloads again on a later launch. Since .38, preparation gracefully pauses MonStaff telemetry and preserves its target/queue for restart. Signed .38 → .39 installation on Cmd+Q with active telemetry passed on macOS Apple Silicon; other platforms, active-timer transitions and privilege-dependent installer behavior remain outside that live verification.75

  1. Authenticate and select a project/work item, or choose Automatic when the agent bridge is capturing for an organization.8
  2. Start a backend time entry; the Core acquires the server-owned tracking collector lease.
  3. Start native aggregate-input and foreground-application collection in the Core.
  4. Capture optional screenshots, upload by presigned URL and register metadata.
  5. Detect idle periods and ask whether to keep, discard or stop.
  6. Stop the entry and flush activity and app usage.
  7. Persist failed network operations in the encrypted queue for lease-fenced retry.

Published in 0.3.26 on 2026-09-08: one idle notification is attempted per unresolved suppression, independently of the changing compatibility generation and refreshed session objects. A confirmed resolution rearms notifications for a later idle period; transient read failures do not resend the same alert. Clicking the native notification restores and focuses the MonStaff dashboard, where the idle decision remains available. Dismissing the system notification does not resolve the idle period. Desktop tests, remote Quality, release, GKE deployment and promotion pass; public updater/download manifests and downloaded artifact hashes were verified. Installed-package qualification passed for macOS Apple Silicon, while an actual installed notification click remains unverified.910

The desktop distinguishes the current user’s assigned open work across active projects from all open work in one selected project. Selecting a project switches to the project-scoped view; clearing it returns to the assigned view. Project lists are paginated and use the backend’s canonical lifecycle-state filter.11

The screenshot gallery applies server-side temporal filters, page-scoped selection and confirmed single or bulk deletion while the backend keeps per-screenshot ownership checks and the pending-deletion reconciler.12 Thumbnails and the viewer receive JPEG bytes from the Core over IPC and display them as blob: URLs, which the Tauri Content Security Policy must allow for img-src; the viewer fills the window, zooms relative to the fitted size (0.5x to 8x) with scrolling and drag-to-pan, and toggles the window’s full-screen mode through the Tauri window API under the core:window:allow-set-fullscreen capability.13

Session tokens, the per-user Ed25519 installation key and Local AI metadata live in the Core behind the operating-system credential store. Queued requests persist encrypted bounded bodies without bearer headers, execute single-flight and carry idempotency keys. Downloaded packs are digest-addressed files verified again before execution.3

GitHub sign-in ends with the backend redirecting the browser to monstaff://auth/callback, which the GUI receives through the deep-link plugin and completes on the Core. On macOS the scheme is also declared by the retired Electron client (com.monstaff.app) and by any stale copy of it still registered with Launch Services, and the deep-link plugin cannot register at runtime there, so the Tauri application claims the scheme for its own bundle identifier in the setup hook (url_scheme::ensure_default_handler) whenever the recorded default is missing or belongs to another bundle. The claim is defensive and never blocks startup; it does not uninstall the Electron application.14

The Core runs the loopback agent sidecar in serve and hook modes, detects installed Claude Code and Codex clients, installs or repairs MonStaff-owned lifecycle hooks, obtains one short-lived grant per client and exports partitioned, grant-bound batches. Hooks capture only finalized visible chat fields, redacted and byte-bounded before encrypted local persistence.3

The sidecar keeps a policy-filtered, locally persisted model of the sessions, turn intervals and provider-observed usage it accepted and serves it on the authorized loopback GET /live; the Core exposes it as GetAgentLiveStatus and the CLI as monstaff agent live. The GUI’s Agent Telemetry page shows this live view only; the bridge status and its actions (detect and repair, context lock, disable) sit on the Setup page next to the per-client hook rows, where the product owner placed them on 2026-09-06.15 The page derives the live agent effort, the open inter-turn wait, the day’s sum of closed waits above the threshold (shown as a separate “closed total today” row that never includes the open tail)16 and the day’s token totals from those facts with deriveAgentLiveState from @monstaff/shared, the same function the backend analytics use. Claude Code hooks read the session transcript from a private per-session byte cursor to emit usage facts; Codex and Pi report none. Context precedence for attribution is the explicit lock, then the running timer’s project (FOREGROUND_TIMER, written by the Core on timer start, restore and stop), then unresolved.17

The live facts are saved in a private encrypted snapshot before event acceptance and restored before bridge readiness. This preserves the day’s closed wait total, session facts and observed usage through process restart and routine grant renewal, independently of export acknowledgements. Restore is scoped to the same user, installation and organization, filters currently authorized effort-enabled clients, and prunes facts older than 48 hours. Missing snapshots start empty; corrupt or unauthenticated snapshots fail explicitly. Existing local size limits, reporting-day boundaries and open-tail exclusion remain; previously lost history is not backfilled. This persistence is verified locally and has not yet been packaged.18

The protocol lives in crates/monstaff-core-protocol; the GUI and CLI consume it through crates/monstaff-core-client. GUI renderer code receives only the Core bridge, never process, collector, key or filesystem primitives. See the Core protocol reference.

The desktop offers “Automatic · via telemetry” when agent capture supplies an organization. The Core verifies this readiness and the backend verifies membership and telemetry policy. The timer records developer time without selecting a project; interval-based agent accounting allocates it after stop and leaves insufficient evidence as “Unattributed”. Loss of telemetry does not stop an existing timer. The existing manual project mode remains available. History exposes whole-allocation project corrections; manual corrections create revisions and stop automatic overwrites for that session. This is implemented locally and awaits migration/deployment.8

Final local verification: 112 desktop unit tests, 199 backend unit tests and 48 integration tests passed. A global boundary check remained open for concurrent tray-wait work; release is still pending.19

Implemented locally on 2026-09-08: the existing M is split vertically, with a rising yellow/orange/red fill for the current wait on the left and closed daily waits on the right. One GUI-root live hook supplies both the tray and the telemetry card, using the unchanged shared reducer. The current half resets on a new counted turn; the daily half resets at local day rollover. A stopped timer, unavailable capture/settings or disabled indicator restores the monochrome template. The tooltip includes both values and their independent maxima.20

Organization policy defaults are 10 minutes/current and 60 minutes/day, configurable from 1 to 1440 minutes in Admin. A typed Core read refreshes the settings every sixty seconds. Background throttling is disabled on supported macOS versions; installed hidden-window and cross-platform qualification remain pending. This is repository-local implementation, not a published release.20

The dual-wait tray and projectless automatic tracking changes are now published in desktop 0.3.24, with successful exact-commit Quality, GKE backend/Admin deployment, release and promotion. Public updater/download manifests and downloaded DMG/CLI hashes were verified. Signed Apple Silicon installed-package qualification passed; extended live-feature and hidden-window checks remain separate. This supersedes the repository-local deployment-pending statements in the implementation snapshots.21

Automatic start entrypoint correction (2026-09-08)

Section titled “Automatic start entrypoint correction (2026-09-08)”

Implemented locally after 0.3.24: the dashboard waits for telemetry readiness and defaults to Automatic when capture supplies an organization, preserving the choice on later refreshes. The tray enables ordinary start without a selected project when automatic tracking is available and adds a localized “Start automatically” action that bypasses a previous project choice. Busy, signed-out and already-running states cannot start another timer. No backend migration is needed for this correction. Verified with 117 desktop tests and 19 native tests; desktop release pending.22

Active-session filter — implemented locally 2026-09-08

Section titled “Active-session filter — implemented locally 2026-09-08”

The desktop Agent Telemetry session list offers a persistent “Only active” / “Solo attivi” switch, initially disabled. It shows sessions with an open turn (activeTurnStartedAt), excluding idle and ended sessions, with a dedicated empty state. Daily statistics keep their existing scope. English/Italian catalogs, desktop typecheck and existing telemetry tests pass; release remains pending.23

The automatic-start correction and active-session filter described above are now published together with the idle notification fix in 0.3.26. This supersedes their earlier release-pending statements. All release and deploy workflows succeeded on the exact release commit; the signed Apple Silicon package passed installed qualification.10

Implemented locally for 0.3.27: GetAgentLiveStatus responses have a dedicated 8 MiB client budget; requests and ordinary responses retain 128 KiB. GUI and CLI share both declared-length and streamed-byte checks. Live history is transferred intact. On read failure the desktop shows a localized retry notice instead of empty/zero activity, and recovers automatically. The new CLI successfully read the installed Core’s history that 0.3.26 rejected. Wire format and protocol version remain unchanged; publication is pending.24

Desktop 0.3.27 is published from 3e53752: Quality, signed release, promotion and GKE deployment succeeded. Public manifests and downloaded DMG/CLI hashes and sizes were verified; signed Apple Silicon installed-package qualification passed. This delivers the agent live-response repair and supersedes its local-only release status. The new GUI has not been verified on the user’s installation.25

Implemented locally after 0.3.27: Recent Projects shows up to five distinct active, accessible projects from the signed-in user’s time entries, newest work first, including the running timer. A project edit or a form selection does not make it recent. The Core reads the full-history backend aggregation; successful local starts immediately update the menu. An unavailable read leaves recents empty.26

Recent Projects, Projects and Work items remain selectable while tracking. A different project stops the current timer and starts the chosen project without a work item; a work-item choice switches to that explicit target, including “No work item”. Selecting the running project or exact current work item keeps the timer unchanged. With no timer, selections only prepare the next Start. A shared mutation guard prevents overlapping GUI changes; failure to stop prevents a new start, while failure to start leaves the timer stopped and surfaces an error. The switch uses sequential stop/start calls and existing collector-lease handling. Local tests passed; backend deployment and desktop/Core publication remain pending.26

Implemented locally on 2026-09-08: a single enlarged M spans the right-hand side of the Start/Stop Working and Show Timer rows, using the same independent colored wait levels as the menu bar. Each half has its own localized tooltip: current wait/reset on the left, today’s closed waits/midnight reset on the right. Image and tooltip updates reuse the menu rows. The image area is informational; native timer actions remain on the text area. Optional automatic start follows the two header rows. The user accepted the isolated preview visually; release and installed interaction qualification remain pending.27

Input activity repair — implemented locally

Section titled “Input activity repair — implemented locally”

The native listener now runs in the macOS default mode and reports capability loss on an unexpected loop exit. The backend derives activity from persisted observed seconds under a per-entry transaction lock, preserving contributions across quiet, duplicate, reordered and concurrent batches. The real OS dispatch regression detects the original defect; database integration passes. This supersedes the implementation-open part of the September 8 diagnosis; published and installed live verification are still pending. Previously absent input events cannot be reconstructed.28

Input activity 0.3.30 — published and verified live

Section titled “Input activity 0.3.30 — published and verified live”

Version 0.3.30 is published from 2c00d47 with all tag-bound Quality, release and promotion jobs successful. The cumulative backend 34598db is deployed with two healthy updated replicas. A signed/notarized Apple Silicon DMG was installed locally after the old updater downloaded but deferred installation; GUI and Core report 0.3.30 and existing input permissions remain granted. Real input counters now reach production. Live aggregation matched 54% from 298/550 observed seconds despite a latest 100% batch; a later latest-zero batch retained the correct 42% from 332/780. Timer context and agent capture were restored, with no pending delivery queue. This closes the activity incident’s release/live gates, while historical missing events remain unrecoverable and the separate updater deferral is not fixed here.29

This release also delivers the inherited tray/menu and personal recent-project changes from 8004da0; the prior release-pending statements for those changes are superseded by the publication evidence above.

macOS update correction — published and verified 2026-09-09

Section titled “macOS update correction — published and verified 2026-09-09”

Installed .32 skipped installation on native Cmd+Q because the framework bypassed the normal exit request. The published AppKit adapter routes native quit through the safe update sequence. Installed .36 then exposed a second blocker: restored telemetry remained active and prevented update preparation. Since .38, preparation gracefully pauses MonStaff telemetry while retaining its configured target and durable queue; timer/remote/unknown blockers and unsuccessful or timed-out shutdown still defer installation. Normal quit without a pending update retains its existing protected-work policy.3031

The signed .38 → .39 transition passed on the user’s macOS Apple Silicon installation with Codex/Claude telemetry active and no running timer: startup downloaded .39 automatically, Cmd+Q installed it without manual telemetry intervention, GUI/Core remained closed, and relaunch showed .39 with capture restored and configuration unchanged. Signature, trust and official executable hash checks passed. This supersedes the earlier pending outgoing-update qualification for this case; other platforms and interruption/elevation scenarios are not covered.5

  1. Local interactive-terminal and Redis retirement. ↩

  2. Single Rust desktop client (ADR-024) ↩

  3. MonStaff Core, CLI and Tauri convergence evidence ↩ ↩2 ↩3

  4. Desktop quit stops the timer and shuts the Core down ↩

  5. Signed macOS automatic update verified end to end. ↩ ↩2 ↩3

  6. Desktop client coexistence baseline ↩

  7. Automatic desktop download and installation on quit. ↩ ↩2

  8. Projectless automatic developer tracking implementation ↩ ↩2

  9. Idle notification deduplication and dashboard activation ↩

  10. Desktop 0.3.26 publication and GKE deployment ↩ ↩2

  11. Desktop work-item visibility repair. ↩

  12. Desktop screenshot library temporal filtering and bulk deletion. ↩

  13. Desktop screenshot gallery CSP repair and viewer zoom evidence ↩

  14. Desktop GitHub login callback delivered to the retired Electron client ↩

  15. Desktop agent bridge card moved to the Setup page ↩

  16. Agent telemetry desktop inter-turn wait day sum implementation ↩

  17. Agent telemetry desktop live statistics implementation ↩

  18. Agent live statistics restart persistence ↩

  19. Projectless automatic tracking final local verification ↩

  20. Dual inter-turn wait tray indicator implementation. ↩ ↩2

  21. Desktop 0.3.24 publication and GKE deployment. ↩

  22. Automatic start dashboard and tray correction ↩

  23. Desktop agent telemetry active-session filter ↩

  24. Agent live response limit diagnosis and repair. ↩

  25. Desktop 0.3.27 publication and GKE deployment. ↩

  26. Recent worked projects and active timer tray switching ↩ ↩2

  27. Enlarged macOS tray menu wait icon and separate half tooltips ↩

  28. Implementation and regression evidence. ↩

  29. Published release and installed live evidence. ↩

  30. macOS native quit updater diagnosis and correction. ↩

  31. Signed updater verification and telemetry quiescence. ↩