Implement ActivityWatch metadata adapter #68
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
nsaspy/local-recall!68
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "agent/issue-16-activitywatch-metadata"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem and scope
Implements #16 as an optional ActivityWatch metadata enrichment source. It correlates a tiny local ActivityWatch window with the current Local Recall capture; it is not an ActivityWatch importer, history synchronizer, persistence layer, or provider connector.
Closes #16.
Architecture
ActivityWatchMetadataSourcebehind the existingMetadataSource/ContextMetadataboundary.DOMAINmetadata capability without changing Xorg/Qtile behavior.Transport and security model
127.0.0.1:5600.127.0.0.1,localhost, or::1; remote hosts, HTTPS, credentials, base paths, queries, and fragments are rejected.Bucket discovery
Bucket IDs are treated as opaque. Discovery uses validated bucket metadata/event type and host metadata rather than username/hostname-derived IDs. Compatible types include current-window, AFK status, and optionally current web tab. Local-host candidates are preferred. Cross-host ambiguity fails closed; same-host duplicates are bounded and resolved deterministically from correlated events.
Correlation semantics
URL/domain privacy
disabled.domain-only; there is no full-URL mode.AFK and normalized metadata
app-> canonicalapplication.title-> canonicalwindow.titlewhen title collection is enabled.afk/not-afkare accepted and normalized to bounded booleanidle.url.domainonly in domain-only mode.activitywatchprovenance and the stable adapter revision.Fallback and privacy boundary
ActivityWatch is optional. Unavailability/degradation produces sanitized failure state and does not disable a valid configured fallback such as generic Xorg. Synthetic integration coverage proves ActivityWatch metadata still crosses Local Recall's deterministic redaction boundary before downstream persistence eligibility. Disabled title/domain fields never appear downstream. ActivityWatch has no direct persistence or model-provider path.
TDD evidence
A test-only red phase was pushed before production implementation. CI run #274 passed formatting/lint/shell checks and then failed strict Pyright specifically because the ActivityWatch production config/types/source did not exist. Production code was added only after that observed red state.
Regression discoveries during implementation received tests for strict typing, hostile transport behavior, stale/duplicate correlation, old long-running events, future events, AFK conflicts, capability gating, redaction, fallback, and architecture boundaries.
Green evidence
The one-shot finalizer applied the last correlation/privacy regressions, removed its own temporary workflow/helper files, formatted the clean tree, and ran the canonical
./scripts/checksuccessfully in Actions run31614570141before committing the final tree.Final PR head
6e88ab24688147cad557f5c4062568f55ccd7d1ais an empty commit over that exact tested tree and passed normal CI run31614770100on Ubuntu 22.04 and 24.04, including:Acceptance criteria mapping
docs/activitywatch.mdplus configuration cross-reference.Known limitations
ActivityWatch's API remains version-unstable, so unsupported future schemas fail closed or degrade the optional source. This implementation intentionally does not copy the ActivityWatch database, synchronize history, collect full URLs, or contact a real ActivityWatch instance in CI. No real local smoke test was required or performed.