8000 feat(automations): tell a person in their own chat app, the notify action by adeelahmad · Pull Request #433 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(automations): tell a person in their own chat app, the notify action - #433

Merged
adeelahmad merged 2 commits into
mainfrom
claude/project-thread-mwk71t
Oct 15, 2026
Merged

adeelahmad merged 2 commits into
mainfrom
claude/project-thread-mwk71t

Conversation

@adeelahmad
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: automations had one action, log_line, and Lens had no way to message a person unprompted: a chat channel could only reply to a message it had just received.

After: the notify action (workflow studio M7, first group: Messages) sends a message to one of three places:

  • me: the automation's own person, in their chat app. Each chat channel now keeps the private chat it last had with someone on its list of people who may talk to Lens (chat_route:<channel>), and channels.tell(db, cfg, account, text, links=()) sends there through every channel that answers as that account. Effect self, so it runs without asking.
  • target:<id>: one of the namespace's notification targets (webhook, Matterbridge, Slack, Discord), through notify.send.
  • gateway:<name>: a Matterbridge room, through the bridge.

The last two reach other people, so their effect is out and they ask first unless the person set that node to run on its own. dry says where it would go and sends nothing. The result names each channel and chat used, so M8 can match a "yes" there to an approval.

Motivation and Context

Workflow studio, module M7 (plan: /mnt/project-files/workflow-studio/plan.md §5 M7). This is the "tell me in Telegram" step of the worked example; the other action groups (AI, web, Lens work, assets) follow in their own PRs.

Choices taken (reversible), differing from the brief's wording:

  • Private chats only, with someone the channel vouches for. The brief says "the reply target of the last message it handled". Taken literally, "tell me" could land in a family group (other people read it) or in a stranger's DM on a Slack app with no users list. So a route is kept only for a private chat (Telegram private chat, Slack DM) whose sender is on the channel's users list, and is re-checked when sending. Matterbridge never counts as private (its gateways are rooms); gateway:<name> reaches it and asks first.
  • Links. When the intent's untrusted is set (the run read outside text), web addresses are broken up (hxxps://evil[.]example/...) except Lens's own; when it read none, the person wrote them and they stay. This uses bridge.safe_links and untrusted.defang.
  • Who may send where. A notification target must be in the automation's namespaces and switched on, and the person must be able to edit that namespace. A Matterbridge gateway needs the bridge on and answering as the person, or the person to be an admin.
  • actions.person(db, intent, user) gives the account an intent acts for, as it is now. A switched-off or removed person makes every action refuse.

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 (ruff, ruff format, mypy clean locally).
  • I added or updated tests (tests/api/test_actions_messages.py: routes kept only for vouched private chats, latest wins, re-checked on send; Telegram and Slack; notify to me, a webhook target and a Matterbridge gateway; dry runs; risk; links broken up or kept).
  • My change requires documentation updates, and I have updated docs/ accordingly (docs/automations.md Actions table and "Telling a person", docs/chat-rooms.md "Telling you things").
  • Users need more than the title: n/a, nothing is reachable by people until the engine (M6) runs automations.

Done questions (AGENTS.md)

  • Goal: the Messages group of M7, merged on green CI.
  • Agents: the action is in actions.catalog(), which M6 serves at GET /api/v1/automations/actions and to MCP and the assistant.
  • Zero setup: once someone messages the bot privately, "tell me" works; nothing else to set.
  • Fewest clicks: no setting; the route is learned from the chat.
  • Configurable: n/a, no new setting.
  • Light: no new dependency or service.
  • Private and secure: never a room; only people the channel lets in; N-BRIDGE updated in the threat model (md, yaml, json).
  • Cost: no model call; each send goes in the activity ledger (chat.<channel>).
  • User decides: anything reaching other people is out and asks first; defaults unchanged.
  • Upgrades: a new table (chat_route), no change to stored data.
  • Honest: docs label it built; the rest of the studio stays planned.
  • Tests, docs and generated files updated (no API change, so no OpenAPI change).
  • Open standards; no new dependency.
  • Refine later written in docs/automations.md: chat approval buttons, email and web push as channels, private chats through Matterbridge, "me" with several people let in, which template links to keep.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CyjR2zEfmTXBewKAx9Taw5


Generated by Claude Code

…tion

An automation can now tell someone something. Each chat channel keeps the
private chat it last had with someone on its list of people who may talk
to Lens (chat_route), and channels.tell sends there, as the account the
bot or app answers as. The notify action uses it for "me" (routine: only
they read it) and also sends to a namespace's notification target or a
Matterbridge gateway, which reach other people and so ask first. Links
an injection could fill are broken up when the run read outside text.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CyjR2zEfmTXBewKAx9Taw5
@adeelahmad adeelahmad self-assigned this Oct 15, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CyjR2zEfmTXBewKAx9Taw5
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