briefing
Installation
SKILL.md
Briefing Pipeline
Multi-domain daily briefing system: collect → generate → review → email → keyword evolution.
Tool
python3 scripts/briefing_run.py <command> [options]
Commands
# Run full pipeline for a domain
python3 scripts/briefing_run.py run --domain ai-drama [--date 2026-03-03]
# Run keyword evolution only
python3 scripts/briefing_run.py evolve --domain ai-drama [--date 2026-03-03]
# Check last run status
python3 scripts/briefing_run.py status --domain ai-drama
# List all configured domains
python3 scripts/briefing_run.py domains
# Run collection step only
python3 scripts/briefing_run.py run --domain ai-drama --step collect
All commands accept --config config.yaml (defaults to hub config).
File Structure
~/briefing/
config/
email.json # Global fallback email config (only user's own email)
engine/
collector.py # Domain-aware RSS/API collector
notify.py # Domain-aware email sender
prompt_init.py # Prompt initialization and evolution
templates/
generate_base.md # Base template for generation prompts
review_base.md # Base template for review prompts
domains/<name>/
domain.yaml # Core config: models, distribution, keyword_evolution, schedule
sources.yaml # Keywords (by supply-chain layer) + source definitions (RSS, API)
config/
email.json # Domain-specific email config (overrides global)
prompts/
generate.md # Gemini generation prompt
review.md # Claude review prompt
data/
today_context.json # Latest collector output
keyword_feedback.json # Per-keyword hit stats (30-day rolling)
keywords_dynamic.yaml # Auto-evolved keywords (candidate/active/deprecated)
keywords_meta.json # Evolution history + idempotency
run_status.json # Latest pipeline run status
output/ # Final briefing markdown files
Email Config
Email recipients are in email.json. Lookup order: domain-specific (domains/<name>/config/email.json) → global fallback (~/briefing/config/email.json).
{
"sender": "user@example.com",
"app_password": "smtp_app_password",
"recipients": ["a@example.com", "b@example.com"],
"cc": ["c@example.com"],
"smtp_host": "smtp.qq.com",
"smtp_port": 465
}
To change recipients for a specific domain, edit its domains/<name>/config/email.json. The global file only applies to domains without their own config.
Adding a New Domain
- Create
~/briefing/domains/<new-name>/ - Add
domain.yaml(copy from existing domain, customize) - Add
sources.yamlwith keywords and sources - Add
prompts/generate.mdandprompts/review.md - Register a cron job: use hub-ops skill to add
briefing:<new-name>handler
Key Config in domain.yaml
models:
generate: { model: "3-Flash", thinking: medium, fallback_model: sonnet }
review: { enabled: true, model: sonnet }
distribution:
email: { enabled: true, subject_template: "{name} | {date}" }
feishu: { enabled: true, chat_id: "oc_xxx" }
keyword_evolution:
enabled: true
max_auto_additions_per_cycle: 5
schedule: "0 8 * * *"
What Doesn't Need Restart
| Change | Needs restart? |
|---|---|
Pipeline logic (scripts/briefing_run.py) |
No — runs as subprocess |
| Keyword evolution logic | No — same file |
domain.yaml / sources.yaml / prompts |
No — read fresh each run |
keywords_dynamic.yaml |
No — read fresh by collector |
| This SKILL.md | No |
briefing_plugin.py (shim) |
Yes — but it never changes |
config.yaml (credentials) |
Yes — tell user to send #restart in Feishu |
Registered Handlers
Handlers are auto-discovered from ~/briefing/domains/. Example:
| Handler | Domain | Cron | Description |
|---|---|---|---|
briefing |
(default domain) | 0 8 * * * |
Daily briefing for the default domain |
briefing:<name> |
<name> |
user-defined | Per-domain briefing |
briefing handler (no suffix) = default domain (set via briefing.default_domain in config.yaml). New domains register as briefing:<name>.
Handler jobs don't need a prompt — they spawn briefing_run.py as subprocess.
Weekly Installs
1
Repository
midnightv1/clau…e-feishuGitHub Stars
20
First Seen
2 days ago
Security Audits
Installed on
amp1
cline1
openclaw1
opencode1
cursor1
kimi-cli1