NexBoard Build Journal — Mon 16 Jun – Sun 22 Jun 2026

What shipped

  • Notes watcher: two separate bugs closed. Action: and Todo: prefixes were optional in the pattern — the verb still had to appear in the allowlist. So Action: add revenue breakdown was silently dropped. Fixed by splitting into two patterns: one that matches any verb+object when an explicit prefix is present, another for bare unprefixed imperatives. Second bug: Obsidian inline formatting (<u>Action:</u>, **bold**, ==highlight==) was wrapping keywords before the regex saw them. Added a _clean_text() strip pass at all three inference entry points.
  • @agent prefix in Telegram. Messages starting with @di, @saeed, @craig, @doug, @social, or @deepwork now skip the CoS mode deliberation entirely and write a routing slip directly for that agent. Still lands in Pending, but the routing hop is gone.
  • Meeting countdown and re-entry watcher: Claude removed. Both were calling the LLM to check calendar state from background jobs. Those calls were leaking test messages to Telegram. Replaced with Python readers that parse a daily calendar snapshot. Faster, deterministic, no LLM in the hot path.
  • Di agent routing fixed. INSTRUCTION-FIRST rule added — explicit task instructions now execute directly rather than routing to calendar. Vault write paths corrected; all openclaw references removed.
  • Mobile today panel. Six APIs fetched in parallel on load. Finance Pulse now available on mobile with PIN tap-to-reveal, sharing session state with the desktop widget via localStorage (8-hour window).
  • Subtask date field corrected. The subtask date input was wired to scheduled; overdue detection uses due. No-date subtasks were appearing overdue, or displaying the wrong date entirely.

The interesting problem

The notes watcher had a class of silent failure: it was dropping explicitly labelled action lines.

The original pattern looked like:

r"^(?:Action:\s+|Todo:\s+|...)?"
r"(?:Call|Email|Send|...)\s+\w+"

The prefix group was optional (?). This meant the prefix only helped if the following verb was already in the allowlist. A line like Action: add revenue breakdown would consume Action:, skip the verb check — then fail the verb match because add wasn’t listed. The prefix was decorative noise, not a signal.

The fix splits the pattern in two. An explicit prefix now functions as a hard signal: any Action: verb object form matches regardless of what the verb is. Unprefixed lines still require the verb allowlist. The prefix is now load-bearing.

Decision of the week

Pulled Claude out of the meeting countdown and re-entry watcher pipelines. Both had accumulated LLM calls that were originally added for flexibility — checking whether a calendar event was significant enough to suppress a re-entry alert, enriching the countdown message. But the same calls were generating test Telegram messages mid-run, and the enrichment wasn’t being applied consistently.

The replacement is simpler: a Python function reads today’s calendar snapshot, checks the event time window, returns a boolean. No inference, no message side-effects. I traded flexibility for predictability, and nothing has needed the flexibility since.

What surprised me

Finding that Action: prefixes were decorative was annoying in retrospect. The intent when the pattern was written was clearly to make them a strong signal — the optional ? undid that entirely. A labelled action line and an unlabelled bare imperative were handled identically. The structure of the regex expressed the opposite of what it was supposed to mean, and it only became visible when a concrete line failed to match.

What’s next

Finance Pulse portfolio section needs a toggle (currently planned but not built). The CoS open-loops doc has a few pending commitment and relationship tracking items that need a watcher pass. The README rewrite from this week is current; no further doc work planned.


Building NexBoard — a self-hosted AI Chief of Staff, built entirely with Claude Code.