LazyTime is an automatic, rule-driven time tracking assistant. It watches your active window title/app, maps that to projects using your rules, and keeps trackings up to date.
- Install/build
lazytimeand run it:
lazytime-
By default, LazyTime starts the native GUI (built with
egui/eframe). On startup it also auto-starts the daemon (if no daemon is already running outside the GUI), so it works out of the box. -
On first run, an onboarding wizard walks you through working hours, your first project/rule, and optional Jira setup.
-
The GUI has a sidebar with these views:
- Current - active tracking, today's total, daemon state.
- Trackings - list/edit of recorded trackings.
- Visual Day - a Gantt-style timeline of the selected day; trackings are colored bars per project that you can drag to move and resize to adjust start/end times.
- Projects - manage projects, colors, and matching rules.
- Jira - interactive Jira sync controls/logs.
- Daemon - daemon status/controls.
- Settings - appearance, general, working hours, Jira config.
Recent changes (undo/redo per view: trackings, visual day, projects) can be reverted from the toolbar.
-
Add your projects/rules in the
Projectsview so window activity can be mapped automatically.
Prefer a terminal UI instead? Run lazytime --tui (see For developers / alternate modes below); it exposes the same core views with keyboard shortcuts.
A config file is created automatically on first run if it does not exist.
- Use a custom config file with
--config /path/to/config.json. - Core settings include default project, DB path, reminders, report range, Jira config, and IPC endpoint override.
| Key | Type | Default | Required | Description |
|---|---|---|---|---|
default_project |
string |
"Default" |
Yes | Fallback project name used when no rule matches. Must be non-empty. |
tracking_stability_seconds |
u64 |
60 |
No | Minimum seconds before daemon auto-switches an already running tracking to a newly detected project. |
working_hours |
object |
{} |
No | Map of weekday (0..6, Monday=0) to time ranges. Reminders are only due inside these ranges. |
track_reminder_seconds |
u64 |
300 |
No | Delay before asking again after choosing No in reminder popup. |
track_reminder_snooze_seconds |
u64 |
1800 |
No | Snooze duration for reminder popup and manual stop auto-tracking snooze window. |
summary_update_seconds |
u64 |
5 |
No | Refresh interval for lazytime --summary --watch. |
report_start |
string | null |
null |
No | Default report start date (YYYY-MM-DD) when --report is used without --start. |
report_end |
string | null |
null |
No | Default report end date (YYYY-MM-DD) when --report is used without --end. |
db_file |
string |
OS-dependent data path | Yes | SQLite database file path. Parent directories are created automatically. |
jira_url |
string | null |
null |
No | Jira base URL (for example https://your-company.atlassian.net). |
jira_token |
string | null |
null |
No | Jira API token used for sync requests. |
jira_email |
string | null |
null |
No | Jira account email used with token auth. |
jira_project |
string | null |
null |
No | Default Jira project key for auto-created issues/worklogs. |
jira_assignee |
string | null |
null |
No | Default Jira assignee for created issues (account id / username, depending on Jira setup). |
jira_issue_type |
string |
"Story" |
No | Jira issue type used when creating issues. |
jira_sap_field |
string |
"sap_project" |
No | Jira custom field key used to store SAP/project mapping metadata. |
ipc_socket_path |
string | null |
null |
No | IPC endpoint override. Unix socket path when ipc-unix; host:port when ipc-tcp. |
working_hours value format:
| Field | Type | Description |
|---|---|---|
working_hours.<weekday> |
array |
List of active time ranges for that weekday (0=Mon ... 6=Sun). |
working_hours.<weekday>[].start |
"HH:MM" |
Range start (24h). |
working_hours.<weekday>[].end |
"HH:MM" |
Range end (24h). |
-
Linux (default)
- Config:
~/.config/lazytime/config.json - Data DB:
~/.local/share/lazytime/lazytime.db - IPC (when
ipc-unix):~/.local/run/lazytime.sock(oripc_socket_pathoverride)
- Config:
-
macOS
- Config:
~/Library/Application Support/lazytime/config.json(or fallback~/.config/lazytime/config.json) - Data DB:
~/Library/Application Support/lazytime/lazytime.db(or fallback~/.local/share/lazytime/lazytime.db) - IPC (recommended): TCP loopback, e.g.
127.0.0.1:43123whenipc-tcpenabled
- Config:
-
Windows
- Config:
%APPDATA%\lazytime\config.json - Data DB:
%LOCALAPPDATA%\lazytime\lazytime.db - IPC (recommended): TCP loopback, e.g.
127.0.0.1:43123whenipc-tcpenabled
- Config:
Notes:
- Paths come from OS-standard directories when available (
dirscrate). - If
db_fileis set in config, that path is used. - If
ipc_socket_pathis set in config, that endpoint is used.
Automatic tracking depends on project rules. First-time setup (GUI):
- Open LazyTime:
lazytime - Go to the
Projectsview in the sidebar. - Add a project (name + optional color; a deterministic color is generated if you skip one).
- Add one or more rules for that project (app + title regex).
Rule behavior summary:
- Rules map
(app_id, title regex)to a project. app_id == "*"means title-only fallback rule (match any app by title).- If no rule matches, LazyTime uses your configured default project.
The same setup is available in the TUI's Projects view (p, then a to add a project).
In normal usage:
- The daemon listens for active-window changes and lock/unlock events.
- On window change, LazyTime detects project from rules and starts/switches tracking.
- On lock, active tracking is paused; on unlock, resume options are offered.
- Automatic tracking only runs within your configured
working_hours; outside those hours the status bar shows "autotracking paused". - In the
Currentview you can start/stop tracking manually; inVisual Dayyou can drag/resize a tracking's bar to adjust its start/end time directly (changes are validated against overlaps and committed on drop). - In the TUI's Current view:
sstarts tracking manually,dstops current tracking.
LazyTime can sync finished trackings to Jira.
- Configure Jira fields either in the GUI (
Settings->Jiratab) or directly inconfig.json(jira_url, token, email, project, etc.). - Use the GUI's
Jiraview, or the TUI's Jira view (j), for interactive sync controls/logs. - Or run a one-shot sync from the CLI:
lazytime --jira-synclazytime-> start GUI (default)lazytime --tui-> start TUI insteadlazytime --daemon-> daemon onlylazytime --summary-> print today summarylazytime --summary --watch-> continuously refresh summarylazytime --report --start YYYY-MM-DD --end YYYY-MM-DD-> report rangelazytime --waybar_state-> one JSON line for waybar
LazyTime stores a daemon runtime lock in SQLite (config_store.key = "daemon_runtime_lock") to avoid duplicate daemon instances. If a daemon crashes, lock cleanup might be skipped.
- Confirm no daemon process is running:
pgrep -af "lazytime.*--daemon"- Inspect lock row:
sqlite3 ~/.local/share/lazytime/lazytime.db "SELECT key, value, last_updated FROM config_store WHERE key='daemon_runtime_lock';"- If no daemon is running, remove stale lock:
sqlite3 ~/.local/share/lazytime/lazytime.db "DELETE FROM config_store WHERE key='daemon_runtime_lock';"- Start
lazytimeagain.
On Windows, run the same SQL against %LOCALAPPDATA%\lazytime\lazytime.db with your SQLite client.
- GUI code (default UI,
egui/eframe) lives insrc/gui/, with one module per view undersrc/gui/views/(current,trackings,visual_day,projects,jira_sync,daemon,settings,onboarding,undo). - TUI code lives in
src/tui/. - Platform implementation stories are in
IMPLEMENTATION_STORIES/(25+). - Build core-only:
cargo build --no-default-features