Skip to content

feat: board-level kanban notification subscriptions (ADR-0011) - #28748

Closed
KulltivateAI wants to merge 1 commit into
NousResearch:mainfrom
KulltivateAI:feature/board-level-notify-subs
Closed

feat: board-level kanban notification subscriptions (ADR-0011)#28748
KulltivateAI wants to merge 1 commit into
NousResearch:mainfrom
KulltivateAI:feature/board-level-notify-subs

Conversation

@KulltivateAI

Copy link
Copy Markdown

Summary

Implements board-level notification subscriptions per ADR-0011. Users can subscribe to ALL events on a kanban board (not just per-task), with optional kind filtering.

Changes (3 files, +223/-32)

hermes_cli/kanban_db.py — DB layer

  • Added BOARD_SUB_TASK_ID = '__board__' constant
  • Schema migration: kinds TEXT column on kanban_notify_subs (idempotent ALTER TABLE)
  • add_notify_sub(): accepts optional kinds parameter
  • list_notify_subs(): new board_only kwarg to filter board-level subs
  • New claim_unseen_board_events(): queries global task_events table with CAS cursor pattern, LIMIT 200

hermes_cli/kanban.py — CLI

  • notify-subscribe: --board flag (mutually exclusive with task_id), --kinds flag
  • notify-unsubscribe: --board flag support
  • notify-list: shows [BOARD] prefix for board-level subs, displays kinds filter

gateway/run.py — Watcher

  • Splits subs into regular vs board-level
  • Board subs processed after regular subs with dedup via delivered_event_keys set
  • Board subs skip auto-unsubscribe on terminal task states

Design Decisions

  • kinds stored as comma-separated TEXT (NULL = all terminal kinds) — backward compatible
  • Dedup tracks (event_id, platform, chat_id, thread_id) tuples
  • Board subs are permanent until explicit unsubscribe

Testing

  • 4515 tests pass (4 failures are pre-existing/flaky on main, unrelated to this change)

- Add BOARD_SUB_TASK_ID constant ('__board__') to kanban_db.py
- Schema migration: add 'kinds' column to kanban_notify_subs
- add_notify_sub(): accept optional 'kinds' parameter
- list_notify_subs(): add 'board_only' kwarg
- New claim_unseen_board_events(): queries global task_events table
  without task_id filter, LIMIT 200, CAS cursor pattern
- CLI: notify-subscribe/unsubscribe accept --board and --kinds flags
  (mutually exclusive with positional task_id)
- CLI: notify-list shows [BOARD] prefix and kinds filter
- Gateway watcher: split subs into regular vs board-level, process
  board subs after regular subs with per-sub kinds filter
- Dedup: track delivered_event_keys to prevent duplicate notifications
  when both per-task and board subs target the same destination
- Board-level subs never auto-unsubscribe on task completion

All 215 existing kanban tests pass.
@alt-glitch alt-glitch added type/feature New feature or request comp/plugins Plugin system and bundled plugins comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have labels May 19, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution. The feature gap is real on current main: notify-subscribe still requires a task id in hermes_cli/kanban.py:684, and the live watcher still claims per-task events at gateway/kanban_watchers.py:181.

Problems

  • The watcher code in this PR targets gateway/run.py, but current main moved this loop into gateway/kanban_watchers.py:29. A salvage needs to apply the board-subscription logic there, where list_notify_subs and claim_unseen_events_for_sub are called at gateway/kanban_watchers.py:163 and gateway/kanban_watchers.py:181.
  • Board notifications attach the real task at gateway/run.py:4679 in the PR, but the formatter still uses sub['task_id'] below; for a board subscription that would render the sentinel board instead of the event task id.
  • The PR adds no tests. Existing notification coverage is in tests/hermes_cli/test_kanban_notify.py, tests/hermes_cli/test_kanban_core_functionality.py, and tests/gateway/test_kanban_notifier.py, and this feature needs coverage for board subscribe/list/unsubscribe, kind filters, dedup with task-level subscriptions, and permanent board subscriptions.
  • Current main has kanban_notify_subs rebuild specs at hermes_cli/kanban_db.py:1855; the new kinds column needs to be included in those current-main schema paths too.

Suggested changes

  • Port the watcher changes to gateway/kanban_watchers.py.
  • Render board-level messages with ev.task_id/task.id instead of the board sentinel.
  • Add focused DB/CLI/watcher regression tests.

Automated hermes-sweeper review.

Comment thread gateway/run.py
"old_cursor": old_cursor,
"cursor": cursor,
"events": [ev],
"task": ev_task,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This supplies the real task object, but the message formatter below still interpolates sub['task_id']; for a board subscription that is the board sentinel, so the user-facing notification would not identify the actual task. Please render board events with ev.task_id or the loaded task id.

@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants