The briefing agent is the core AI agent for the Haiven platform. It generates structured, LLM-powered outputs across 9 scopes: daily briefings, document drafting, email composition, content publishing, and opportunity detection. All scopes go through a single POST /briefing endpoint.
briefing.haiven.sitehttp://localhost:8035| Scope | When to use |
|---|---|
daily |
Morning: prioritized view of open tasks and recent KB updates |
end_of_day |
End of day: completions count and carry-over open items |
review |
Revise a task artifact using voice or text instructions |
context_assembly |
Gather KB context for a task before starting work |
pre_meeting |
Upcoming meeting prep with KB context (also runs on 15-min schedule) |
document |
Draft a structured document from a task via Seed-36B |
email |
Compose an email draft with GLM tone classification + Seed-36B body |
opportunity |
Daily KB scan for blog ideas, patterns, and follow-ups |
content_pipeline |
Publish blog (WordPress) + social snippets (LinkedIn, X) + podcast |
Fetches open tasks (up to 20), recently completed tasks (up to 10), and recent KB entries (up to 10). Generates a prioritized summary via GLM-4.7-Flash.
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{"scope": "daily", "notify": false}' | jq .briefing
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{"scope": "daily", "notify": true}'
voice_instructions is injected as a system message before the template prompt:
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{"scope": "daily", "voice_instructions": "Focus on high-priority and overdue items only. Be brief."}'
After generating the briefing, makes a second LLM call to extract actionable items and creates them as tasks in work-hub. Deduplicates against existing open tasks by title.
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{"scope": "daily", "extract_tasks": true, "notify": false}' \
| jq '{briefing: .briefing, new_tasks: .created_task_ids}'
Counts completions, lists carry-over open tasks, produces a short wrap-up. No KB search.
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{"scope": "end_of_day", "notify": true}'
Before starting work on a task, run context assembly to populate its context field with everything the knowledge base knows about the topic. The task status is set to context_ready when done.
TASK_ID="<uuid-from-work-hub>"
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d "{\"scope\": \"context_assembly\", \"task_id\": \"${TASK_ID}\"}" \
| jq '{total_sources: .data_sources.total_sources, summary: .briefing}'
Four parallel KB queries run: meeting notes, research, references, and AI conversations — all scoped to the task title. Results are deduplicated by point_id.
Retrieve the assembled context afterwards:
curl -sf http://localhost:8030/api/v1/tasks/${TASK_ID} | jq .context
Reads the current artifact from the task, searches the KB using your instructions as the query, then rewrites the artifact accordingly. Saves the result back to the task.
TASK_ID="<uuid-from-work-hub>"
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d "{
\"scope\": \"review\",
\"task_id\": \"${TASK_ID}\",
\"voice_instructions\": \"Make it shorter, cut the jargon, and add a clear next action\"
}"
Both task_id and voice_instructions are required. The revised text appears in briefing and is saved to the task immediately.
Generates a structured document draft using a 7-step pipeline. KB context is assembled first, then Seed-36B writes the body.
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{
"scope": "document",
"task_id": "your-task-uuid-here"
}'
Use pipe-separated keys in voice_instructions:
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{
"scope": "document",
"task_id": "your-task-uuid-here",
"voice_instructions": "subject:Q1 Product Roadmap|client:Acme Corp"
}'
| Key | Effect |
|---|---|
subject:... |
Overrides the KB search topic and document subject |
client:... |
Filters KB context to client-relevant material; injected as system context |
Pass the Langfuse template name in the template field. Templates are managed at ai-ops.haiven.site. Falls back to the default if not found.
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{
"scope": "document",
"task_id": "your-task-uuid-here",
"template": "proposal-template"
}'
Two-model pipeline: GLM-4.7-Flash classifies the tone from context; Seed-36B writes the body.
Pass recipient and subject as pipe-separated keys in voice_instructions:
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{
"scope": "email",
"voice_instructions": "to:client@example.com|subject:Project Update — Week 12"
}'
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{
"scope": "email",
"task_id": "optional-related-task-uuid",
"voice_instructions": "to:team@company.com|subject:Q2 Planning Kickoff|style:casual|client:Internal"
}'
| Key | Required | Effect |
|---|---|---|
to:... |
Yes | Recipient email address |
subject:... |
Yes | Email subject line (also used as KB search query) |
style:... |
No | Override GLM's tone classification (e.g. formal, casual, concise) |
client:... |
No | Filter KB context to client-relevant material |
The composed draft is returned in briefing. If task_id is provided, it is saved as a task artifact in work-hub.
Scans the knowledge base for five types of signal. Results are cached in Redis after the daily scheduled run, so on-demand calls return the cache instantly if available.
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{"scope": "opportunity", "notify": false}'
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{"scope": "opportunity", "notify": true}'
The response data_sources.opportunities contains the full ranked list. Each opportunity has a type, title, rationale, and urgency_score.
Detection types:
| Type | What it finds |
|---|---|
blog_idea |
Insights and lessons worth publishing |
productization_pattern |
Reusable workflows that could become products |
client_follow_up |
Open items and promises from client conversations |
cross_pollination |
Ideas applicable across different domains |
competitive_intel |
Market trends and competitor signals |
Edit /mnt/apps/src/haiven-agent-briefing/config/opportunity.yml:
enabled: true
detection_types:
- blog_idea
- productization_pattern
- client_follow_up
- cross_pollination
- competitive_intel
output_channel: ntfy
max_opportunities: 10
urgency_threshold: 0.3
Opportunities below urgency_threshold are excluded. Changes take effect on the next container restart.
Takes a work-hub task and publishes it across multiple channels.
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{
"scope": "content_pipeline",
"task_id": "your-task-uuid-here",
"voice_instructions": "targets:blog"
}'
Posts are published to WordPress as drafts — not immediately live. Review at https://www.elijah.ai/wp-admin. If WordPress credentials are absent or unreachable, the Markdown draft is saved to /mnt/storage/drafts/ instead.
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{
"scope": "content_pipeline",
"task_id": "your-task-uuid-here",
"voice_instructions": "targets:blog,social_linkedin,social_x|tone:professional|audience:technical"
}'
| Target | Output location |
|---|---|
blog |
WordPress draft + /mnt/storage/drafts/ fallback |
social_linkedin |
/mnt/storage/social/{date}-{slug}-snippets.txt |
social_x |
Same file as LinkedIn, max 280 chars |
podcast |
/mnt/storage/podcast/episodes/ + RSS feed update |
| Key | Default | Effect |
|---|---|---|
targets:... |
blog |
Comma-separated list of publish targets |
tone:... |
professional |
Writing tone (e.g. casual, technical) |
audience:... |
general |
Target audience (e.g. developers, executives) |
client:... |
— | Filter KB context to client-relevant material |
# List recent post folders
ls -lt /mnt/storage/content-output/
# Inspect a post folder
ls /mnt/storage/content-output/2026-03-01-my-post-title/
# blog.md social-linkedin.txt social-x.txt featured-image.png social-image.png manifest.json
cat /mnt/storage/content-output/2026-03-01-my-post-title/manifest.json
# Read social snippets
cat /mnt/storage/social/2026-03-01-my-post-title-snippets.txt
Pre-meeting briefings run automatically every 15 minutes via APScheduler. They query the KB for upcoming calendar events (filtered to doc_type=calendar-event) and generate prep notes per meeting.
curl -sf -X POST http://localhost:8035/briefing \
-H "Content-Type: application/json" \
-d '{"scope": "pre_meeting"}'
Events already briefed within the past 2 hours are skipped (idempotency via event UID, backed by Redis).
To disable the scheduler without affecting manual calls, set BRIEFING_PRE_MEETING_ENABLED=false.
The agent fires automatically on weekdays via systemd timers. Both send notifications via notification-hub.
| Timer | Time | Scope |
|---|---|---|
haiven-briefing-morning.timer |
Mon–Fri 07:30 | daily |
haiven-briefing-eod.timer |
Mon–Fri 17:30 | end_of_day |
Both include a 2-minute randomized delay.
# Check timer status
systemctl list-timers haiven-briefing*
# View recent logs
journalctl -u haiven-briefing-morning.service -n 30
journalctl -u haiven-briefing-eod.service -n 30
# Trigger manually (as if the timer fired)
sudo systemctl start haiven-briefing-morning.service
sudo systemctl start haiven-briefing-eod.service
If you are calling the briefing agent from another service, use /v1/agent instead of /briefing. It accepts intent strings rather than scope names.
curl -sf -X POST http://localhost:8035/v1/agent \
-H "Content-Type: application/json" \
-d '{
"user_message": "Draft a document for my current task",
"intent": "draft",
"task_id": "your-task-uuid-here",
"entities": {"instruction": "client:Acme Corp"}
}'
| Intent | Scope |
|---|---|
briefing.daily |
daily |
briefing.weekly |
end_of_day |
scheduling.query |
pre_meeting |
research.topic |
context_assembly |
review_feedback |
review |
draft |
document |
opportunity.scan |
opportunity |
email.compose |
email |
content.publish |
content_pipeline |
Prompt templates for daily and end_of_day are managed in Langfuse:
ai-ops.haiven.site (Langfuse)briefing-daily (variables: {{open_tasks}}, {{completed_tasks}}, {{recent_kb}})briefing-eod (variable: {{task_counts}})If Langfuse is unavailable, the service falls back to hardcoded templates in app/templates.py and continues functioning.
GLM-4.7-Flash has thinking mode ON by default — the service extracts the answer from reasoning_content automatically. If responses are empty, check LiteLLM is reachable:
curl -sf http://localhost:4000/health | jq .
curl -sf http://localhost:4000/v1/models | jq '.data[].id'
The task_id was not found in work-hub. Verify the task exists:
curl -sf http://localhost:8030/api/v1/tasks/<task_id>
The KB may not have content on this topic yet. Test directly:
curl -sf -X POST http://localhost:8022/v1/search \
-H "Content-Type: application/json" \
-d '{"query": "<task title>", "limit": 5}'
Check data_sources.blog.wp_status in the response:
- draft / pending — published successfully
- wp_unreachable_draft_saved — WP failed, Markdown saved to /mnt/storage/drafts/
- draft_saved_local — WP credentials not configured
Fix: verify BRIEFING_WP_API_USER and BRIEFING_WP_API_TOKEN in the service .env.
Lower urgency_threshold in config/opportunity.yml to 0.1 as a test. Also check Redis is reachable:
docker exec -it redis redis-cli ping
The scope requires calendar events to be ingested into haiven-knowledge with doc_type=calendar-event. Verify the calendar ingestion pipeline is running.
systemctl list-timers haiven-briefing*
systemctl cat haiven-briefing-morning.service
# Reload if config changed
sudo systemctl daemon-reload
sudo systemctl enable --now haiven-briefing-morning.timer haiven-briefing-eod.timer
# Check notification-hub health
curl -sf http://localhost:8040/health
# Test a manual notification
curl -sf -X POST http://localhost:8040/notify \
-H "Content-Type: application/json" \
-d '{"source_agent": "haiven-agent-briefing", "title": "Test", "body": "ping"}'
# Check logs
docker logs -f notification-hub
docker logs agent-briefing --tail 50
Common causes: Redis unreachable at startup (APScheduler fails to initialize), or missing required env vars (BRIEFING_LITELLM_URL, BRIEFING_WORKHUB_URL).
All LLM calls are traced. Open http://ai-ops.haiven.site to browse traces filtered by agent_type. Span names include: generate_body, wp_publish, social_generate, podcast_tts, podcast_ffmpeg, context_assembly.
| Service | Domain | Purpose |
|---|---|---|
| work-hub | work.haiven.site |
Task source and artifact store |
| haiven-knowledge | knowledge.haiven.site |
Semantic KB used for context queries |
| notification-hub | hub.haiven.site |
Delivers briefings via ntfy/TTS |
| LiteLLM | llm.haiven.site |
LLM gateway (GLM + Seed-36B) |
| Langfuse | ai-ops.haiven.site |
Prompt management and LLM tracing |
| WordPress | www.elijah.ai |
Blog publishing target |
| chatterbox-tts | Internal | Podcast audio generation |