Herald Service: Add Matrix output adapter for status broadcasts #382

Closed
opened 2026-02-15 07:01:23 +00:00 by jason.woltje · 1 comment
Owner

Summary

Extend the Herald service to broadcast job status updates to Matrix rooms in addition to (or instead of) Discord threads.

Context

Herald currently formats status updates and sends them via the Discord bridge. It needs to become bridge-agnostic — broadcasting to all active chat providers.

Implementation

Herald receives an injected list of active IChatProvider instances and broadcasts to all of them:

class HeraldService {
  constructor(
    @Inject('CHAT_PROVIDERS') private providers: IChatProvider[]
  ) {}

  async broadcast(jobId: string, update: StatusUpdate) {
    for (const provider of this.providers) {
      if (provider.isConnected()) {
        await provider.sendThreadMessage({ threadId, content: formatted });
      }
    }
  }
}

Option B: Direct injection

Herald gets both DiscordService and MatrixService injected (simpler but less extensible).

Verbosity Levels

Same noise management as Discord:

  • Low (main room): Milestones only (job started, job completed/failed)
  • Medium (thread): Step completions, gate results
  • High (on request): Full step logs

Matrix-Specific Formatting

  • Use Matrix's m.notice message type for bot updates (not m.text) to avoid notification noise
  • Support formatted body (HTML) for rich status messages
  • Use reactions ( ) on the original command message for quick status

Acceptance Criteria

  • Herald broadcasts to all active chat providers
  • Matrix rooms receive job status updates
  • Verbosity levels respected
  • Matrix-specific formatting (m.notice, HTML body)
  • No crash if Matrix is not configured
  • Tests verify broadcast to multiple providers

Refs

## Summary Extend the Herald service to broadcast job status updates to Matrix rooms in addition to (or instead of) Discord threads. ## Context Herald currently formats status updates and sends them via the Discord bridge. It needs to become bridge-agnostic — broadcasting to all active chat providers. ## Implementation ### Option A: Bridge Registry (recommended) Herald receives an injected list of active `IChatProvider` instances and broadcasts to all of them: ```typescript class HeraldService { constructor( @Inject('CHAT_PROVIDERS') private providers: IChatProvider[] ) {} async broadcast(jobId: string, update: StatusUpdate) { for (const provider of this.providers) { if (provider.isConnected()) { await provider.sendThreadMessage({ threadId, content: formatted }); } } } } ``` ### Option B: Direct injection Herald gets both `DiscordService` and `MatrixService` injected (simpler but less extensible). ### Verbosity Levels Same noise management as Discord: - **Low** (main room): Milestones only (job started, job completed/failed) - **Medium** (thread): Step completions, gate results - **High** (on request): Full step logs ### Matrix-Specific Formatting - Use Matrix's `m.notice` message type for bot updates (not `m.text`) to avoid notification noise - Support formatted body (HTML) for rich status messages - Use reactions (✅ ❌ ⏳) on the original command message for quick status ## Acceptance Criteria - [ ] Herald broadcasts to all active chat providers - [ ] Matrix rooms receive job status updates - [ ] Verbosity levels respected - [ ] Matrix-specific formatting (m.notice, HTML body) - [ ] No crash if Matrix is not configured - [ ] Tests verify broadcast to multiple providers ## Refs - Herald service location (find via grep for HeraldService) - Discord noise management: `apps/api/src/bridge/discord/discord.service.ts` - EPIC: #377 - Depends on: #378, #380
jason.woltje added the apiapi labels 2026-02-15 07:01:23 +00:00
jason.woltje added this to the M12-MatrixBridge (0.0.12) milestone 2026-02-15 07:01:51 +00:00
Author
Owner

Completed in commit ad24720 on branch feature/m12-matrix-bridge.

  • Herald Service refactored from Discord-specific to bridge-agnostic CHAT_PROVIDERS array
  • Broadcasts to ALL active chat providers (Discord, Matrix, future)
  • Graceful error handling: one provider failure does not block others
  • Skips disconnected providers automatically
  • Tests verify multi-provider broadcasting behavior
Completed in commit ad24720 on branch feature/m12-matrix-bridge. - Herald Service refactored from Discord-specific to bridge-agnostic CHAT_PROVIDERS array - Broadcasts to ALL active chat providers (Discord, Matrix, future) - Graceful error handling: one provider failure does not block others - Skips disconnected providers automatically - Tests verify multi-provider broadcasting behavior
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaic/stack#382