Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
af6af33
docs(notifications): specify act buttons, Discord bot mode, the ntfy …
arg1998 Sep 29, 2026
ef33e0d
docs(notifications): tokens are minted per call, and only the produce…
arg1998 Sep 29, 2026
a9d1cf7
feat(contracts): act-button audit, Discord bot setup, listener state …
arg1998 Sep 29, 2026
c98c9e1
feat(persistence): schema v6 with act-button tokens, the press audit …
arg1998 Sep 29, 2026
47b3983
feat(notifications): act buttons on Telegram, Discord bot mode and nt…
arg1998 Sep 29, 2026
898703a
feat(cli): channels list shows the Discord mode and whether chat answ…
arg1998 Sep 29, 2026
f316a18
ci(notifications): live check covers Rich Messages with act buttons, …
arg1998 Sep 29, 2026
ae5da81
docs(notifications): answer from your phone — act buttons per platfor…
arg1998 Sep 29, 2026
abbd04c
docs(notifications): listener retry timings as built
arg1998 Sep 29, 2026
03389da
fix(notifications): quick first Telegram poll, named Discord form err…
arg1998 Sep 29, 2026
61c7433
docs(notifications): Discord bot setup click-path with its pitfalls, …
arg1998 Sep 29, 2026
9723065
docs(notifications): allowed people, allow a refused presser from the…
arg1998 Sep 29, 2026
259b43b
feat(notifications): a refused presser is told privately where the ad…
arg1998 Sep 29, 2026
87d40e8
fix(notifications): the preview reads a draft's secret names, and a b…
arg1998 Sep 29, 2026
01ab63f
feat(dashboard): answer from the chat — act-button settings, allowed …
arg1998 Sep 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .changeset/notification-act-buttons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"browserhive": minor
---

Answer from your phone: Approve, Reject and Mark resolved right in Telegram, Discord and ntfy, and richer Telegram messages.

- **Answer without opening the dashboard.** Switch on **Answer from the chat** for a channel, and a notification that waits for you carries buttons that act: **Mark resolved** and **Reject** for an attention request, **Approve** and **Deny** for a vault fill. Press one and BrowserHive does what the same button in the dashboard does, then edits the message: the buttons disappear and it says who answered ("Resolved on Telegram by … after 42 s"). Off by default.
- **Only the right person, only once.** On Telegram and Discord only the accounts on the channel's allow-list may press; by default that is the person who connected the chat, and anyone else is told their id so you can add them. Every button works once, for 24 hours, only in its own chat, and only while the request still waits. Every press is listed under the new **Notifications → Actions**. The agent learns that you answered from Telegram, Discord or ntfy, never your chat identity.
- **Discord bot mode.** A Discord channel can now use a bot instead of a webhook, the only way to press buttons in Discord. The wizard walks through the Developer Portal, builds the invite link with the minimal permissions, lists your servers and channels, and links your account with a **This is me** button. The channel card shows whether the bot is connected.
- **ntfy answers through a second topic.** Give an ntfy channel a reply topic, and its buttons make your phone post the answer there; BrowserHive listens and updates the notification. Works on Android and iOS.
- **Nothing to expose.** Every connection goes out from your machine (Telegram long polling, the Discord gateway, an ntfy subscription). Presses made while BrowserHive was stopped are handled at the next start when the platform kept them. The webhook channel carries the act actions as they are, and your receiver answers through the REST API.
- **Telegram Rich Messages.** Telegram notifications now have a heading, the facts as a table, real tables, collapsible quotes and coloured buttons, with the screenshot inside the message. If Telegram refuses one, the classic format is sent instead.
- **Setup and terminal.** Startup channels take `actButtons=true` and `allow=<user ids>`, `mode=bot` for Discord and `reply=` for ntfy. `browserhive channels list` shows whether answers reach BrowserHive.
- New REST endpoints: `GET /api/v1/channels/actions` and the Discord bot setup under `/api/v1/channels/discord/…`; channels report `connection`; the `channels` WebSocket topic adds `action.recorded`. The database moves to schema v6 (three new tables; an older release still opens it).
8 changes: 6 additions & 2 deletions .github/workflows/notify-live.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
name: notify-live

# Live notification check (spec 09 §8): real Telegram, a Discord webhook and ntfy, through the
# real adapters: send with a screenshot, read back where the platform allows, edit, delete. It
# Live notification check (spec 09 §8): real Telegram (a Rich Message with act buttons), a Discord
# webhook, a Discord bot (gateway and interactive buttons) and ntfy (with a reply-topic round
# trip), through the real adapters: send with a screenshot, read back where the platform allows,
# edit, delete. It
# guards against the fakes drifting from the platforms. Runs weekly, on dispatch, and on pull
# requests labelled `live-notify` from this repository (never from forks). The `notify-live`
# environment holds the secrets and needs the owner's approval. A platform whose secrets are not
Expand Down Expand Up @@ -47,6 +49,8 @@ jobs:
TG_BOT_TOKEN: ${{ secrets.TG_BOT_TOKEN }}
TG_CHAT_ID: ${{ secrets.TG_CHAT_ID }}
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
DISCORD_CHANNEL_ID: ${{ secrets.DISCORD_CHANNEL_ID }}
NTFY_TOPIC: ${{ secrets.NTFY_TOPIC }}
run: bun scripts/notify-live.ts
- name: Open or update the drift issue
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/attention.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Outcomes:

## The operator's side

