diff --git a/AUTOMATED_DEV.md b/AUTOMATED_DEV.md index 3e4a3de..86512b1 100644 --- a/AUTOMATED_DEV.md +++ b/AUTOMATED_DEV.md @@ -226,13 +226,26 @@ Docker build, and branch protection enforces CI. No single point of failure. Every repo has a Gitea webhook that sends all activity (pushes, PRs, issues, comments, reviews, CI status) to a channel in our self-hosted [Mattermost](https://mattermost.com) instance. This creates a real-time feed -where everyone — human and agent — can see what's happening across all projects -without cross-communication overhead. +where the human can see what's happening across all projects without checking +Gitea's notification inbox. -The agent also has its own Mattermost bot user (`@claw`), separate from the -human. This means: +**Important caveat:** The agent can't see this feed directly. Gitea's webhook +messages arrive in Mattermost as a "bot" integration user. Mattermost +deliberately hides bot messages from other bot users to prevent infinite +bot-to-bot loops. This means the agent's Mattermost bot account is blind to the +Gitea webhook feed, even though it's posted in a channel the agent has access +to. -- The agent posts status updates to dedicated channels (`#git` for Gitea work, +This is why we built the [notification poller](#the-notification-poller) — a +separate Python script that polls Gitea's notification API directly, bypassing +Mattermost entirely. The human sees Gitea activity via the Mattermost webhook +feed; the agent sees it via the API poller. Same events, different delivery +paths, because of a Mattermost platform limitation. + +The agent has its own Mattermost bot user (`@claw`), separate from the human. +This means: + +- The agent posts status updates to dedicated channels (`#git` for work status, `#claw` for general work narration) - The human's DMs stay clean — only direct alerts and responses - In group channels, it's clear who said what @@ -243,16 +256,33 @@ human. This means: A practical setup: - **#git** — Real-time Gitea webhook feed (all repos) + agent's work status - updates. Everyone sees commits, PRs, reviews, CI results as they happen. + updates. The human sees commits, PRs, reviews, CI results as they happen. (The + agent posts here but can't read the webhook messages — see caveat above.) - **#claw** — Agent's internal work narration. Useful for debugging what the agent is doing, but notifications muted so it doesn't disturb anyone. - **DM with agent** — Private conversation, sitreps, sensitive commands - **Project-specific channels** — For coordination with external collaborators -The webhook feed in #git means nobody needs to check Gitea's notification inbox -manually. PRs, reviews, and CI results flow into a channel that's always open. -The agent monitors the same feed (via its notification poller) and can react to -events in near-realtime. +### The Notification Poller + +Because the agent can't see Gitea webhooks in Mattermost (bot-to-bot visibility +issue), we built a lightweight Python script that polls the Gitea notifications +API every 2 seconds and wakes the agent via OpenClaw's `/hooks/wake` endpoint +when new notifications arrive. + +Key design decisions: + +- **The poller never marks notifications as read.** That's the agent's job after + processing. Prevents the poller and agent from racing. +- **Tracks notification IDs, not counts.** Only fires on genuinely new + notifications, not re-reads of existing ones. +- **The wake message tells the agent to route output to Gitea/Mattermost, not + DM.** Prevents chatty notification processing from disturbing the human. +- **Zero dependencies.** Python stdlib only (`urllib`, `json`, `time`). Runs + anywhere. + +Full source code is available in +[OPENCLAW_TRICKS.md](OPENCLAW_TRICKS.md#the-gitea-notification-poller). ## CI: Gitea Actions