Files
deskmeter/CLAUDE.md
buenosairesam c7ddfa6af5 fend updates
2025-12-19 23:26:03 -03:00

13 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Deskmeter is a productivity tool that measures time spent across desktop workspaces. It consists of four main components:

  • dmcore: Core tracking daemon (dmapp/dmcore/main.py) that monitors active workspace and task changes

Architecture

Core Components

Task Management System:

  • Task definitions stored in files, tracked via dmapp/dmcore/task.py
  • File modification time monitoring for automatic task switching
  • Hierarchical task organization under workspace paths (e.g., work/default, work/dlt)

Workspace Tracking:

  • Uses wmctrl to detect active X11 workspace (requires XORG, not Wayland)
  • Maps workspace indices to labels in dmapp/dmcore/main.py:desktops
  • Special handling for "work" desktops with automatic task enforcement

Data Storage:

  • MongoDB backend storing workspace switches with timestamps and durations
  • State persistence in dmapp/dmcore/state.py for current workspace/task tracking

Web Interface Structure

Flask Routes (dmapp/dmweb/dm.py):

  • / - Today's productivity summary (large display with auto-refresh)
  • /calendar/<scope>/<year>/<month>/<day>?grid=<1|3|6> - Google Calendar-style view with aggregated task blocks
    • Scopes: daily, weekly, monthly
    • Grid: Hour aggregation (1h, 3h, or 6h blocks)
    • Shows only active workspaces (Plan/Think/Work) with gaps for idle time
    • Cascading overlapping blocks for multiple tasks per time period
  • /switches/<scope>/<year>/<month>/<day> - Raw switches view with proportional cell heights
    • Shows all workspace switches with time-based height visualization
  • /work - Work projects breakdown for today
  • /totals - All-time statistics
  • /day/<month>/<day> - Single day view
  • /period/<start>/<end> - Custom date range
  • /api/current_task - JSON endpoint for current task info (used by GNOME extension)
  • /api/today - HTML fragment for AJAX updates

Development Commands

Python Backend

# Install dependencies
pip install -r requirements.txt

# Start MongoDB service
sudo systemctl start mongod.service

# Run core tracking daemon
cd dmapp/dmcore
python3 main.py

# Run Flask web server
cd dmapp/dmweb  
python3 run.py

# Run tests
cd dmapp/tests
python3 test_dmapp.py

Running the Web Interface

Use the dmweb.sh script for flexible deployment:

cd /home/mariano/wdir/run

# Syntax: ./dmweb.sh <worktree> <port> <debug>
./dmweb.sh dm-fend-updates 10002 1

# Parameters:
# - worktree: directory name in /home/mariano/wdir/ (default: dm)
# - port: Flask server port (default: 10000)
# - debug: 1 for debug mode with auto-reload, 0 for production (default: 0)

Angular Frontend (Not Yet Implemented)

The Angular frontend (dmapp/dmfnt/) mentioned in the architecture is planned but not currently implemented. All current functionality is in the Flask templates.

GNOME Extension

cd gnome-extension

# Install extension
./install.sh

# Restart GNOME Shell (X11 only)
# Alt+F2 → type 'r' → Enter
# (On Wayland: log out and back in)

# Enable extension
gnome-extensions enable deskmeter-indicator@local

# Update extension after changes
./update.sh
# Then restart GNOME Shell

# Debug logs
journalctl -f -o cat /usr/bin/gnome-shell

# Test API endpoint
curl http://localhost:10000/api/current_task

System Setup

The application requires:

  • MongoDB running locally
  • wmctrl installed (apt install wmctrl)
  • X11 desktop environment (not Wayland for dmcore; GNOME extension works on both X11/Wayland)
  • Python virtual environment recommended

Key Configuration

Workspace Labels: Edit desktops tuple in dmapp/dmcore/main.py:12 Work Desktop Mapping: Configure work_desktops dict in dmapp/dmcore/main.py:13 Timezone: Set in dmapp/dmcore/main.py:19 using zoneinfo

Calendar & Switches Visualization

Overview