A new request shows up as a notification, on the **Attention** page, and as a banner on the session's page.
A new request shows up as a notification, on the **Attention** page, and as a banner on the session's page. With a [notification channel](notifications.md#channels) it reaches your phone too, and with act buttons on you can answer it there ([answer from your phone](notifications.md#answer-from-your-phone)); the agent's result then says `resolved_by: "telegram"` (or `discord`, `ntfy`), never your chat identity.

1. Open the request. You see the reason, mode, options and how long the agent has been waiting.
2. For `takeover` requests, click **Open live & take over**. The live view accepts your mouse, wheel, keyboard and touch input and sends it to the agent's browser. Input is allowed only while this request is open and is checked on every event.
Expand Down
8 changes: 4 additions & 4 deletions docs/guide/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ A list value joins its items with `+`; a value cannot contain `,` (write `%2C`).
| Platform | Parameters |
|---|---|
| `telegram` | `name`, `token=env:NAME`, `chat` (a chat id), optional `thread` (a forum topic id) |
| `discord` | `name`, `webhook=env:NAME` (the webhook URL), optional `mode=webhook` |
| `ntfy` | `name`, `topic` (a topic, or `env:NAME`), optional `server` (default `https://ntfy.sh`), `token=env:NAME` |
| `discord` | webhook mode: `name`, `webhook=env:NAME` (the webhook URL). Bot mode: `name`, `mode=bot`, `token=env:NAME` (the bot token), `channel` (the channel id), optional `guild` (the server id) |
| `ntfy` | `name`, `topic` (a topic, or `env:NAME`), optional `server` (default `https://ntfy.sh`), `token=env:NAME`, `reply` (the [reply topic](notifications.md#ntfy-a-second-topic-for-answers) for act buttons, or `env:NAME`), `replyToken=env:NAME` |
| `webhook` | `name`, `url` (a URL, or `env:NAME`), optional `secret=env:NAME` (the signing key) |

Rules, all optional: `categories` (`needs-you+problems+wrap-ups+reports+system`), `min` (`info`, `warn`, `error`, `critical`), `sessions` (session name patterns such as `shop-*`), `harness`, `content` (`counts`, `titles`, `full`), `quiet=22:00-07:00` with `tz=Europe/Berlin`, `ttl.<category>=2h` (Telegram at most `47h`), `deleteWhenResolved` (`true`, or a `+` list of categories), `images` (a `+` list of categories; needs `content=full`) and `maskImages=true`.
Rules, all optional: `categories` (`needs-you+problems+wrap-ups+reports+system`), `min` (`info`, `warn`, `error`, `critical`), `sessions` (session name patterns such as `shop-*`), `harness`, `content` (`counts`, `titles`, `full`), `quiet=22:00-07:00` with `tz=Europe/Berlin`, `ttl.<category>=2h` (Telegram at most `47h`), `deleteWhenResolved` (`true`, or a `+` list of categories), `images` (a `+` list of categories; needs `content=full`), `maskImages=true`, `actButtons=true` ([answer from your phone](notifications.md#answer-from-your-phone); Telegram, Discord bot mode, ntfy with `reply`, webhook) and `allow` (a `+` list of Telegram or Discord user ids allowed to press them; not for ntfy).

## `init`

Expand Down Expand Up @@ -139,7 +139,7 @@ Token commands work on the database directly when the server is stopped, or thro

| Command | Meaning |
|---|---|
| `channels list [--json]` | Every notification channel: platform, status (and "from startup"), where it sends, whether its variables are set, the last delivery and the last 24 hours. |
| `channels list [--json]` | Every notification channel: platform (with the Discord mode), status (and "from startup"), where it sends, whether its variables are set, whether chat answers reach BrowserHive (`connected`, `reconnecting`, `offline (reason)`, or `—` when act buttons are off), the last delivery and the last 24 hours. |
| `channels test <name> [--json]` | Sends a real test message. Exit `0` when the platform accepted it, `1` with the reason when it did not. |
| `channels preview <name> [--sample <kind>] [--json]` | Prints the platform request a send would make (secrets shown as variable names); sends nothing. Samples: `attention` (default), `attention-resolved`, `vault-confirm`, `tool-errors`, `crash`, `degraded`, `test`. |

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,4 @@ Version, transport, uptime, bind address, sessions live versus the cap, open att

Persisted notifications for attention requests, tool errors, crashed sessions and pending vault confirmations, grouped by day. Mark as read or dismiss, individually or all at once. Once an attention request or vault confirmation is settled (in the dashboard, by a timeout, or elsewhere), its row keeps its place and shows the outcome as a small pill (**resolved**, **expired**, or **closed** when the agent stopped waiting), and a toast still on screen for it closes. See [Notifications](notifications.md).

**Channels** (Notifications → Channels) sends notifications to your phone through Telegram, Discord, ntfy or a webhook: one card per channel with its status, last delivery and 24-hour counts, and an **Add channel** wizard with a live preview and a test message. **Delivery log** lists every send, edit and delete, and says why anything was not sent. See [Channels](notifications.md#channels).
**Channels** (Notifications → Channels) sends notifications to your phone through Telegram, Discord (webhook or bot), ntfy or a webhook: one card per channel with its status, last delivery, 24-hour counts and, when act buttons are on, whether answers from the chat reach BrowserHive; and an **Add channel** wizard with a live preview and a test message. Its **What to send** step switches **Answer from the chat** on and edits who may answer. **Delivery log** lists every send, edit and delete, and says why anything was not sent. **Actions** lists every press of an act button: who, which button, from which chat, and what happened. See [Channels](notifications.md#channels) and [Answer from your phone](notifications.md#answer-from-your-phone).
Loading
Loading