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