Specialized autonomous agents running in the background across morning briefings, meeting prep, reply generation, and more.
- Agents: 8 specialized
- Cost Savings: 5× vs boss agent
- Safety Model: Read-only by default
01 — Why Dedicated Agents
The boss agent (Opus 4.6) can do anything. Give it a workflow and it will execute. But "can do anything" is the wrong architecture for recurring, high-frequency background tasks. It's expensive, slow, and carries the full tool surface. A morning briefing doesn't need Slack posting tools. A meeting prep doesn't need email sending. Loading unnecessary capabilities wastes context, increases cost, and creates risk.
01 — Specialized Storage Schemas
Each agent writes results through a terminal tool (DUMP_REPLY, DUMP_MEETING_PREP) into purpose-built database schemas. The reply generator stores suggested_reply, thread_summary, provider_draft_id, attachment metadata, and recipient lists. These schemas enable rich UIs that would be impossible with unstructured agent output.
02 — Read-Only Tool Sets
Background agents use build_tools_for_readonly_subagent() — a tool builder that only loads read-only MCP tools. No GMAIL_SEND_EMAIL, no SLACK_POST_MESSAGE. This is a hard architectural boundary, not a prompt instruction. The tools simply aren't available.
03 — Focused Prompts, Cheaper Models
The boss agent uses Opus 4.6 ($15/M input). Background agents use Sonnet 4.6 ($3/M input) — 5× cheaper — with tightly scoped system prompts. A 500-line general-purpose prompt dilutes attention. A 100-line task-specific prompt concentrates it.
A hallucinated "send this email" tool call fails with "tool not found" instead of sending an email. Safety through architecture, not instructions.
02 — The Background Agent Roster
Eight specialized agents run autonomously. Every agent follows the same pattern: NATS consumer receives event → agent graph runs → terminal tool writes structured output to DB → UI updates via Ably push.
| Agent | Trigger | What It Does | Model |
|---|---|---|---|
| Morning Briefing | Daily cron (pre-dawn) | Day summary: calendar, emails, tasks. Parallel subgraphs for body + replies | Sonnet 4.6 |
| Evening Briefing | Daily cron (end of day) | Recaps completed items, pending threads, tomorrow's agenda | Sonnet 4.6 |
| Reply Generator | Webhook (new email / Slack DM) | Drafts reply with tone matching. Creates Gmail draft. Opus refinement pass | S 4.6 + O 4.6 |
| Meeting Prep | Cal sync + daily refresh + pre-meeting cron | Prep notes: attendee context, relevant docs, talking points | Sonnet 4.6 |
| Action Items | Webhooks (Gmail, Linear, GitHub, Cal) | Surfaces PR reviews, assigned issues, emails needing reply | Sonnet 4.6 |
| Onboarding | User signup | Researches user on the web, generates profile, seeds memory graph | Sonnet 4.6 |
| Skills | User approves learned pattern | Indexes skill execution summary, stores reusable workflow pattern | Sonnet 4.6 |
| Begging Agent | Near credit limit | Nudges user about usage, suggests upgrade path. Quality matters — converts free users to paid | Opus 4.6 |
Shared Execution Pattern
NATS Event → Consumer → Agent Graph → DUMP_* Tool → DB + Ably Push
Note: From this point on, this document uses the Meeting Prep agent as a running example to illustrate how a background agent works end-to-end. The patterns shown — event-driven triggers, agent graph execution, structured output via DUMP tools — are the same across all eight agents.
03 — Meeting Prep — The Full Pipeline
One of our most loved background agents. Three consumers, a dedicated LangGraph agent, and multiple trigger paths.
Pipeline Stages
Stage 1 — SyncCalendarConsumer (webhooks app)
Fetch events via sync_token → normalize → match workflows → publish calendar events
Stage 2 — CalendarUpdateSuggestions (rag app)
Filter to next 2 days → separate cancelled/active → skip declined → route to prep or action item
Stage 3 — MeetingPrepConsumer (agent app)
Upsert skeleton → defer if not today → content diff → time shift detection (>20 min = regen) → skip RSVP-only → run agent → publish action item → send email
Stage 4 — meeting_prep_graph (LangGraph ReAct)
START → agent ⇄ tools → END
Tools: MEMORY_SEARCH, HYBRID_SEARCH, ADD_INTEGRATIONS, WEB_SEARCH, PEOPLE_SEARCH, Read-only MCP, DUMP_MEETING_PREP
Four Trigger Paths
- Calendar Sync — User connects Calendar. Skeleton upserted, deferred if not today.
- Webhook Update — Event changes (reschedule, new attendee). Content diff → regen only if material.
- Morning Refresh — Daily pre-dawn. Refreshes stale preps generated before today.
- Pre-Meeting Cron — ~20 min before meeting. Always regenerates. Sends email with prep notes.
The consumer decides whether to run the agent at all. RSVP changes, minor time shifts, and non-today events are handled without invoking the LLM.
04 — The Meeting Prep Agent
Classification Gate
- Work meeting → proceed — Colleague sync, client call, sprint planning, 1:1s, standups
- Not work → skip immediately — Haircut, gym, dentist, focus time. Calls
DUMP_MEETING_PREP(skip=true)
Research Strategy — Domain Comparison
Internal (same domain):
- Routine sync: Linear current cycle, blockers
- Topic meeting: HYBRID_SEARCH for specs/docs
- Vague title: MEMORY_SEARCH for patterns
External (different domain):
- Known contact: Gmail threads, relationship history
- New contact: PEOPLE_SEARCH, WEB_SEARCH
- High-stakes: all of above + correspondence
The Agent's Prompt is Opinionated
Good: "Heads up: they mentioned response time concerns in their last email"
Bad: "Key Notes: Enterprise prospect. High-stakes call."
Tone: "Sharp colleague giving a heads-up, not a system generating a report." 100 lines of tone guidance and classification heuristics the boss agent's prompt can't carry for every task.
Update Intelligence
- Content Change — Title, description, attendees → regenerate with fresh context
- Time Shift >20 min — Regenerate + publish action item notification
- RSVP-Only — Skip entirely, keep existing prep
- Stale Prep — Generated before today → always regenerate
05 — Reply Generator
Demonstrates parallel pre-computation: expensive operations run before the agent's first LLM call, saving ReAct turns and latency.
LangGraph Execution Flow
START → ┌─ memory_search_node ─┐
├─ preprocess_attachments_node ─┤ → agent ⇄ tools → END
└─ prefetch_tone_skill_node ─┘
Three nodes run in parallel before the agent's first LLM call.
01 — Memory Search
Generates optimized queries from sender/subject/snippet, searches Zep for relationship context. The agent receives pre-computed memory instead of calling MEMORY_SEARCH itself — saves a full ReAct turn.
02 — Attachment Preprocessing
Extracts content from PDFs, images, and documents attached to the latest message. The agent sees extracted text, not raw attachments.
03 — Tone Skill Prefetch
Loads the user's learned email/Slack tone profile (if one exists). Both the Sonnet agent and the Opus refinement pass use this to match the user's natural voice.
Two-Model Architecture
Sonnet 4.6 (Research + draft) → Opus 4.6 (Tone refinement) → Gmail Draft (In user's account)
Production-quality replies at a fraction of the cost. Cheap model for research, expensive model for the final voice.
06 — Design Principles
01 — Each Agent is an Isolated Unit of Work
Every background agent runs on its own NATS consumer with independent retry semantics, cost tracking, and error handling. A failed meeting prep doesn't affect the morning briefing. A timed-out reply generator doesn't block the next email. They share infrastructure (NATS, Postgres, Zep, TurboPuffer) but never share state.
02 — Read-Only by Default
Background agents observe and summarize. They never take actions with real-world consequences — no emails sent, no messages posted, no issues created. The one exception (Gmail draft creation in the reply generator) is a deliberate, user-facing decision that creates a draft, not a sent email.
03 — Terminal Tools Enforce Schema
Every agent ends with a DUMP_* tool call that writes structured output to a purpose-built table. The schema is the API. Adding a field means updating the tool schema, the DB migration, and the UI component.
04 — Deferred Execution Saves Cost
Meeting prep defers non-today events. The morning briefing refreshes stale preps on the day of. Pre-meeting crons run 20 minutes before. This cascading deferral pattern means most events are only processed once, on the day they matter — not on every calendar sync.
05 — Consumer Decides, Agent Executes
The NATS consumer handles all "should we run?" logic — content diffs, time shift detection, RSVP filtering, staleness checks. The agent itself is stateless — it receives context and produces output. The LLM is never invoked for decisions that can be made deterministically.
This architecture powers dimension.dev's background agents — eight specialized agents handling recurring intelligence tasks for thousands of users daily.