Skip to content

feat(cli): add privacy-safe activity summaries - #116

Draft
abouchard11 wants to merge 1 commit into
ActivityWatch:masterfrom
abouchard11:agent/privacy-safe-summary
Draft

feat(cli): add privacy-safe activity summaries#116
abouchard11 wants to merge 1 commit into
ActivityWatch:masterfrom
abouchard11:agent/privacy-safe-summary

Conversation

@abouchard11

Copy link
Copy Markdown

Summary

  • add aw-client summary for bounded, AFK-filtered category, application, and domain totals
  • aggregate on the local ActivityWatch server and emit either a table or provider-neutral JSON
  • make application/domain inclusion optional and document exactly which fields are included or omitted
  • reuse the active client when loading category settings so host, port, testing mode, and authentication stay consistent

Why

ActivityWatch's agent/AI guidance recommends locally aggregated, review-before-send context instead of raw exports. Today, users need to write the query and normalization code themselves. This command turns that workflow into a reproducible CLI path without exposing raw titles, full URLs, document names, message subjects, or raw event history.

Related: ActivityWatch/activitywatch#1388
Related: ActivityWatch/aw-webui#925

Validation

  • ruff check aw_client tests/test_summary.py
  • ruff format --check aw_client tests/test_summary.py
  • mypy aw_client tests/test_summary.py
  • XDG_DATA_HOME=/tmp/activitywatch-test-data pytest -q tests/test_summary.py tests/test_auth.py tests/test_requestqueue.py — 17 passed
  • real-server integration test against seeded window, AFK, and browser buckets; verified aggregates and confirmed confidential titles and full URL paths were absent from output

@greptile-apps

greptile-apps Bot commented Aug 17, 2026

Copy link
Copy Markdown

Greptile Summary

The PR adds a locally aggregated aw-client summary command with table and JSON output, configurable application/domain inclusion, and consistent category-settings lookup through the active client.

  • Builds bounded category, application, and domain aggregates on the ActivityWatch server.
  • Adds normalization, redaction metadata, human-readable formatting, documentation, and focused tests.
  • Extends category-settings loading to reuse the caller's configured client.

Confidence Score: 3/5

The PR should not merge until browser buckets with unknown hostname metadata can no longer disclose another machine's domain activity in a host-specific summary.

The new selector assigns every legacy unknown-host browser bucket to any requested hostname, so shared-server deployments can mix another machine's overlapping browser activity into privacy-oriented output.

Files Needing Attention: aw_client/summary.py and tests/test_summary.py

Security Review

The browser-bucket selector can associate legacy unknown-host buckets from other machines with the requested hostname, allowing overlapping domain activity to appear in a host-specific summary.

Important Files Changed

Filename Overview
aw_client/summary.py Adds bucket discovery and summary formatting, but unknown-host bucket inclusion can mix browser activity across machines.
aw_client/queries.py Adds bounded server-side category, application, and domain aggregation using existing canonical event semantics.
aw_client/cli.py Adds the summary command and consistently reuses the active client for category settings.
aw_client/classes.py Generalizes category-settings retrieval to accept a compatible caller-provided client while preserving fallback behavior.
tests/test_summary.py Covers aggregation, redaction, formatting, and CLI output, but codifies globally accepting unknown-host browser buckets.
README.md Documents valid summary invocations, output sensitivity, and application/domain omission controls.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    CLI[summary command] --> Buckets[Discover browser buckets]
    Buckets --> Query[Build privacySummary query]
    Settings[Load category settings through active client] --> Query
    Query --> Server[Local ActivityWatch aggregation]
    Server --> Normalize[Normalize bounded result]
    Normalize --> JSON[Provider-neutral JSON]
    Normalize --> Table[Human-readable table]
Loading

Reviews (1): Last reviewed commit: "feat(cli): add privacy-safe activity sum..." | Re-trigger Greptile

Comment thread aw_client/summary.py
Comment on lines +20 to +22
bucket_hostname = bucket.get("hostname") or data.get("hostname")
if bucket_hostname not in (None, "", "unknown", hostname):
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Unknown buckets break host isolation

If a shared ActivityWatch server contains browser buckets from multiple machines with missing or unknown hostname metadata, this predicate assigns all of them to the requested host, causing overlapping domains and durations from another machine to appear in the host-specific summary. How this was verified: The selected buckets are passed into the summary query and combined when their events overlap the requested machine's active browser periods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant