6.4 KiB
6.4 KiB
PRD: MACP Phase 2A Event Bridge + Notification System
Metadata
- Owner: Jarvis
- Date: 2026-03-27
- Status: in-progress
- Best-Guess Mode: true
Problem Statement
MACP Phase 1 writes structured lifecycle events to .mosaic/orchestrator/events.ndjson, but no repo-local bridge consumes those events for external systems. Phase 2A adds a portable watcher, webhook delivery, and Discord-friendly formatting so MACP event streams can drive OpenClaw integrations and human-facing notifications.
Objectives
- Add a synchronous event watcher that tails
events.ndjsonusing stdlib-only file polling and persists cursor state across restarts. - Add a webhook adapter that can forward selected MACP events to a configured HTTP endpoint with bounded retries.
- Add a Discord formatter that turns task lifecycle events into concise human-readable strings.
- Extend the
mosaic macpCLI with awatchcommand for one-shot or continuous event bridge execution.
Scope
In Scope
- New
tools/orchestrator-matrix/events/package with watcher, webhook adapter, and Discord formatter modules. - Cursor persistence at
.mosaic/orchestrator/event_cursor.json. mosaic macp watch [--webhook] [--once]CLI support using.mosaic/orchestrator/config.json.- Stdlib-only verification of watcher polling, webhook delivery, Discord formatting, CLI watch behavior, and cursor persistence.
- Developer documentation and sitemap updates covering the Phase 2A event bridge.
Out of Scope
- Adding Discord transport or webhook server hosting inside this repository.
- Replacing the existing Matrix transport bridge.
- Introducing async, threads, or third-party Python packages.
- Changing event emission behavior in the controller beyond consuming the existing event stream.
User/Stakeholder Requirements
- External systems must be able to consume MACP events without reading the NDJSON file directly.
- The watcher must remain portable across environments, so file polling is required instead of platform-specific file watching.
- Restarting the watcher must not replay previously consumed events.
- Webhook delivery failures must be logged and isolated so the watcher loop continues running.
- Discord formatting must stay concise and useful for task lifecycle visibility.
Functional Requirements
EventWatchermust watch.mosaic/orchestrator/events.ndjson, parse appended JSON lines, and invoke registered callbacks for matching event types.EventWatcher.poll_once()must tolerate a missing events file, truncated/corrupt lines, and cursor positions that are stale after file truncation.- Cursor writes must be atomic and stored at
.mosaic/orchestrator/event_cursor.json. send_webhook(event, config)must POST JSON to the configured URL usingurllib.request, optionally adding a bearer token, respecting timeout, and retrying with exponential backoff.create_webhook_callback(config)must return a callback that swallows/logs failures instead of raising into the watcher loop.format_event(event)must supporttask.completed,task.failed,task.escalated,task.gated, andtask.started, including useful task metadata when present.format_summary(events)must produce a short batch summary suitable for notification digests.bin/mosaic-macpmust exposewatch, optionally enabling webhook delivery from config, and support one-shot polling with--once.
Non-Functional Requirements
- Security: no secrets embedded in code or logs; auth token only sent via header when configured.
- Performance: each webhook attempt must be bounded by
timeout_seconds; no event-processing path may hang indefinitely. - Reliability: corrupt input lines and callback delivery failures must be logged to stderr and skipped without crashing the watcher.
- Portability: Python 3.10+ stdlib only; no OS-specific file watcher APIs.
- Observability: warnings and failures must be clear enough to diagnose cursor, parsing, and webhook problems.
Acceptance Criteria
EventWatcher.poll_once()reads newly appended events, returns parsed dicts, invokes registered callbacks, and skips already-consumed events after restart.- Webhook delivery posts matching events to a local test endpoint, supports bearer auth configuration, and retries boundedly on failure.
- Discord formatter returns expected concise strings for the required task lifecycle event types and a usable batch summary.
mosaic macp watch --onceprocesses events from a bootstrapped repo state without error and honors--webhook.- Cursor persistence prevents replay on a second run and resets safely when the events file is truncated.
Constraints and Dependencies
- Python implementation must use stdlib only and support Python 3.10+.
- Shell CLI behavior must remain bash-based and consistent with the existing Mosaic command style.
- The watcher consumes the event schema already emitted by Phase 1 controller logic.
- Webhook configuration lives under
.mosaic/orchestrator/config.jsonatmacp.webhook.
Risks and Open Questions
- Risk: partial writes may leave an incomplete trailing JSON line that must not advance the cursor incorrectly.
- Risk: synchronous webhook retries can slow one poll cycle if the endpoint is unavailable; timeout and retry behavior must remain bounded.
- Risk: event payloads may omit optional metadata fields, so formatter output must degrade cleanly.
- ASSUMPTION: the watcher should advance past corrupt lines after logging them so a single bad line does not permanently stall downstream consumption.
- ASSUMPTION: CLI
watchshould default to no-op callback processing when no delivery option is enabled, while still updating the cursor and reporting processed count.
Testing and Verification Expectations
- Baseline checks: Python bytecode compilation/import validation for new modules and shell syntax validation for
bin/mosaic-macp. - Situational tests: temporary orchestrator state exercising watcher polling, callback filtering, webhook POST capture, CLI one-shot watch execution, and cursor persistence across repeated runs.
- Evidence format: command-level results recorded in the scratchpad and summarized against acceptance criteria.
Milestone / Delivery Intent
- Target milestone/version: Phase 2A observability bridge
- Definition of done: code merged to
main, CI terminal green, issue#10closed, and verification evidence recorded against all acceptance criteria.