8000 feat(timeline): mute a source, a person or a kind, for good or until a time, for yourself alone by adeelahmad · Pull Request #635 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(timeline): mute a source, a person or a kind, for good or until a time, for yourself alone - #635

Merged
adeelahmad merged 1 commit into
mainfrom
claude/project-thread-pf8kii
Oct 18, 2026
Merged

adeelahmad merged 1 commit into
mainfrom
claude/project-thread-pf8kii

Conversation

@adeelahmad
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: the only way to get a noisy source off your timeline was to hide its items one at a time, and the next one came back.

After: an opened item has Mute Work Gmail: everything from that source or person leaves your timeline, with Undo in the message, and a Muted row above the list shows what you muted with an × to lift each one. Muting hides, it never deletes: the activities stay stored, still trigger automations and still show to everyone else, and hidden=true on the timeline shows them to you, as what you hid. Agents mute a source or person (actor) or a kind of activity (kind, the kinds under it too), for good or until a time (snooze it for a day), with POST /api/v1/activities/mute and GET /api/v1/activities/mutes, the MCP mute_activities and activity_mutes tools (and hidden on timeline to read what was hid or muted), and the assistant's mute_activities, which acts at once but asks first after it has read text from outside Lens, as hiding does.

How: domain/event_mutes.py keeps one event_mute row per person and target (an actor id or a kind) with the name shown, until and when it was set; a mute that has run out is dropped the next time the person's mutes are read, and a person's rows go when they are removed. event_mutes.keeper replaces event_marks.keeper in the timeline route and the assistant: a muted actor's or kind's activities count as hidden for that person, so the page (hidden=false) leaves them out, hidden=true shows them, and a For you page scores only what is left. The page's useMutes hook reloads the timeline after a mute and filters the items already loaded at once.

Motivation and Context

Step 7 of the activity stream design (thread above): "Mute. Each person mutes a source or a kind ('hide syslog') or snoozes it for a day. Muting hides; it never deletes." Follows #570, #622, #627 and #631.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change; ! in the title)

Checklist:

  • The title is a Conventional Commit.
  • My code follows the code style of this project (make hooks checks it on commit).
  • I added or updated tests.
  • My change requires documentation updates, and I have updated docs/ accordingly.
  • Users need more than the title to understand it, so I wrote it as a fragment in changelog.d/ (timeline-mutes.md).

Done questions (AGENTS.md)

  • Goal: a lasting "leave everything from this out" per person, on the page and for agents, with nothing lost; merged on green CI.
  • Agents: POST /api/v1/activities/mute, GET /api/v1/activities/mutes, MCP mute_activities and activity_mutes, the assistant's mute_activities.
  • Zero setup: nothing to configure.
  • Fewest clicks: one click on Mute, Undo in the message rather than a confirm, one click on the chip's × to lift it.
  • Configurable: n/a, no new setting; mutes are per person, set where the items are.
  • Light: one small query per page for the person's mutes, applied in the same per-page query as the mark filters; no model call.
  • Private and secure: a person's mutes are their own, over activities they can already read; nothing changes for anyone else and nothing is deleted. No new surface for the threat model.
  • Cost: no model call; nothing in the ledger to log.
  • User decides: muting is the person's own click; the assistant asks first after outside text; existing defaults unchanged.
  • Upgrades: a new table, created on start with DEFINE TABLE IF NOT EXISTS; nothing existing changes shape, so no migration step.
  • Honest: docs/timeline.md's status table lists muting as built, with muting a kind or until a time from the page under Refine later; the README's built line names it.
  • Tested and documented: test_timeline_mutes.py (actor and kind, hidden filters, snooze and expiry, bad asks, removal, MCP, read-only token, assistant at once and asking first), jest timeline-ui.test.tsx (Mute, the Muted chip, Undo); docs timeline.md (Muting section), mcp.md, assistant.md, automations.md, requirements.md, changelog.d; make openapi regenerated the client.
  • Open standards: the same Activity Streams 2.0 page; no new dependency.
  • Reported: result goes back in the thread; refine later: muting a kind or for a day from the page (a menu on Mute), a muted actor's own line in the Filters.
  • Reuse: the marks keeper shape, the approval path hiding already uses, the page's toast with Undo and the timeline queries; no new machinery.

Local CI (ci/local-ci.sh) on this head: running; CI on the PR decides the merge.


Generated by Claude Code

…a time, for yourself alone

An opened item's Mute button and a Muted row with unmute on the Timeline page; POST /api/v1/activities/mute and GET /activities/mutes; MCP mute_activities and activity_mutes; the assistant's mute_activities, which asks first after outside text. A muted actor's or kind's activities count as hidden for the person: left out of the page, shown by hidden=true, never deleted, still seen by everyone else.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ln25ykE6uBDqx21WBU94SX
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.

2 participants

0