3.3 KiB
Plan: (no topic) Thread Routing
Date: 2026-05-14 Status: Planning Priority: Medium
Problem
When Alex sends a message in Zulip's (no topic) thread (the default unnamed thread), it usually means one of two things:
- He missed the correct topic — it should go to the most recent active thread in the same stream
- He's starting a genuinely new discussion
Eagle needs to automatically detect which case it is and act accordingly.
Design
Detection Logic
Step 1: Find most recent active thread in stream
- Query Zulip API for recent messages in the current stream (last N hours)
- Exclude
(no topic)thread itself - Get the thread with the most recent message →
candidate_thread
Step 2: Relevance check
- Take first ~200 chars of
(no topic)message - Take thread name + last 2-3 messages from
candidate_threadas context - Ask LLM (cheap/fast call): "Is this message topically related to this thread? yes/no + confidence"
Step 3: Action
If related (confidence > 0.7):
- Quote Alex's message in
candidate_threadwith attribution:[Cross-posted from (no topic) — @Alex] - Reply in
(no topic):Переношу в тред «{thread_name}» ↗ - Continue discussion in
candidate_thread - ⚠️ Coordination: check if another Eagle instance is active in
candidate_thread(see below)
If not related (new topic):
- Rename
(no topic)thread to a descriptive topic name (2-5 words, inferred from message) - Reply normally in the renamed thread
Multi-instance Coordination
Eagle may have multiple instances running in different Zulip topics simultaneously. To avoid conflicts when routing to an existing thread:
Option A: DB mutex (preferred)
zulip_thread_lockstable:(stream, topic, locked_by_session, locked_at)- Before posting in another thread → INSERT lock (fail on conflict)
- Release lock after posting
- Stale lock (>5 min) → auto-expire
Option B: Message-based handoff
- Before cross-posting → send a "silent" message to
candidate_thread(deletable):[Eagle routing incoming from (no topic)] - If another instance replies with
[ACK]→ let it handle - If no reply in 30s → proceed
Recommendation: Option A — simpler, no timing issues.
Multi-instance Awareness
Each Eagle instance should know its own Zulip topic context. When spawned in a topic, it registers itself in zulip_thread_locks. Eagle reads this to avoid double-posting.
Implementation Steps
- Add Zulip stream message history query to Eagle's toolkit (REST API call via hermes)
- Create
zulip_thread_lockstable inpersonal_osDB - Write topic routing logic as a function in the Eagle prompt or as a cron-triggered script
- Test: send message in
(no topic), verify routing + rename behavior
Questions
- Does Eagle get invoked automatically for every (no topic) message, or only when mentioned?
- Is Eagle a single process or multiple instances per stream? (affects coordination complexity)
- What's the stream scope? Only
master? Or all streams?
Notes
- Current session: this
(no topic)thread inmasterstream should be renamed to something likeplanning: system improvements 2026-05 - Zulip topic rename API:
PATCH /api/v1/messages/{message_id}withtopicparam (requires first message ID of the thread)