Repository navigation
Proactive reminders 3/3: 24/7 runtime and Slack/email delivery #355
Copy link
Copy link
Open
Labels
agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a templateMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a templatearea:automationScheduled tasks and automationScheduled tasks and automationenhancementNew feature or requestNew feature or request
Description
Why
Proactivity only counts if it works when the laptop is closed. Phase 3 makes reminders and schedules run 24/7 and reach the user outside the app.
Part of the 3-phase proactive-reminders track. Depends on phase 1 (event reminders), phase 2 (schedules) and #352 (isolated per-person deployment). Related: #349.
Scope
- 24/7 runtime: the deployed instance (Deployment step 1: official image and one isolated instance per person #352) runs schedules and event watchers continuously; reminders keep firing while the desktop app is closed.
- External channels: deliver reminders via Slack and email first (user opts in per channel), with a link back to the card or conversation.
- Reply path: approving from an external channel is allowed only through a verified, expiring link or an authenticated reply; never by an unauthenticated message.
- Reliability: at-least-once delivery with deduplication, retries with backoff, a visible delivery log, and an alert when the runtime itself is down.
- Resource limits: per-instance and per-task caps on loops, concurrency and cost ([Team] Bound agent loops and resource consumption #56) so one runaway Bot cannot flood the user.
- Privacy: external messages carry the minimum content; sensitive detail stays in the app.
- Personal vs team: team reminders go only to people with grants ([Team] Gate cross-owner agent routes by per-Bot grants (default deny; superseded the publication gate) #51); managers can see "assigned tasks stuck" for tasks they delegated; all sends are audited ([Team] Add a human-readable authorization and task audit trail #57).
Acceptance
- With the desktop app closed, a schedule fires and a reminder arrives in the opted-in channel within the expected window.
- Restarting or upgrading the instance does not lose or duplicate reminders.
- An external approval link works once, expires, and is rejected for the wrong user.
- Turning a channel off stops delivery immediately.
Open questions (decided 2026-10-21 by the Chief)
- Channel first: Slack. Email follows once the owner has supplied a credential. No real transport ships without one.
- Timezones: provisional — a reminder is rendered in the recipient's own local time; a team reminder fires on the instance's timezone. 暂定、可改 (changeable without reopening the design).
- Escalation when ignored: provisional — remind the same person once after the window, then let the assigner see it in their inbox; at most two sends per reminder. 暂定、可改.
Process (2026-10-21)
First half only: a delivery adapter with Slack's shape and a replaceable transport, tested against a fake Slack; the real Slack/email transport waits for a credential from the user (spec in the triage comment of 2026-10-21). Implemented by an agent and reviewed per .github/agent/review-policy.json. The earlier line about cloud OpenCode/Codex and "bots do not hand-write code" is void; it predates the owner decision of 2026-10-19.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a templateMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a templatearea:automationScheduled tasks and automationScheduled tasks and automationenhancementNew feature or requestNew feature or request
Activity
Birfy commentedon Oct 19, 2026
Triage on main
7b9e90b, 2026-10-19 ~12:10 Asia/Shanghai: needs-human, not agent-ready. Depends on #352 (deployment) and #353/#354; external delivery (Slack/email) also needs a decision on which connector and whose credentials.Birfy commentedon Oct 20, 2026
Triage (maintenance, 2026-10-20 08:04 Asia/Shanghai)
Checked on main
a45fc8c. No container image or headless runtime on main yet. #352 is still open and needs-human, so the 24/7 part cannot start. External delivery could use the owner's existing Composio connector (Gmail / Slack) incore/src/host/connectors.js.Conflict with the owner's rules (fixed in this triage)
The body allows approving "through a verified, expiring link or an authenticated reply". Approvals are given only with explicit UI buttons, never with a typed reply. So:
Expected behavior
With your opt-in, a reminder from #353/#354 also reaches you outside the app as a short line (who, why) plus a link back. It never carries the content of the chat or the tool call.
First slice (smallest shippable step, after #352 step 1)
Details I decided (say if you disagree)
Question for the owner
(a) Keep #355 parked until #352 step 1 ships, then start with email to yourself; (b) start now from the running desktop app (works only while it is open), 24/7 later; or (c) like (a), but Slack DM to yourself first.
Recommendation: (a).
Birfy commentedon Oct 20, 2026
Owner decision (2026-10-20): Confirmed option (a): wait for #352 (official image / one instance per person), then first send email-to-self. Off-app messages only carry a link back into the app — never approve by replying to the message.
Birfy commentedon Oct 20, 2026
Not started in this run (2026-10-20 08:55 Asia/Shanghai): per the Owner decision, this waits for #352 (official image / one instance per person), which is still open.
Birfy commentedon Oct 20, 2026
Claimed by maintenance run (2026-10-20 11:55 Asia/Shanghai, main
a7adfe0): developing on branchfeat/355-email-to-selfin Birfy/FlyBot, following the Owner decision above (first slice only).Birfy commentedon Oct 20, 2026
Email to yourself, first slice: details I decided (2026-10-20 12:05 Asia/Shanghai, PR #493)
Following the Owner decision (a). #352 is merged.
Coder finished,Coder failed: <reason>,Coder is waiting for your approval, plus the group name) and a link back into FlyBot. It never includes chat text, tool names or arguments. It ends with "Approve or reject only in FlyBot. Replies to this email are not read." No email can approve anything.docs/docker.md): you use your own mail account's SMTP server, so there is no third-party service and no relay we run.FLYBOT_SMTP_URL:smtps://means TLS on port 465;smtp://host:587means STARTTLS.FLYBOT_EMAIL_TO: the only recipient.FLYBOT_URL: the link in the email. Defaulthttp://127.0.0.1:3080/, which matches the SSH-tunnel setup in the guide.compose.yamlpasses all three through only when they are set. Any malformed value means no email is sent.SMTP_535,SMTP_TIMEOUT, …), never the server's text. The UI shows only the recipient address.node:net/node:tls).Merge origin/main into feat/355-email-to-self
2 remaining items
Birfy commentedon Oct 20, 2026
Releasing the claim (Birfy, 2026-10-20 22:06 Asia/Shanghai). The confirmed first slice (email to yourself, branch
feat/355-email-to-self, PR #493) was closed by the owner as won't-do on 2026-10-20 21:12, so this issue no longer has a confirmed scope. Removedagent-readyandagent-working; asking the owner whether to keep it parked for later (24/7 runtime, Slack delivery) or close it.Birfy commentedon Oct 20, 2026
Owner decision (2026-10-20 22:08 Asia/Shanghai): proceed WITHOUT email push. Scope = 24/7 running + Slack push only; drop all email delivery (#493 closed as won't-do). Not on hold.
Birfy commentedon Oct 20, 2026
Triage correction: this was
agent-ready, but it cannot be implemented from a repo change alone, so it becomesneeds-human.Blocking reasons: (1) a 24/7 runtime depends on the isolated per-person deployment (#352) and phases 1–2; (2) Slack and email delivery need channel credentials and an opt-in UI the repo does not have; (3) the issue itself leaves three owner questions open — which channel first, timezone handling inside a team, and the escalation when a reminder is ignored; (4) its Process line says implementation goes through cloud OpenCode and bots do not hand-write this code.
Removing
agent-ready; the maintenance routine will not open a branch for it.Birfy commentedon Oct 21, 2026
Triage spec (2026-10-21, main
16f50984).Acceptance
Scope: scheduler/automation and delivery in the host, the client delivery-log view, a Slack app configuration path, and docs; tests with a mock channel (dedupe + retry).
Gate: NOT agent-ready — it cannot be delivered from this repo alone: it needs a running isolated per-person instance (#352, built but not deployed) and Slack app credentials. Blocking: owner/deployment, not engineering. It turns agent-ready when #352 is live and Slack credentials exist.
Birfy commentedon Oct 21, 2026
Triage (2026-10-21): first half only, per the Chief's decision. The spec below is the spec of record. Not labelled
agent-readyyet — one item at a time, #356 first.In scope: a local delivery adapter with Slack's shape, tested against a fake Slack. Out of scope: the real Slack/email transport (waits for a user credential), 24/7 runtime (#352), external approval links.
Acceptance criteria
chat.postMessageshape:postMessage({ channel, text, blocks?, threadTs? })→{ ok, ts }or a typed failure (rate_limitedwithretryAfterMs,channel_not_found,network). The transport is injected; production Slack is not part of this PR.Retry-After; bounded attempts (3); a permanent failure (channel not found) is not retried.--importoffline guard where the suite already uses one); the retry test uses fake timers, not real sleeps.npm run verifygreen at the tip; the retry/idempotency tests fail against the code before the change.Change scope
core/src/host/notify.js(adapter + fake transport; name may change in review)core/test/notify.test.jsdocs/subsystems/core-host.md(it ownscore/src/host/)schedules.jsin this half — the adapter is standalone until the real channel landscore/client.jschangeProvisional, changeable: Slack first, email later; recipient-local time for rendering; one reminder nudge then the assigner's inbox, at most two sends.
Birfy commentedon Oct 21, 2026
Final triage state:
agent-ready, fourth in the Dev order. First half only, per the Chief: a transport-agnostic delivery adapter with Slack'schat.postMessageshape, a fake Slack transport, and at-least-once + dedupe/backoff tests. Real Slack/email transport, 24/7 runtime (#352) and external approval links stay out until a user credential exists. The v1 detail posted above is the spec of record.