adapters.activitywatch¶
ActivityWatch adapter: data ingestion from AW JSON exports and the AW REST API.
Error handling¶
All REST API functions raise typed exceptions so callers can distinguish failure modes and respond accordingly:
AWConnectionError-- the AW server is unreachable or refused the connection (wrapsConnectionRefusedError,ConnectionResetError,urllib.error.URLError).AWTimeoutError-- the AW server did not respond within the configured timeout (wrapsTimeoutError,socket.timeout).
All REST functions accept an optional timeout keyword argument
(default: DEFAULT_AW_TIMEOUT_SECONDS = 10). The tray app exposes
this as the aw_timeout_seconds config setting and --aw-timeout CLI
flag.
When the tray polls AW and encounters repeated failures, it applies
adaptive backoff: connection-refused errors progressively increase
the sleep between polls (exponential, capped at 5 minutes), while
timeout errors keep the normal polling interval (since the timeout
itself is already the wait). After 3 consecutive failures a WARNING
is logged and an aw_unreachable status event is published to the
web UI. On recovery, an INFO message is logged and the backoff resets.
types¶
taskclf.adapters.activitywatch.types
¶
Privacy-safe normalized event types for ActivityWatch data.
AWEvent
¶
Bases: BaseModel
A single ActivityWatch window event, normalized and privacy-scrubbed.
Raw app names are mapped to reverse-domain identifiers via
:func:~taskclf.adapters.activitywatch.mapping.normalize_app.
Raw title strings are replaced with a salted hash via
:func:~taskclf.core.hashing.salted_hash -- the original title
is never persisted.
Source code in src/taskclf/adapters/activitywatch/types.py
AWInputEvent
¶
Bases: BaseModel
Aggregated keyboard/mouse activity from aw-watcher-input.
Each event covers a short polling interval (typically 5 s) and carries only aggregate counts -- never individual key identities. This makes the type privacy-safe by construction.
The upstream AW fields deltaX/deltaY and scrollX/scrollY
are mapped to snake_case for consistency with project conventions.
Source code in src/taskclf/adapters/activitywatch/types.py
mapping¶
taskclf.adapters.activitywatch.mapping
¶
App-name normalization, classification, and category assignment.
ActivityWatch reports the foreground application as a human-readable
name (e.g. "Firefox", "Code"). This module maps those names
to reverse-domain identifiers, boolean flags, and a semantic category
consumed by :class:~taskclf.core.types.FeatureRow.
normalize_app(app_name)
¶
Map an AW application name to a reverse-domain ID, flags, and category.
Performs a case-insensitive lookup in :data:KNOWN_APPS. Unknown
applications fall back to "unknown.<sanitized_name>" with all
flags set to False and category "other".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
app_name
|
str
|
Application name as reported by ActivityWatch
(e.g. |
required |
Returns:
| Type | Description |
|---|---|
AppInfo
|
A |
AppInfo
|
tuple. |
Source code in src/taskclf/adapters/activitywatch/mapping.py
client¶
taskclf.adapters.activitywatch.client
¶
ActivityWatch data access: JSON export parsing and REST API client.
Provides two data-ingestion paths:
- File-based -- :func:
parse_aw_exportreads an AW JSON export (the format produced by Export all buckets as JSON in the AW web UI orGET /api/0/export). - REST-based -- :func:
fetch_aw_eventsqueries a runningaw-serverinstance for events in a time range.
Both paths normalize application names via
:func:~taskclf.adapters.activitywatch.mapping.normalize_app and
replace raw window titles with salted hashes so that no sensitive text
is ever persisted.
AWConnectionError
¶
Bases: OSError
The ActivityWatch server refused the connection or is unreachable.
Source code in src/taskclf/adapters/activitywatch/client.py
AWTimeoutError
¶
Bases: OSError
The ActivityWatch server did not respond within the timeout.
Source code in src/taskclf/adapters/activitywatch/client.py
AWNotFoundError
¶
Bases: OSError
The ActivityWatch resource was not found (HTTP 404).
Source code in src/taskclf/adapters/activitywatch/client.py
parse_aw_export(path, *, title_salt)
¶
Parse an ActivityWatch JSON export file into normalized events.
Filters for buckets of type currentwindow (i.e.
aw-watcher-window data). Each event's application name is
normalized and its window title is replaced with a salted hash.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
Path to the AW export JSON file. |
required |
title_salt
|
str
|
Salt used for hashing window titles. |
required |
Returns:
| Type | Description |
|---|---|
list[AWEvent]
|
Sorted (by timestamp) list of :class: |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If path does not exist. |
KeyError
|
If the JSON structure is missing expected keys. |
Source code in src/taskclf/adapters/activitywatch/client.py
parse_aw_input_export(path)
¶
Parse aw-watcher-input events from an AW JSON export.
Filters for buckets of type os.hid.input. These events carry
only aggregate counts (key presses, mouse clicks, movement, scroll)
and contain no sensitive payload.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
Path to the AW export JSON file. |
required |
Returns:
| Type | Description |
|---|---|
list[AWInputEvent]
|
Sorted (by timestamp) list of :class: |
list[AWInputEvent]
|
Empty if no |
Source code in src/taskclf/adapters/activitywatch/client.py
list_aw_buckets(host, *, timeout=DEFAULT_AW_TIMEOUT_SECONDS)
¶
List all buckets from a running AW server.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
host
|
str
|
Base URL of the AW server (e.g. |
required |
timeout
|
int
|
Seconds to wait for a response. |
DEFAULT_AW_TIMEOUT_SECONDS
|
Returns:
| Type | Description |
|---|---|
dict[str, dict]
|
Dict mapping bucket IDs to their metadata. |
Source code in src/taskclf/adapters/activitywatch/client.py
find_window_bucket_id(host, *, timeout=DEFAULT_AW_TIMEOUT_SECONDS)
¶
Auto-discover the aw-watcher-window bucket on host.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
host
|
str
|
Base URL of the AW server. |
required |
timeout
|
int
|
Seconds to wait for a response. |
DEFAULT_AW_TIMEOUT_SECONDS
|
Returns:
| Type | Description |
|---|---|
str
|
The bucket ID whose |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no |
Source code in src/taskclf/adapters/activitywatch/client.py
find_input_bucket_id(host, *, timeout=DEFAULT_AW_TIMEOUT_SECONDS)
¶
Auto-discover the aw-watcher-input bucket on host.
Unlike :func:find_window_bucket_id, this returns None when no
input bucket exists because aw-watcher-input is an optional
watcher that many users don't run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
host
|
str
|
Base URL of the AW server. |
required |
timeout
|
int
|
Seconds to wait for a response. |
DEFAULT_AW_TIMEOUT_SECONDS
|
Returns:
| Type | Description |
|---|---|
str | None
|
The bucket ID whose |
Source code in src/taskclf/adapters/activitywatch/client.py
fetch_aw_events(host, bucket_id, start, end, *, title_salt, timeout=DEFAULT_AW_TIMEOUT_SECONDS)
¶
Fetch events from the AW REST API for a time range.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
host
|
str
|
Base URL of the AW server (e.g. |
required |
bucket_id
|
str
|
Bucket to query (e.g. |
required |
start
|
datetime
|
Inclusive start of the query window (UTC). |
required |
end
|
datetime
|
Exclusive end of the query window (UTC). |
required |
title_salt
|
str
|
Salt used for hashing window titles. |
required |
timeout
|
int
|
Seconds to wait for a response. |
DEFAULT_AW_TIMEOUT_SECONDS
|
Returns:
| Type | Description |
|---|---|
list[AWEvent]
|
Sorted list of :class: |
Source code in src/taskclf/adapters/activitywatch/client.py
fetch_aw_input_events(host, bucket_id, start, end, *, timeout=DEFAULT_AW_TIMEOUT_SECONDS)
¶
Fetch input events from the AW REST API for a time range.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
host
|
str
|
Base URL of the AW server. |
required |
bucket_id
|
str
|
Input bucket to query (e.g.
|
required |
start
|
datetime
|
Inclusive start of the query window (UTC). |
required |
end
|
datetime
|
Exclusive end of the query window (UTC). |
required |
timeout
|
int
|
Seconds to wait for a response. |
DEFAULT_AW_TIMEOUT_SECONDS
|
Returns:
| Type | Description |
|---|---|
list[AWInputEvent]
|
Sorted list of :class: |