A lightweight, open-source, privacy-first desktop time tracker built with Python and CustomTkinter.
LedgerTimer is designed specifically for freelancers, contractors, and professionals who need to log billable hours for clients. It features a simple punch-in/punch-out interface, flexible retroactive editing, and clean end-of-month CSV/Excel exports for seamless invoicing.
- Manual Punch In/Out: A prominent, simple button interface to record work sessions in real-time.
- Retroactive Time Editing: Complete freedom to modify the Start Time, End Time, or overall duration of any log after an activity is completed (to correct mistakes).
- Detailed Task Descriptions: An input field for every session to note down exactly what work was done, ensuring complete transparency for your clients.
- Client/Project Tagging: Easily categorize each logged session under specific clients or projects.
- End-of-Month Export: One-click data export to standard
.csv(Excel-compatible) formats, filtered by date range or client for quick billing. - Local & Secure Storage: Uses a lightweight, local SQLite database to store all historical logs safely on your machine.
- Language: Python 3.10+
- GUI Framework:
customtkinter(Modern, sleek, dark/light mode responsive widgets) - Data Storage:
sqlite3(Built into Python, zero setup required) - Data Export: Python's native
csvmodule - Packaging Tool:
PyInstallerfor single-file executable distribution (.exe,.app, or Linux binary)
Hey AI! Please strictly follow these engineering guidelines when helping me write, debug, or refactor code for LedgerTimer:
- Keep it Simple & Modular: Keep the UI layer (
gui.py), database layer (database.py), and export logic (export.py) cleanly separated. - CustomTkinter Elements Only: Always use
customtkinterelements (e.g.,CTkButton,CTkEntry,CTkTextbox,CTkFrame) instead of rawtkinterwidgets to keep the dark-mode aesthetic consistent. - UI Layout Blueprint: * Top Section: Client/Project selector, Task Description input box, and a prominent Start/Stop Timer button with a live running clock.
- Middle Section: A scrollable table or list showing today's logged activities. Double-clicking a log should open a clean modal/popup to let the user manually edit the start/end times and descriptions.
- Bottom Section: Date-range filters and a prominent "Export to CSV" button.
- Database Resiliency: Ensure the SQLite database automatically initializes its tables (
logs,projects) on the very first boot if they don't already exist.
- Python 3.10 or higher
pip(Python package manager)
-
Clone the repository:
git clone https://github.com/vincent7q/LedgerTimer.git cd LedgerTimer -
Install dependencies:
pip install -r requirements.txt
-
Run the program:
python -m ledgertimer
-
Install PyInstaller:
pip install pyinstaller
-
(Optional) Regenerate the app icon if needed:
python ledgertimer/ico_generator.py
This creates
ledgertimer/app_icon.ico. The file is already committed, so skip this step unless you want to update the icon. -
Build using the spec file (recommended):
python -m PyInstaller LedgerTimer.spec --noconfirm
The spec file handles everything automatically:
Setting Value Single-file output --onefileNo console window --windowedCustomTkinter assets bundled via collect_data_filesApp icon (window + taskbar) ledgertimer/app_icon.icoExe icon (file explorer) ledgertimer/app_icon.icoDo not use a raw
pyinstaller --onefile ...command — it will regenerate the spec and lose the icon settings. -
The finished executable is at:
dist/LedgerTimer.exeledger.dbwill be created automatically in the same folder as the.exeon first run.
PyInstaller cannot cross-compile — the Linux binary must be built on Linux. The easiest way on Windows is via WSL2.
-
Install WSL2 and a distro (e.g. Ubuntu) if not already set up:
wsl --install -
Open a WSL terminal, navigate to the project, and install dependencies:
cd /mnt/c/Users/<you>/source/LedgerTimer sudo apt update && sudo apt install python3 python3-pip python3-tk -y pip3 install -r requirements.txt pip3 install pyinstaller
-
Build using the same spec file:
python3 -m PyInstaller LedgerTimer.spec --noconfirm
The
icon=setting in the spec is silently ignored on Linux — this is expected. -
The finished binary is at:
dist/LedgerTimerMake it executable if needed:
chmod +x dist/LedgerTimer ./dist/LedgerTimer
If you prefer a VM or CI pipeline (e.g. GitHub Actions), the same steps apply — install Python + tkinter, install dependencies, then run pyinstaller LedgerTimer.spec --noconfirm.
Like Linux, macOS builds must be run on a Mac (no cross-compilation).
-
Install Python 3.10+ from python.org (recommended over Homebrew — it includes Tkinter).
-
Install dependencies:
pip3 install -r requirements.txt pip3 install pyinstaller
-
(Optional) Generate a macOS
.icnsicon. The.icofile used for Windows is not supported on macOS:# Convert app_icon.ico to app_icon.icns using sips + iconutil (macOS built-in tools) mkdir app_icon.iconset sips -z 16 16 ledgertimer/app_icon.png --out app_icon.iconset/icon_16x16.png sips -z 32 32 ledgertimer/app_icon.png --out app_icon.iconset/icon_16x16@2x.png sips -z 32 32 ledgertimer/app_icon.png --out app_icon.iconset/icon_32x32.png sips -z 64 64 ledgertimer/app_icon.png --out app_icon.iconset/icon_32x32@2x.png sips -z 128 128 ledgertimer/app_icon.png --out app_icon.iconset/icon_128x128.png sips -z 256 256 ledgertimer/app_icon.png --out app_icon.iconset/icon_128x128@2x.png sips -z 256 256 ledgertimer/app_icon.png --out app_icon.iconset/icon_256x256.png sips -z 512 512 ledgertimer/app_icon.png --out app_icon.iconset/icon_256x256@2x.png iconutil -c icns app_icon.iconset -o ledgertimer/app_icon.icns rm -rf app_icon.iconsetThen update the
icon=line inLedgerTimer.specto'ledgertimer/app_icon.icns'before building. -
Build using the spec file:
python3 -m PyInstaller LedgerTimer.spec --noconfirm
-
The finished app bundle is at:
dist/LedgerTimer.appTo run it:
open dist/LedgerTimer.app
Gatekeeper warning: Unsigned apps downloaded from the internet will be blocked by macOS. To bypass for local use, right-click → Open, or run:
xattr -d com.apple.quarantine dist/LedgerTimer.app