Two complementary views for analyzing workspace switching patterns:

  • Calendar View (/calendar) - Google Calendar-style blocks showing when you worked on each task
  • Switches View (/switches) - Granular list of every workspace switch

Both support daily, weekly, and monthly scopes with navigation.

Calendar View Features

Visual Design:

  • Task blocks positioned at actual times during the day
  • Each task gets consistent color (HSL hue based on task name hash)
  • Gradient within each block:
    • Left side (bright) = active time (Plan/Think/Work workspaces)
    • Right side (faded) = idle time (Other/Away workspaces)
    • Gradient split point = active/idle ratio

Block Grouping:

  • Consecutive switches to same task are merged into blocks
  • Minimum durations filter micro-switches:
    • Daily: 60 seconds
    • Weekly: 5 minutes
    • Monthly: 10 minutes

Data Structure (get_task_blocks_calendar()):

{
    'task_id': str,
    'task_path': str,
    'start': datetime,
    'end': datetime,
    'duration': int,           # total seconds
    'active_seconds': int,     # Plan/Think/Work time
    'idle_seconds': int,       # Other/Away time
    'active_ratio': float      # 0.0 to 1.0
}

Switches View Features

Visual Design:

  • Each switch row color-coded by task (same colors as calendar)
  • Border color and background both use task color for visual grouping
  • Active workspaces (Plan/Think/Work) shown bold
  • Idle workspaces (Other/Away) shown faded

Display:

  • Timestamp, workspace name, task path, duration for each switch
  • Stats summary showing total switches and total time
  • All switches in chronological order

Task History System

Problem: Historic task IDs (from archived task files) display as raw IDs instead of paths.

Solution: Automatic on-demand task resolution via task_history collection:

  1. When displaying unknown task ID, get_task_path() tries:
    • Current tasks collection (active tasks from main file)
    • task_history collection (cached historic tasks)
    • File scan: searches all files in /home/mariano/LETRAS/adm/task/
  2. When found via file scan, stores in task_history for next time
  3. Returns task_id as fallback if not found anywhere

Benefits:

  • No manual history loading required
  • No dmcore startup overhead
  • History populates automatically as you view old data
  • Frontend self-sufficient and independent

Files:

  • Frontend parsing: dmapp/dmweb/get_period_times.py:parse_task_line()
  • File scanning: dmapp/dmweb/get_period_times.py:load_task_from_files()
  • Resolution: dmapp/dmweb/get_period_times.py:get_task_path()

Component Integration

How Task Updates Flow

  1. User switches workspace → GNOME detects immediately
  2. dmcore polling (every 2 seconds) → detects workspace change via wmctrl
  3. Task enforcement → dmcore updates MongoDB state collection with current task
  4. GNOME extension → listens to workspace-switched signal, waits 2.2s, queries API
  5. Panel indicator updates → shows current task path in top panel

GNOME Extension Architecture

Location: gnome-extension/deskmeter-indicator@local/

Files:

  • extension.js - Main extension logic, workspace switch listener, API polling
  • metadata.json - Extension metadata (GNOME 40-47 compatible)
  • stylesheet.css - Panel indicator styling

Behavior:

  • Connects to GNOME's workspace-switched signal
  • Debounces updates by 2.2 seconds after workspace switch
  • Queries /api/current_task endpoint
  • Displays task path in panel, truncates if > 40 chars
  • Shows last 2 path segments for long paths (e.g., .../work/project)

Update Workflow:

  1. Edit source files in gnome-extension/deskmeter-indicator@local/
  2. Run ./update.sh to copy to ~/.local/share/gnome-shell/extensions/
  3. Restart GNOME Shell (Alt+F2r on X11, or log out/in on Wayland)
  4. Check logs: journalctl -f -o cat /usr/bin/gnome-shell

Development Notes

  • The system enforces task constraints within work desktops - switching to a non-work task automatically reverts to the designated work task
  • Task files are monitored for changes to enable automatic context switching
  • Web interface runs on port 10000 by default (configurable via dmweb.sh script)
  • Core daemon sleeps for 2 seconds between workspace checks
  • GNOME extension debounce delay (2.2s) must be > dmcore polling interval (2s) to ensure MongoDB is updated before API query

