fix: agent can't see Gitea webhooks in Mattermost (bot-to-bot limitation)
All checks were successful
check / check (push) Successful in 11s
All checks were successful
check / check (push) Successful in 11s
Mattermost hides bot messages from other bots to prevent loops. Document why the notification poller exists as a workaround.
This commit is contained in:
parent
a6cd3e5997
commit
4f68638a28
@ -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,
|
Every repo has a Gitea webhook that sends all activity (pushes, PRs, issues,
|
||||||
comments, reviews, CI status) to a channel in our self-hosted
|
comments, reviews, CI status) to a channel in our self-hosted
|
||||||
[Mattermost](https://mattermost.com) instance. This creates a real-time feed
|
[Mattermost](https://mattermost.com) instance. This creates a real-time feed
|
||||||
where everyone — human and agent — can see what's happening across all projects
|
where the human can see what's happening across all projects without checking
|
||||||
without cross-communication overhead.
|
Gitea's notification inbox.
|
||||||
|
|
||||||
The agent also has its own Mattermost bot user (`@claw`), separate from the
|
**Important caveat:** The agent can't see this feed directly. Gitea's webhook
|
||||||
human. This means:
|
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)
|
`#claw` for general work narration)
|
||||||
- The human's DMs stay clean — only direct alerts and responses
|
- The human's DMs stay clean — only direct alerts and responses
|
||||||
- In group channels, it's clear who said what
|
- In group channels, it's clear who said what
|
||||||
@ -243,16 +256,33 @@ human. This means:
|
|||||||
A practical setup:
|
A practical setup:
|
||||||
|
|
||||||
- **#git** — Real-time Gitea webhook feed (all repos) + agent's work status
|
- **#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
|
- **#claw** — Agent's internal work narration. Useful for debugging what the
|
||||||
agent is doing, but notifications muted so it doesn't disturb anyone.
|
agent is doing, but notifications muted so it doesn't disturb anyone.
|
||||||
- **DM with agent** — Private conversation, sitreps, sensitive commands
|
- **DM with agent** — Private conversation, sitreps, sensitive commands
|
||||||
- **Project-specific channels** — For coordination with external collaborators
|
- **Project-specific channels** — For coordination with external collaborators
|
||||||
|
|
||||||
The webhook feed in #git means nobody needs to check Gitea's notification inbox
|
### The Notification Poller
|
||||||
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
|
Because the agent can't see Gitea webhooks in Mattermost (bot-to-bot visibility
|
||||||
events in near-realtime.
|
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
|
## CI: Gitea Actions
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user