Miru Time Tracking is a local-first macOS menu bar app for employees who need a fast, focused way to track work in Miru. It keeps the timer visible in the system menu bar, opens into a compact desktop tracker, and syncs the current timer with Miru web when an account is connected.
Built from LuanRoger/electron-shadcn with Electron Forge, Vite, React, TypeScript, Tailwind, TanStack Router, Vitest, and Playwright.
Miru Time Tracking is MIT-licensed software.
- Miru web app: https://app.miru.so
- Miru product site: https://miru.so
- Miru web source: https://github.com/saeloun/miru-web
- Desktop source: https://github.com/saeloun/miru-time-desktop
These screenshots are generated from the packaged Electron app flow used by the integration specs: signed-in timer, account/sync menu, idle recovery, and a sanitized profile-avatar preview. The avatar preview uses generic local work data and does not expose email, tokens, workspace, client, project, or entry details.
Latest release: https://github.com/saeloun/miru-time-desktop/releases/tag/v0.1.8
- Native macOS menu bar timer with a stable-width time label and stateful tray icon colors for ready, running, paused, and idle.
- Compact time tracker window positioned below the menu bar, with high-contrast timer controls, fixed-width icon dock, and a Miru-styled command surface.
- Local-first tracking through renderer local storage plus persisted Electron
userDatatimer state, so timers survive app relaunches. - Resumable timer stack so starting a new timer keeps the previous timer available to resume or remove.
- Timesheet drill-down from Today, This week, and Entries summary cards into detailed time entries.
- Miru account bridge for login, signup handoff, logout, workspace switching, current timer pull/push, and saving, editing, or deleting time entries.
- Current timer sync with Miru web through
GET/PUT /api/v1/desktop/current_timer, including multiple desktop timer states. - Idle recovery with a custom in-app modal: trim and continue, trim and restart, or keep idle time.
- Employee-focused UI with no billing, rates, invoice, admin, or dashboard surfaces.
- Profile-aware settings showing the Miru user avatar when available, workspace, sync status, idle threshold, and locale.
- Miru locale support that reads
user.localeor user settings first, then falls back to stored/browser locale and English strings. - Integration coverage for the desktop timer, tray title, idle recovery, persistence, account menu behavior, and locale rendering.
The app intentionally behaves like a small desktop utility, not a full web dashboard.
- The first screen is login/signup when no Miru session exists.
- The primary surface is the timer, project/task notes, summary, and timesheet entries.
- Account and sync controls live in a focused popover from the profile button.
- The tray icon carries state visually; the tray title stays width-stable to avoid menu bar jitter.
rtk mise exec -- bun install
rtk mise exec -- bun run startThe app opens an Electron window and creates a macOS menu bar item. During normal development it stores app data in Electron userData.
Production builds connect to Miru web at https://app.miru.so by default and do not show a Miru URL field in the sign-in flow.
Useful development overrides:
MIRU_API_BASE_URL=http://127.0.0.1:3000 rtk mise exec -- bun run start
MIRU_SHOW_BASE_URL_FIELD=true rtk mise exec -- bun run start
MIRU_ALLOW_BASE_URL_OVERRIDE=true rtk mise exec -- bun run startMIRU_API_BASE_URL changes the default API host. MIRU_SHOW_BASE_URL_FIELD exposes the sign-in URL field. MIRU_ALLOW_BASE_URL_OVERRIDE lets the main process honor stored or submitted custom hosts.
Use Node 24, matching CI.
rtk mise exec -- bun install
rtk mise exec -- bun run check
rtk mise exec -- bun run test
rtk mise exec -- bun run packagebun run package creates an unpacked macOS app under out/. bun run make creates distributable release artifacts under out/make/.
Portable ZIP builds for release:
rtk mise exec -- bun run make:mac:release
rtk mise exec -- bun run make:mac:release:apple
rtk mise exec -- bun run make:mac:release:intel
rtk mise exec -- bun run make:linux
rtk mise exec -- bun run make:windowsUse make:mac:release for public macOS ZIPs; it enables the release-only Forge signing and notarization path. See Release Checklist for the required Apple certificate and notarization environment variables.
rtk mise exec -- bun run check
rtk mise exec -- bun run test
rtk mise exec -- bun run test:e2e
rtk mise exec -- bun run packageUseful full release check:
rtk mise exec -- bun run check
rtk mise exec -- bun run test
rtk mise exec -- bun run test:e2e
rtk mise exec -- bun run make
rtk mise exec -- bun auditThe Playwright Electron specs launch the packaged app in a temporary profile so tests do not touch your real timer or Miru session.
Package the macOS app:
rtk mise exec -- bun run packageOpen the packaged app:
open "out/Miru Time Tracking-darwin-arm64/Miru Time Tracking.app"Install it into /Applications:
ditto "out/Miru Time Tracking-darwin-arm64/Miru Time Tracking.app" "/Applications/Miru Time Tracking.app"
open "/Applications/Miru Time Tracking.app"Build a distributable ZIP:
rtk mise exec -- bun run makeThe ZIP is generated under:
out/make/zip/darwin/arm64/
Renderer calls are exposed through window.miruApi:
login,signup,logoutswitchWorkspacesyncCurrentTimer("pull" | "push")saveTimerEntry,updateTimerEntry,deleteTimerEntry
The main process owns API calls, local account persistence, timer persistence, tray updates, and offline fallback. Email/password login completes a desktop session today. Signup returns users to the login form after Miru creates the account, and Google opens Miru web sign-in until Miru web exposes a native desktop token callback. See Sync strategy for the API contract and conflict rules.
See Integration specs for the current e2e coverage.
Covered flows include:
- Signed-out onboarding.
- Shared desktop timer behind the renderer.
- Native tray title and icon state.
- Idle recovery actions.
- Timer hero layout guard so elapsed time and controls do not overlap.
- Start-new-timer and paused timer resume flows.
- Timer context persistence across relaunch.
- Account menu close/logout behavior.
- Miru user locale rendering.
- RTL locale layout.
- Live timesheet history, date switching, and summary-card drill-down.
- Miru current timer push/pull with multiple timer states.
- Run
rtk mise exec -- bun run check. - Run
rtk mise exec -- bun run test. - Run
rtk mise exec -- bun run test:e2e. - Run
rtk mise exec -- bun run make:mac:release. - Open the packaged app and confirm the Miru icon, tray timer, account popover, and idle modal render correctly.
- Publish the generated ZIP manually or run
rtk mise exec -- bun run publishwhen ready for a draft GitHub release.
Additional release notes live in Release checklist.


