Thread Architecture — Hub, Kanban & Notification Spec
Thread Architecture — Hub, Kanban & Notification Spec
Motivation
Reduce unsolicited notifications. Push only what's actionable. File everything else silently to the hub. Make the whole system inspectable by a human — file-based, no hidden database.
Current State (before this spec)
Kanban Structure
Flat directories under ~/.hermes/emailkb/kanban/:
kanban/
├── finance/
├── services/
├── shopping/
├── trading/
├── utilities/
└── real-estate/
All tasks mixed by category, no thread attribution, no steering metadata.
Cron Jobs
15 cron jobs, many delivering origin (push notification). No consistent output model. Some are agent-driven, some are scripts.
Hub
Static build from /root/ai-system/kb/. Content goes to KB but no structured connection between threads, tasks, and notifications.
Target State
Thread Model
A Thread is a named processing pipeline with: 1. A source (IMAP inbox, API endpoint, script output) 2. An intelligence pass (agent reads source, classifies, decides) 3. A kanban folder for tasks it creates 4. A KB folder for reference output it writes 5. A steering file that governs its behavior 6. A notification rule — when should it message the user
Kanban Structure (per Thread)
~/.hermes/emailkb/kanban/
├── inbox-review/
│ ├── steering.yaml ← governs this thread
│ ├── 2026-10-01-massive-renewal.md
│ └── 2026-10-02-bluebonnet-bill.md
├── tli/
│ ├── steering.yaml
│ ├── 2026-10-02-OSCROverweight.md
│ └── 2026-10-01-UNHTargetHike.md
├── schwab/
│ ├── steering.yaml
│ └── 2026-10-02-trade-fill-rstb.md
├── schwab-randy/
│ ├── steering.yaml
│ └── 2026-10-02-dividend.md
├── robinhood/
│ ├── steering.yaml
│ └── 2026-10-01-margin-alert.md
├── options-lab/
│ ├── steering.yaml
│ └── 2026-10-02-astscall-expiry.md
└── move-to-nv/
├── steering.yaml
└── 2026-09-28-public-storage.md
Each thread folder lives under kanban/<thread-name>/. Tasks are markdown files with YAML frontmatter and a markdown body. The steering.yaml defines rules for that thread.
Steering File Format
# steering.yaml for a thread
thread: inbox-review
source: imap (himalaya)
cadence: "0 8,13,17 * * 1-5" # cron expression or "on-demand"
# How the agent handles items from this thread
intelligence:
classify: true
categories: [actionable, reference, noise]
skip_subjects:
- "Your trade confirmation"
- "Your monthly statement"
- "Your Daily Digest"
- "Your listening picks"
skip_senders:
- "The Long Investor" # handled by tli thread
- "Robinhood" # handled by robinhood thread
# Kanban rules
kanban:
create_on: [actionable]
deadline_field: extract_from_body
auto_close_on: [] # future: match on email reply
# Notification rules
notify:
priority_🔴: # immediate push
- sender_contains: ["Mason", "Independence Title", "Alamo Title"]
- deadline_within: 3d
priority_🟡: # daily digest only
- deadline_within: 7d
- category: actionable
priority_🟢: # never push
- any: true
# Hub output
hub:
kb_path: kb/email/<yyyy-mm>/<date>-triage.md
rebuild_after_write: false # rebuild triggered manually
Notification Model
| Priority | Means | Delivery | Examples |
|---|---|---|---|
| 🔴 Urgent | Must act within days | Immediate push message | Deadline in 3d, financial at-risk, sender is real person with ask |
| 🟡 Digest | Should know about | Batched once per daily pass | Optional action item, renewal coming in 2 weeks, low-$ item |
| 🟢 Filed | Reference only | No message. Hub only. | Completed task, routine confirmation, newsletter, statement |
Hub Output
Each thread writes its reference output to the KB:
kb/
├── email/2036-10/
│ └── 02-triage.md ← Inbox Review daily file
├── tli/2036-10-02/
│ ├── signals.md
│ └── portfolio-crossref.md
├── trading/
│ ├── schwab-activity.md
│ ├── robinhood-snapshot.md
│ └── positions.md
└── options-lab/2036-10-02/
└── expiry-scan.md
The hub build (cd /root/hub && python3 build.py) picks up all KB changes and cross-links them. Build is triggered on demand (manual or via cron), not on every file write.
Migration Plan
| Step | What | Risk |
|---|---|---|
1. Write this spec to kb/system/thread-spec.md |
Done | None |
2. Create steering.yaml templates for each thread |
Low | Minor — can be edited later |
| 3. Restructure kanban: flat → per-thread folders, move existing tasks | Medium | Tasks rehomed, no content loss |
4. Pause/rewrite cron jobs that deliver origin → switch to local + silent processing |
Medium | May miss a notification during switchover |
| 5. Wire inbox-review thread as first live thread | Medium | Pattern for all others |
| 6. Wire remaining threads (TLI, Schwab, Schwab-Randy, Robinhood, Options Lab) | Low | Same pattern |
Implemented one thread at a time. Each follows the same steering → kanban → hub → notify path.
What Changed (Oct 2, 2026)
Kanban Restructured
Old: flat directories by category. New: per-thread folders. Empty legacy dirs removed.
kanban/
├── inbox-review/ (19 tasks — all email-triaged items)
│ └── steering.yaml
├── tli/ (1 task — ASTS buy alert)
│ └── steering.yaml
├── robinhood/ (empty)
│ └── steering.yaml
├── schwab/
│ └── steering.yaml
├── schwab-randy/
│ └── steering.yaml
├── options-lab/
│ └── steering.yaml
└── move-to-nv/ (1 task — address updates)
└── steering.yaml
Cron Jobs Rerouted
All deliver: origin → deliver: local. Agent handles notification routing via steering files.
| Job | Delivery Change | Rationale |
|---|---|---|
| Morning Brief | origin → local | On-demand, hub only |
| Dividend Calendar Refresh | origin → local | On-demand, hub only |
| TLI Hub Morning Update | origin → local | tli thread handles notifications |
| TLI Hub Afternoon Update | origin → local | Same |
| tli-position-crossref | origin → local | Same |
| robinhood-daily-snapshot | origin → local | robinhood thread handles notifications |
| robinhood-alert-watch | origin → local | Same |
| stillwater-calendar-reminder | unchanged | — |
Steering Files Created
One per thread at kanban/<thread>/steering.yaml. Agent reads rules at runtime to classify, decide urgency, file to hub, and gate notifications.