plugins/sjawhar/skills/fill-toggl/SKILL.md
Use when auto-filling missing Toggl time entries from desktop activity, Claude Code sessions, and existing patterns
npx skillsauth add sjawhar/dotfiles fill-togglInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
REQUIRED SUB-SKILL: Use using-toggl for Toggl MCP tools.
Auto-fill missing Toggl time entries from desktop activity, Claude Code sessions, and existing entry patterns.
Key principle: Claude session content is the primary source of truth for what was worked on; desktop activity provides both timing AND validation that you were actively working (not just background processes).
Required (first argument): Date or period
today, yesterday2026-01-152026-01-13..2026-01-15Optional flags (named parameters only):
--sessions <path>: Path to directory containing Claude Code session JSONL files--toggl-db <path>: Path to local Toggl SQLite databaseDefault data locations (used if flags not provided):
/data/toggl/production/DatabaseModel.sqlite/data/claude/*/ (searches all home directories)These paths are checked automatically. If not found, the command will ask.
Timezone handling:
2026-01-18T00:00 America/Los_AngelesExamples:
/fill-toggl today/fill-toggl yesterday --sessions ~/claude-sessions/fill-toggl 2026-01-15 --sessions ~/transcripts --toggl-db ~/toggl.sqliteIf a bare path is provided without a flag, ask the user to clarify whether it's a sessions path or Toggl DB path.
Determine date range from user argument (default: today)
Fetch existing Toggl entries for the date range using toggl_get_time_entries
Fetch previous week's entries using toggl_get_time_entries with appropriate date range - this provides patterns for common descriptions, projects, and tags
Get desktop activity from Toggl:
/data/toggl/production/DatabaseModel.sqlitetoggl_get_timeline API (note: rate limited to 30 req/hr)Collect Claude Code sessions:
--sessions provided: use that path/data/claude/*/ for all home directories.claude/projects/*/ for session .jsonl filesRule: Every time entry MUST have exactly ONE tag. This applies to ALL entries in the date range, not just newly created ones.
Scan ALL existing entries in the date range for tag violations:
Find multi-tag entries: Query entries where tag count > 1
For each multi-tag entry:
Find zero-tag entries: Also flag entries with NO tags for user to assign one
Complete this cleanup before proceeding to gap detection.
For each Claude Code session file found, launch a subagent (using Task tool with subagent_type: "general-purpose") to analyze the session.
Subagent prompt template:
Analyze this Claude Code session transcript and extract activity blocks.
Session file: {path}
## Instructions
Read the JSONL file. Each line is a JSON object with:
- `type`: "user", "assistant", "summary", etc.
- `message`: The content
- `timestamp`: ISO timestamp
- `cwd`: Current working directory
## Your task
1. Identify time ranges of active work from timestamps
2. Summarize WHAT was being worked on (not just "coding" but specific tasks like "implementing OAuth flow")
3. Split into separate blocks when timestamp gaps > 30 minutes occur
4. Infer project names from directory paths, file names, or conversation content
## Output format (JSON only, no markdown fences)
{
"session_file": "{filename}",
"total_duration_minutes": 75,
"blocks": [
{
"start": "2026-01-15T09:15:00Z",
"end": "2026-01-15T10:30:00Z",
"description": "Implementing OAuth2 flow for GitHub login",
"inferred_project": "vivaria",
"confidence": "high",
"evidence": "Multiple files in /vivaria/auth/ were edited"
}
]
}
If no activity found: {"session_file": "{filename}", "blocks": []}
If file is unreadable: {"session_file": "{filename}", "error": "description of issue"}
Large session files: If a session file exceeds 50,000 lines, sample: read first 1000 lines, last 1000 lines, and sample every 100th line in between. Focus on timestamps and conversation flow.
Run subagents in parallel for efficiency. Collect their outputs.
Subagent error handling:
Build a coverage map from existing Toggl entries (list of covered time ranges)
Find gaps using this logic:
Filter out gaps shorter than 15 minutes of actual activity
For each gap, determine what to fill it with:
Primary source: Claude Code session content
Secondary source: Previous week patterns
Pattern matching heuristics:
Tertiary source: Desktop activity
Activity type separation:
Interpreting desktop activity:
Mandatory entry splitting:
⏸️ STOP AND WAIT FOR USER INPUT
| Time | Duration | Description | Project | Tags | Source | |------|----------|-------------|---------|------|--------| | 09:15-10:30 | 1h 15m | Code review for auth PR | vivaria | Code Review | Claude session | | 14:00-14:45 | 45m | Similar to "standup prep" | meetings | Meeting | Pattern match | | 16:30-17:15 | 45m | Development work | (unknown) | — | Desktop activity |
⚠️ Warning: If any proposed entry is missing a project or tags, highlight it and ask the user to provide values before proceeding.
Wait for user feedback. They may:
Project and tag resolution:
toggl_list_projects and tags with toggl_list_tagsCreate entries using toggl_create_time_entry for each approved gap
Check for overlaps:
Report results:
You are NOT DONE until ALL of the following are verified:
Verification loop:
Repeat until all completion criteria pass:
Gap check: Fetch fresh Toggl entries and desktop activity. Identify any remaining gaps where activity occurred but no entry exists.
Quality check: For each Toggl entry in the date range, verify:
Report any entries missing these and propose fixes.
Overlap check: Scan all entries for time overlaps. Report any overlapping pairs with details.
Session alignment check: Cross-reference entries against Claude sessions to verify descriptions make sense. Flag mismatches (e.g., entry says "development" but session shows code review).
Granularity check: Flag any entries exceeding 2 hours for user review.
Present findings to user. If issues found:
Create/update entries as approved and return to step 14.
If accessing the local SQLite database (user must provide the path):
Database format: SQLite 3.x with WAL, Core Data managed
Key table: ZMANAGEDACTIVITY
ZSTART, ZEND: Cocoa timestamps (seconds since 2001-01-01 00:00:00 UTC)ZFILENAME: App name (e.g., "iTerm2", "Chrome")ZTITLE: Window title (e.g., "ssh", "✳ Claude Code")ZISIDLE: 0 = active, 1 = idleTimestamp conversion: cocoa_timestamp + 978307200 = unix_timestamp
Query example (substitute the actual date):
SELECT
datetime(ZSTART + 978307200, 'unixepoch', 'localtime') as start_time,
datetime(ZEND + 978307200, 'unixepoch', 'localtime') as end_time,
ZFILENAME as app,
ZTITLE as title,
ZISIDLE as is_idle
FROM ZMANAGEDACTIVITY
WHERE date(ZSTART + 978307200, 'unixepoch', 'localtime') = ?
AND ZISIDLE = 0
ORDER BY ZSTART
toggl_get_time_entries, toggl_get_timeline, toggl_create_time_entry, toggl_list_projects, toggl_list_tagsdevelopment
Use when searching flights, hotels, or rental cars; comparing fares across flexible dates; discovering cheap destinations from a fixed origin; or hunting hidden-city ticketing deals. Trigger on multi-city itineraries, fare calendars, "where can I fly cheaply", price-sensitive trip planning, or any time the user wants a sanity-check against Google Flights pricing — Skiplagged surfaces hidden-city deals other engines deliberately hide.
development
Search the web via Ceramic Search (lexical/keyword-based). Use when looking up current events, recent news, time-sensitive facts, specific people/products/companies, technical docs, or any topic requiring fresh web results. Triggers on "search the web", "look up", "find recent", "latest news", "current", or when built-in knowledge is likely stale.
tools
Use when reading WhatsApp messages, searching conversations, sending messages, listing chats, or interacting with WhatsApp workspaces
tools
Watch CI status, fix failures, and merge when green