A comprehensive, professionally architected command-line tool for tracking work time on tasks with organized daily logs. Built with modern Python package structure, Typer CLI framework, Rich formatting, type hints, dataclasses, and enterprise-level architectural patterns.
π― Version 2.2.0 - Google Sheets Sync & Project Support: Enhanced --time option with date support, project/category tagging, and Google Sheets sync with haunts-compatible format.
- Smart task tracking: Start, end, pause, and resume tasks
- Anonymous work sessions: Start working without naming the task
- Single-task mode: Auto-ends previous tasks (default behavior)
- Parallel mode: Work on multiple tasks simultaneously with
--parallelflag - Custom timestamps: Backdate entries with
--time HH:MMor--time "YYYY-MM-DD HH:MM" - Project tagging: Organize tasks by project with
--project "Project Name" - Pause/Resume: Interrupt work and continue later
- Unified list command: See active, paused, and completed tasks at a glance
- Recent tasks: View detailed recent work history
- Daily summaries: Time totals and task breakdown by day
- Flexible filtering: By date, task name, project, or custom limits
- Haunts-compatible format: Sync to Google Sheets with haunts column layout
- Multiple auth methods: Haunts OAuth, OAuth token, or Service Account
- Auto-sync option: Sync automatically after ending tasks with
--sync - Selective sync: Daily, monthly, or by specific date
- Tag tasks:
drudge start "Fix bug" --project "Backend API" - Filter by project:
drudge list --project "Backend" - Project display: Projects shown in task listings
- Date support:
--time "2025-12-10 14:30"for any date - Backward compatible:
--time 14:30still works (uses today)
- Clean by date: Remove all entries for a specific date
- Clean by task: Remove all entries for a task across all dates
- Selective cleaning: Clean task entries for specific date only
- Clean all: Reset entire worklog with confirmation
- Automatic backups: Safety first - backups before deletion
- Default:
drudge end- Ends only active tasks - --all flag:
drudge end --all- Ends active AND paused tasks - --sync flag:
drudge end --sync- End and sync to Google Sheets
- Native Typer
--helpintegration - Command-specific help:
drudge COMMAND --help - Consistent with standard CLI conventions
- Python 3.8+ (tested with Python 3.10 and 3.13)
- Required packages:
typer[all]andrich
pip install drudge-cli# Clone the repository
git clone https://github.com/Trik16/drudge.git
cd drudge
# Install in development mode
pip install -e .# Run the setup script
./setup_drudge_alias.sh
# Or add manually to your shell config
echo 'alias drudge="python3 -m src.worklog"' >> ~/.zshrc
source ~/.zshrcDrudge supports tab completion for commands and options in Bash, Zsh, Fish, and PowerShell.
# Install completion for your current shell
drudge --install-completion
# Restart your shell or source your config
source ~/.zshrc # for Zsh
source ~/.bashrc # for BashZsh:
# Generate completion script
drudge --show-completion zsh > ~/.drudge-completion.zsh
# Add to ~/.zshrc
echo 'source ~/.drudge-completion.zsh' >> ~/.zshrc
source ~/.zshrcBash:
# Generate completion script
drudge --show-completion bash > ~/.drudge-completion.bash
# Add to ~/.bashrc
echo 'source ~/.drudge-completion.bash' >> ~/.bashrc
source ~/.bashrcFish:
# Generate completion script
drudge --show-completion fish > ~/.config/fish/completions/drudge.fishPowerShell:
# Generate completion script
drudge --show-completion powershell | Out-File -FilePath $PROFILE# Try typing and press TAB
drudge <TAB> # Shows all available commands
drudge start <TAB> # Shows task name suggestions
drudge end --<TAB> # Shows available flags# Start your workday
drudge start "Morning emails"
# Check what's active
drudge list
# End the task
drudge end "Morning emails"
# View today's summary
drudge dailyDrudge can be configured using a YAML file located at ~/.worklog/config.yaml. This file is automatically created from a template on first run.
The config file is created automatically when you first run any drudge command. You can view and manage it with:
# Show configuration summary
drudge config
# Show full config.yaml content
drudge config --show
# Edit configuration file directly
nano ~/.worklog/config.yaml
# or
code ~/.worklog/config.yaml# Basic settings
worklog_directory: "~/.worklog"
sheet_document_id: "1A2B3C4D5E6F7G8H9I0J"
timezone: "Europe/Rome"
# Project categorization
projects:
- Backend
- Frontend
- DevOps
- Research
# Google Sheets sync (haunts-compatible format)
google_sheets:
enabled: true
auto_sync: false
round_hours: 0.5 # Round to 15min (0.25), 30min (0.5), hour (1.0)
# Optional: Haunts integration (for Calendar sync)
haunts:
enabled: false
config_path: "~/.haunts"| Parameter | Type | Default | Description |
|---|---|---|---|
worklog_directory |
string | ~/.worklog |
Directory for worklog data |
sheet_document_id |
string | - | Google Sheets document ID (shared) |
timezone |
string | system | Timezone (from haunts or system) |
Define project categories to organize your work entries. Projects can be assigned when starting tasks:
# Start a task with project categorization
drudge start "Implement login feature" --project Backend
drudge start "Fix CSS layout" --project Frontend| Parameter | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false |
Enable/disable Google Sheets sync |
auto_sync |
boolean | false |
Auto-sync on task end |
round_hours |
float | 0.5 |
Rounding: 0.25 (15min), 0.5 (30min), 1.0 (hour) |
Note: Decimal places are automatic: 0.25β2 decimals, 0.5β1 decimal, 1.0β0 decimals
| Parameter | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false |
Whether you use haunts for Calendar sync |
config_path |
string | ~/.haunts |
Path to haunts config (reference only) |
Note: Haunts is optional. If enabled, it reads the Google Sheet and creates Calendar events independently.
The round_hours setting controls how task durations are rounded. Decimal places are automatic:
# Example 1: Round to 30 minutes (default)
round_hours: 0.5
# 2h 12m β 2,0 hours (2h 00m) - 1 decimal
# 2h 38m β 2,5 hours (2h 30m) - 1 decimal
# 2h 52m β 3,0 hours (3h 00m) - 1 decimal
# Example 2: Round to 15 minutes
round_hours: 0.25
# 2h 12m β 2,25 hours (2h 15m) - 2 decimals
# 2h 38m β 2,50 hours (2h 30m) - 2 decimals
# 2h 52m β 2,75 hours (2h 45m) - 2 decimals
# Example 3: Round to full hour
round_hours: 1.0
# 2h 12m β 2 hours - 0 decimals
# 2h 38m β 3 hours - 0 decimalsNote: Uses comma (,) as decimal separator for European format.
Once configured, you can organize your work by project:
# Start tasks with project categorization
drudge start "API refactoring" --project Backend
drudge start "Button animations" --project Frontend
# Tasks are tracked with their projects
drudge list
# Output shows: "API refactoring [Backend]" and "Button animations [Frontend]"
# End tasks (project info is preserved)
drudge end "API refactoring"
# Output: π Completed 'API refactoring' [Backend] (2h 30m)When enabled, drudge can sync completed tasks to Google Calendar via Haunts:
# Manual sync (when sync_mode: manual)
drudge daily --sync
# View what will be synced
drudge daily
# Shows completed tasks with their projects and durationsNote: Haunts integration requires the Haunts package to be installed and configured.
| Command | Description | Example |
|---|---|---|
| Task Management | ||
drudge start "Name" |
π Start a new task (auto-ends previous) | drudge start "Bug fix #123" |
drudge start |
π Start anonymous work session | drudge start |
drudge start --parallel |
π Start without ending active tasks | drudge start "Review" --parallel |
drudge start --project NAME |
π Start with project categorization | drudge start "API work" --project Backend |
drudge start --time HH:MM |
π Start at specific time | drudge start "Meeting" --time 09:30 |
drudge end "Name" |
π End a specific task | drudge end "Bug fix #123" |
drudge end |
π End ALL active tasks (paused remain) | drudge end |
drudge end --all |
π NEW End active AND paused tasks | drudge end --all |
drudge end --time HH:MM |
π End at specific time | drudge end "Meeting" --time 17:30 |
drudge pause "Name" |
βΈοΈ Pause an active task | drudge pause "Task" |
drudge resume "Name" |
drudge resume "Task" |
|
| Cleaning & Maintenance | ||
drudge clean YYYY-MM-DD |
ποΈ NEW Clean all entries for date | drudge clean 2025-10-03 |
drudge clean "Task" |
ποΈ NEW Clean task (all dates) | drudge clean "Bug fix" |
drudge clean "Task" --date |
ποΈ NEW Clean task for specific date | drudge clean "Meeting" -d 2025-10-03 |
drudge clean --all |
ποΈ NEW Clean ALL entries (confirm) | drudge clean --all |
| Viewing & Reporting | ||
drudge list |
π Show active, paused, completed | drudge list |
drudge list --date YYYY-MM-DD |
π List entries for date | drudge list --date 2025-10-03 |
drudge list --task "keyword" |
π Filter by task name | drudge list --task "bug" |
drudge list --limit N |
π Limit results | drudge list --limit 10 |
drudge recent |
π Recent tasks (full details) | drudge recent |
drudge recent --limit N |
π Show N recent tasks | drudge recent --limit 10 |
drudge daily |
π Today's summary | drudge daily |
drudge daily --date YYYY-MM-DD |
π Specific date summary | drudge daily --date 2025-10-03 |
| Help & Info | ||
drudge --help |
β IMPROVED Main help | drudge --help |
drudge COMMAND --help |
β IMPROVED Command help | drudge start --help |
| Configuration | ||
drudge config |
βοΈ Show config summary | drudge config |
drudge config --show |
βοΈ Display full config.yaml | drudge config --show |
drudge version |
π¦ Show version | drudge version |
# Start a task
$ drudge start "Fix bug #123"
π Started 'Fix bug #123' at 2025-10-04 10:00:00
# End it
$ drudge end "Fix bug #123"
π Completed 'Fix bug #123' at 2025-10-04 12:30:00 (Duration: 02:30:00)# Don't know what you're working on yet?
$ drudge start
π‘ Starting anonymous work session
# Name it later (converts anonymous β named)
$ drudge start "Research and planning"
βοΈ Renamed anonymous work to 'Research and planning'# Work on multiple tasks simultaneously
$ drudge start "Backend API"
$ drudge start "Code review" --parallel # Keeps Backend API running
$ drudge list
π₯ ACTIVE TASKS:
β’ Backend API (Running: 01:00:00)
β’ Code review (Running: 00:15:00)
# End specific task
$ drudge end "Code review"
π Completed 'Code review' (Duration: 00:30:00)# Working on a task
$ drudge start "Important project"
# Lunch break
$ drudge pause "Important project"
βΈοΈ Paused 'Important project'
# Back from lunch
$ drudge resume "Important project"
βΆοΈ Resumed 'Important project'
# Finish up
$ drudge end "Important project"
π Completed 'Important project' (Duration: 03:30:00)# Create test scenario
$ drudge start "Active Task"
$ drudge start "Another Task" --parallel
$ drudge pause "Active Task"
$ drudge list
π₯ ACTIVE TASKS:
β’ Another Task (Running: 00:05:00)
βΈοΈ PAUSED TASKS:
β’ Active Task
# End only active tasks (DEFAULT behavior)
$ drudge end
β
Ended 1 task(s) successfully # Only "Another Task" ended
$ drudge list
βΈοΈ PAUSED TASKS:
β’ Active Task # Paused task remains!
# End ALL tasks including paused (NEW --all flag)
$ drudge end --all
βΆοΈ Resumed 'Active Task'
π Completed 'Active Task'
β
Ended 1 task(s) successfully# Clean all entries for a specific date
$ drudge clean 2025-10-03
β
Cleaned 15 entries for 2025-10-03
πΎ Backup created for safety
# Clean all entries for a task (across all dates)
$ drudge clean "Bug fix #123"
β
Cleaned 3 entries for task 'Bug fix #123'
πΎ Backup created for safety
# Clean task entries for specific date only
$ drudge clean "Meeting" --date 2025-10-03
β
Cleaned 1 entries for task 'Meeting' on 2025-10-03
πΎ Backup created for safety
# Clean everything (with confirmation)
$ drudge clean --all
β οΈ This will clean ALL worklog entries!
Are you sure you want to continue? [y/N]: y
β
Cleaned 50 entries and 10 daily files
πΎ Backup created for safety# Forgot to track? Backdate it
$ drudge start "Morning standup" --time 09:00
π Started 'Morning standup' at 2025-10-04 09:00:00
$ drudge end "Morning standup" --time 09:30
π Completed 'Morning standup' (Duration: 00:30:00)# View today's summary
$ drudge daily
π
Daily Summary for 2025-10-04
π Total: 5 tasks, 7h 30m
β’ Fix bug #123: 2h 30m
β’ Code review: 1h 00m
β’ Morning standup: 0h 30m
β’ Documentation: 2h 00m
β’ Backend API: 1h 30m
# View specific date
$ drudge daily --date 2025-10-03# Configure projects in ~/.worklog/config.yaml
# (file is auto-created on first run)
$ drudge config --show
# Edit to add your projects under 'projects:' section
# Start tasks with project categorization
$ drudge start "Implement login API" --project Backend
π Started 'Implement login API' [Backend] at 2025-10-04 10:00:00
$ drudge start "Fix responsive design" --project Frontend --parallel
π Started 'Fix responsive design' [Frontend] at 2025-10-04 10:30:00
# List shows projects
$ drudge list
π₯ ACTIVE TASKS:
β’ Implement login API [Backend] (Running: 02:00:00)
β’ Fix responsive design [Frontend] (Running: 01:30:00)
# End tasks (project info is preserved)
$ drudge end "Implement login API"
π Completed 'Implement login API' [Backend] (Duration: 02:00:00)
$ drudge end "Fix responsive design"
π Completed 'Fix responsive design' [Frontend] (Duration: 01:30:00)
# Daily summary shows projects
$ drudge daily
π
Daily Summary for 2025-10-04
π Total: 2 tasks, 3h 30m
β’ Implement login API [Backend]: 2h 00m
β’ Fix responsive design [Frontend]: 1h 30m
# Sync to Google Calendar (with Haunts integration)
$ drudge daily --sync
β
Synced 2 tasks to Google CalendarDrudge can sync your work tasks to Google Sheets in a haunts-compatible format. This allows you to:
- Keep a time-tracking spreadsheet
- Sync to Google Calendar (if using haunts)
- Share work reports with your team
-
Create or use existing Google Sheet
-
Configure in
~/.worklog/config.yaml:# Add your Sheet Document ID (from URL) sheet_document_id: "1A2B3C4D5E6F7G8H9I0J" google_sheets: enabled: true auto_sync: false # or true for automatic sync on 'drudge end' round_hours: 0.5 # 0.25=15min, 0.5=30min, 1.0=hour
-
Sync your tasks:
drudge sync # Sync all entries drudge sync --daily # Sync today's entries drudge sync --monthly # Sync current month drudge daily --sync # Alias for --daily
1. Config Sheet (name: config)
- Maps project names to Calendar IDs (optional for drudge, required for haunts)
2. Monthly Sheets (names: January, February, March, etc.)
- Auto-created based on task dates
- Contains your task entries
Monthly Sheet Columns:
| Column | Name | Description | Example |
|---|---|---|---|
| A | Date | Task date | 04/10/2025 |
| B | Start time | Task start time | 09:30 |
| C | Project | Project category | Backend |
| D | Activity | Task description | Implement login API |
| E | Details | Additional notes | Added JWT auth |
| F | Spent | Duration (decimal hours) | 2,5 |
| G | Event id | Calendar event ID (filled by haunts) | - |
| H | Link | Calendar event link (filled by haunts) | - |
| I | Action | Sync control (used by haunts) | - |
Task in drudge:
drudge start "Implement login API" --project Backend
# ... work for 2h 30m ...
drudge end "Implement login API"Synced to Google Sheet (October tab):
| Date | Start | Project | Activity | Spent |
|------------|-------|---------|---------------------|-------|
| 04/10/2025 | 09:00 | Backend | Implement login API | 2,5 |
Configure how hours are formatted in the sheet:
google_sheets:
hours_decimal: 1 # Decimal places (0, 1, or 2)
round_hours: 0.25 # Round to 15min (0.25), 30min (0.5), or hour (1.0)Examples:
- Task: 2h 47m
hours_decimal: 1, round_hours: 0.25β2,75(2h 45m)hours_decimal: 2, round_hours: 0.5β2,50(2h 30m)hours_decimal: 0, round_hours: 1.0β3(3h)
If you use haunts for Calendar sync:
- Drudge β Writes tasks to Google Sheet
- Haunts β Reads sheet and creates Calendar events
- Haunts β Fills
Event idandLinkcolumns
Without haunts:
- You still get a time-tracking spreadsheet
- No automatic calendar sync
- Perfect for manual reporting
To use Google Sheets sync, you need:
- Google Cloud Project with Sheets API enabled
- OAuth 2.0 credentials or service account
- Credentials file at
~/.worklog/credentials.json
See Google Sheets API Quickstart for detailed setup.
For detailed sheet structure, column specifications, and setup guides, see:
src/worklog/
βββ __init__.py # Package initialization
βββ __main__.py # Entry point
βββ models.py # Data models (TaskEntry, PausedTask, WorkLogData)
βββ config.py # Configuration management
βββ validators.py # Input validation
βββ managers/ # Business logic
β βββ worklog.py # Core WorkLog class
β βββ backup.py # Backup management
β βββ daily_file.py # Daily file operations
βββ cli/ # Command-line interface
β βββ commands.py # Typer commands
βββ utils/ # Utilities
βββ decorators.py # Common decorators
~/.worklog/
βββ worklog.json # Complete task database (JSON)
βββ worklog.log # Application logs
βββ 2025-10-01.txt # Human-readable daily logs
βββ 2025-10-02.txt
βββ 2025-10-03.txt
βββ daily/ # Backup directory
βββ 2025-10-01.txt
βββ 2025-10-02.txt
2025-10-04 09:00:00 Morning standup (00:30:00)
2025-10-04 10:00:00 Fix bug #123 (02:30:00)
2025-10-04 14:00:00 Backend API [ACTIVE]
2025-10-04 15:00:00 Code review [PAUSED]
New Features:
- β¨ Enhanced end command:
--allflag to end both active and paused tasks - β¨ Clean command: Erase worklog entries by date, task, or all (with backups)
- β¨ Improved help: Native Typer
--helpintegration (removed custom help command)
Improvements:
- π§ End command:
drudge endkeeps paused tasks,drudge end --allends everything - π‘οΈ Clean safety: Automatic backups, confirmation for --all, smart daily file rebuild
- π All 47 test cases passing (100%)
New Features:
- Anonymous work sessions
- Parallel task mode
- Optimized list command
- Enhanced recent command
Major Refactoring:
- Complete architectural overhaul
- Typer CLI framework with Rich formatting
- Professional package structure
- 28 comprehensive test cases
- Initial release with basic task tracking
# Run all tests
pytest tests/ -v
# Run specific test file
pytest tests/test_cli_integration.py -v
# Run specific test class
pytest tests/test_worklog_updated.py::TestNewFeatures -v
# Run tests in Docker (isolated environment)
docker build -f Dockerfile.test -t drudge-test .
docker run --rm drudge-test- 106 comprehensive test cases
- 47 CLI integration tests
- 20 Google Sheets sync tests
- 39 core worklog tests
- 100% pass rate on Python 3.10-3.13
- Core features: Start, end, pause, resume
- New features: Anonymous tasks, parallel mode, clean command, Google Sheets sync
- Edge cases and error handling
# Build distribution
python3.10 -m build
# Check distribution
twine check dist/*# Upload to PyPI
twine upload dist/*MIT License - See LICENSE file for details
- GitHub: github.com/Trik16/drudge
- PyPI: pypi.org/project/drudge-cli
- Changelog: CHANGELOG.md
- Release Notes: docs/RELEASE_2.1.0.md
Contributions are welcome! Please feel free to submit a Pull Request.
For issues, questions, or feature requests, please open an issue on GitHub.
Built with β€οΈ using Python, Typer, and Rich
Version 2.1.1 - Enhanced CLI with native help, powerful clean command, and improved task management