Working on Calendar/Switches Views

Current Implementation

Routes (dmapp/dmweb/dm.py):

  • /calendar and /switches must be defined BEFORE the catch-all /<string:task> route
  • Both support /<scope> (daily/weekly/monthly) and /<scope>/<year>/<month>/<day>
  • Navigation via prev/next date links and tab switching between scopes

Templates:

  • calendar_view.html - 24-hour grid with task blocks positioned by time
  • switches_view.html - Simple list with task-based color coding
  • Both use Jinja2 |hash filter for color generation (registered in __init__.py)

Data Flow:

  1. Route extracts date range from URL params
  2. Calls get_task_blocks_calendar() or get_raw_switches()
  3. Each function calls get_task_path() for task name resolution
  4. get_task_path() auto-populates task_history on cache miss
  5. Template renders with inline styles (HSL colors from task name hash)

Potential Improvements

  • Performance: Cache get_task_path() results in-memory to avoid repeated DB lookups
  • Color collision: Current hash % 360 can produce similar hues for different tasks
  • Weekly/monthly calendar: Currently shows sequential blocks, could show multi-column grid like daily view
  • Task filtering: Add URL param to filter by specific task(s)
  • Export: Add CSV/JSON export of block or switch data
  • Overlapping blocks: If switching between tasks within same hour, blocks could overlap visually

Key Design Decisions

  1. No JavaScript frameworks - Pure server-rendered HTML with minimal CSS transitions
  2. Task history is frontend-only - dmcore never touches task_history collection
  3. Color coding consistency - Same task always gets same color across all views
  4. Gradient indicates work quality - Visual distinction between active focus and idle time
  5. Multiple thresholds - Different minimum block durations for different scopes reduces noise

UI/UX Design

Dark Mode Theme (applied across all views):

  • Background: #1a1a1a
  • Text: #e0e0e0
  • Accent/links: #6b9bd1
  • Borders: #444
  • Component backgrounds: #2a2a2a

Calendar View Features:

  • Hour-based aggregation (configurable: 1h, 3h, 6h grids)
  • Overlapping task blocks cascade right and down (8% horizontal, 4px vertical per task)
  • Only active workspaces shown (Plan/Think/Work) - idle time appears as gaps
  • Task colors generated via hash-based HSL for consistency
  • Height proportional to time spent in each grid period

Switches View Features:

  • Cell heights proportional to switch duration (30px min, 200px max)
  • Color-coded by task with hash-based HSL
  • Dark backgrounds with reduced opacity for idle workspaces

Navigation:

  • Consistent nav bar across all views: Today | Calendar | Switches | Work | All Time
  • All views interconnected for easy movement between different data perspectives

GNOME Extension

A GNOME Shell extension displays the current task in the top panel:

  • Location: gnome-extension/deskmeter-indicator@local/
  • Polls /api/current_task endpoint
  • Updates on workspace switch with 2.2s debounce
  • Automatically truncates long task paths
  • Installation: ./gnome-extension/install.sh or ./gnome-extension/update.sh

Key Implementation Details

Calendar Aggregation (dmapp/dmweb/get_period_times.py:get_task_blocks_calendar()):

  • Aggregates switches by configurable time grid (1h, 3h, or 6h)
  • Only includes active workspaces: Plan, Think, Work
  • Returns blocks with task_id, task_path, start time, duration, and hour
  • Filters out blocks shorter than min_block_seconds

Task Path Resolution:

  • Primary: tasks collection (current tasks)
  • Fallback: task_history collection (cached historical tasks)
  • Last resort: On-demand file search in task directory
  • Caching prevents repeated file I/O

Switch Height Calculation (switches view):

  • Finds max delta in current view
  • Heights scale linearly: base_height + (ratio * (max_height - base_height))
  • Base: 30px, Max: 200px

Tool Development Guidelines

  • This is a personal tool, not professionally developed
  • Reuse existing code as much as possible unless refactor is required explicitly
  • Only modify existing code if it absolutely doesn't make sense to add a new flow
  • When adding features, maintain the dark mode theme consistency
  • All new views should include the standard navigation bar