Calendar → Clockify · Google Calendar · Microsoft 365/Outlook · free, no paid APIs
Sync your calendar events to Clockify time entries automatically. Supports Google Calendar (ICS link), Microsoft 365/Outlook (Microsoft Graph API with device code auth), and any ICS-compatible calendar.
| Source | Auth | What you need |
|---|---|---|
| Google Calendar | ICS private link | The "Secret iCal address" from Calendar settings |
| Microsoft 365 / Outlook | Device code OAuth | An Azure AD app registration (client ID only) |
| Any ICS calendar | ICS URL | A public or private ICS link |
git clone <repo-url> clocky-fill && cd clocky-fill
uv sync
# Configure
cp config.example.json config.json
cp project_map.example.csv project_map.csv
# Dry-run to preview
uv run clocky --date 2026-07-16 --dry-run
# Run for real
uv run clocky --date 2026-07-16
# Use Microsoft Graph
uv run clocky --source microsoft --date 2026-07-16 --dry-run| Field | Required | Description |
|---|---|---|
clockify_api_key |
✓ | Your Clockify API key |
workspace_id |
✓ | Clockify workspace ID |
default_project_id |
Fallback project when no rule matches | |
timezone |
IANA timezone (default: America/Mexico_City) |
|
source |
ics, microsoft, or auto (default: ics) |
|
ics_url |
for ICS | Private ICS link from Google/Outlook |
ms_client_id |
for Microsoft | Azure AD app registration client ID |
Security:
config.jsonis in.gitignore— never commit your real keys.
- Register an app in Azure AD:
- Supported account types: "Accounts in any organizational directory"
- Redirect URI:
http://localhost(not used, but required) - API permissions:
Calendars.Read(delegated)
- Under Authentication, enable: "Allow public client flows" → Yes
- Copy the Application (client) ID → put it in
config.jsonasms_client_id - On first run, a browser will open for device code authentication. The token is
cached in
~/.clocky_fill_ms_token.json(0600 permissions).
| Column | Description |
|---|---|
match_type |
contains (substring) or exact |
pattern |
Text to match in the event title |
project_id |
Clockify project ID (leave blank if skip=true) |
skip |
true → never sync, report for manual entry |
Rules are evaluated in order — the first match wins. Unmatched events fall
to default_project_id.
| What | Where |
|---|---|
| API key | Clockify → Profile Settings → API |
| Workspace ID | URL: app.clockify.me/workspaces/<ID>/... |
| Project IDs | GET /workspaces/<ID>/projects with X-Api-Key header |
| ICS URL | Google Calendar → Settings → calendar → "Secret iCal address" |
uv run clocky [OPTIONS]
| Flag | Description |
|---|---|
--date YYYY-MM-DD |
Single day (default: today) |
--from YYYY-MM-DD |
Start of date range |
--to YYYY-MM-DD |
End of date range |
--dry-run |
Preview without creating entries |
--source {ics,microsoft,auto} |
Calendar source (default: auto) |
--config PATH |
Custom config path |
--map PATH |
Custom map path |
--log PATH |
Custom log path |
-v, --verbose |
Show debug output |
0 23 * * * cd /path/to/clocky-fill && UV_LINK_MODE=copy /path/to/uv run clocky >> sync.log 2>&1
- Program:
uv - Arguments:
run clocky - Start in: project folder
clocky_fill/
├── __init__.py # package metadata (v0.3.0)
├── cli.py # argparse + rich UI
├── config.py # Config dataclass + validation
├── sync.py # orchestration: fetch → match → create
├── project_map.py # CSV rule loading + event→project matching
├── clockify.py # Clockify REST API client
├── log.py # synced_log.json persistence (dedup)
├── calendar.py # compatibility re-exports
└── providers/
├── __init__.py # CalendarProvider ABC + CalendarEvent
├── ics.py # ICSCalendarProvider (Google, Outlook ICS, …)
└── microsoft.py # MicrosoftGraphProvider (device-code OAuth2)
tests/
├── conftest.py # shared fixtures
├── test_config.py # config validation tests
├── test_project_map.py # CSV loading + matching tests
├── test_clockify.py # Clockify API client tests
├── test_log.py # synced_log persistence tests
├── test_sync.py # orchestration tests
├── test_providers_ics.py # ICS provider tests
└── test_providers_microsoft.py # Microsoft Graph provider tests
uv run ruff check clocky_fill/ tests/ # lint
uv run ruff format clocky_fill/ tests/ # format
uv run pyright clocky_fill/ # type-check
uv run pytest tests/ -v # run tests (41/41)
uv run pytest tests/ --cov=clocky_fill # with coverage- All-day events are skipped (Clockify handles them differently).
- Recurring events are expanded automatically (ICS provider).
synced_log.jsonprevents duplicate entries across multiple runs.- No paid APIs: Google Calendar ICS is free, Clockify API is free on all plans, and Microsoft Graph API with Calendars.Read is free.
MIT