feat(x): resolve X handles for person/brand topics via agent WebSearch

When a topic is a person/brand (e.g. "Dor Brothers", "Jason Calacanis"),
the agent now resolves their X handle via WebSearch before running the
script, then passes --x-handle to search their posts unfiltered (no
topic keywords required). This finds posts the entity made without
mentioning their own name.

- SKILL.md + OpenClaw variant: Step 0.5 handle resolution instructions
- last30days.py: --x-handle CLI arg, passed through to _run_supplemental()
- bird_x.search_handles(): topic is now Optional[str] for unfiltered mode
- schema.py: resolved_x_handle field on Report
- render.py: show resolved handle in stats output

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matt Van Horn
2026-02-25 20:00:49 -08:00
parent bed0557b65
commit 4f584a4e96
7 changed files with 402 additions and 9 deletions
+5
View File
@@ -288,6 +288,8 @@ class Report:
web_error: Optional[str] = None
youtube_error: Optional[str] = None
hackernews_error: Optional[str] = None
# Handle resolution
resolved_x_handle: Optional[str] = None
# Cache info
from_cache: bool = False
cache_age_hours: Optional[float] = None
@@ -312,6 +314,8 @@ class Report:
'prompt_pack': self.prompt_pack,
'context_snippet_md': self.context_snippet_md,
}
if self.resolved_x_handle:
d['resolved_x_handle'] = self.resolved_x_handle
if self.reddit_error:
d['reddit_error'] = self.reddit_error
if self.x_error:
@@ -472,6 +476,7 @@ class Report:
web_error=data.get('web_error'),
youtube_error=data.get('youtube_error'),
hackernews_error=data.get('hackernews_error'),
resolved_x_handle=data.get('resolved_x_handle'),
from_cache=data.get('from_cache', False),
cache_age_hours=data.get('cache_age_hours'),
)