Morning Signal is built as a visible agent workflow rather than a hidden prompt chain. The core design choice is simple: gather source evidence first, then ask the model to synthesize.
Company URL
-> company profile discovery
-> human approval checkpoint
-> LangGraph query planner
-> Nimble Search
-> Nimble Extract
-> evidence packet
-> OpenAI synthesis
-> typed newsletter brief
-> Next.js UI
-> optional Resend delivery
Live retrieval quality depends on context quality. If the agent misunderstands the company, ICP, market, or competitors, every downstream search becomes noisier.
The approval step lets a user correct the inputs before the agent spends calls on live research.
LangGraph makes the agent stages explicit:
That separation makes the workflow easier to observe, extend, and test. It also
supports the streamed UI in /api/brief/stream, where each graph stage updates
the visual work map before the final brief appears.
Nimble is in the critical path before synthesis:
nimbleSearch() discovers fresh public web sources.nimbleExtract() turns selected URLs into usable page content.The LLM does not act as the source of truth. It receives a bounded evidence packet and turns that packet into a structured brief.
The app uses Zod schemas in lib/types.ts to keep the workflow typed:
CompanyProfileSearchResultExtractedPageNewsletterBriefSignalSourceStructured schemas make the UI predictable and make it easier to validate whether final claims are source-backed.
Set:
DEMO_MODE=true
Demo mode uses deterministic fixtures in lib/company.ts, lib/nimble.ts, and
lib/llm.ts. It preserves the workflow shape without requiring live provider
credentials.
This is the recommended mode for public demos.
Set:
DEMO_MODE=false
NIMBLE_API_KEY=
OPENAI_API_KEY=
Live mode calls Nimble Search, Nimble Extract, and OpenAI. It can research any valid public HTTP/HTTPS company website.
Local live runs save generated briefs in SQLite at:
data/signals.db
Database files are ignored by git. In demo mode, API routes skip persistence so the app can run safely on serverless hosting.
For production, replace SQLite with durable managed storage.
lib/email.ts sends the finished brief through Resend when configured. The
recipient must be included in NEWSLETTER_ALLOWED_RECIPIENTS.
This prevents the demo from becoming an open email relay.
Set these values to trace graph execution:
LANGSMITH_TRACING=true
LANGSMITH_API_KEY=
LANGSMITH_PROJECT=nimble-gtm-signal-agent
Useful traces include planned queries, result counts, extraction failures, source counts, synthesis prompts, and validation results.