_ _ _____ _ _ _____ _ _______ _____ _____ ___ _____ _____
| | | | ___| \ | |_ _| | | | ___ \ ___| / ___|/ _ \| __ \| ___|
| | | | |__ | \| | | | | | | | |_/ / |__ \ `--./ /_\ \ | \/| |__
| | | | __|| . ` | | | | | | | /| __| `--. \ _ | | __ | __|
\ \_/ / |___| |\ | | | | |_| | |\ \| |___ /\__/ / | | | |_\ \| |___
\___/\____/\_| \_/ \_/ \___/\_| \_\____/ \____/\_| |_/\____/\____/
Know before you invest.
VENTURE SAGE is a production-grade, multi-agent due diligence system that turns a plain-text startup description into a structured investment memo in minutes. Built on AWS Bedrock and the Strands Agents SDK, it orchestrates a team of seven specialized AI agents β each connected to real-time web research APIs β that run in a deterministic BFS-resolved dependency graph.
The result: institutional-quality analysis covering market sizing, competitive landscape, founder credibility, financial health, risk exposure, and a scored investment recommendation β all streamed to a Rich interactive CLI.
| Capability | Detail |
|---|---|
| 7 Specialized Agents | Market Β· Competitor Β· Founder Β· Finance Β· Risk Β· Investment Β· Memo |
| Staged Parallel Execution | Stage 1 agents run concurrently via asyncio.gather; downstream stages receive merged context |
| Deterministic Routing | BFS walk over the agent DAG β no supervisor LLM, no routing hallucinations |
| Cascade Prevention | A downstream agent is skipped when all of its dependencies have failed β partial failures allow downstream agents to run with available context |
| Structured Output | Every agent enforces a Pydantic v2 response_model with Literal types at the LLM boundary |
| Input Guardrails | Startup descriptions are validated for length, readability, and prompt-injection patterns before entering the pipeline |
| Output Guardrails | Agent outputs are checked for hollow fields and score-category coherence before propagating downstream |
| Offline Evals | Two eval suites (guardrail + structural) run without LLM calls β schema constraints, cross-agent consistency, golden-data checks |
| Prompt Caching | Bedrock CacheConfig(strategy="auto") cuts latency and cost on repeated runs |
| Streaming Tokens | Custom callback_handler streams raw LLM tokens β zero SDK noise |
| Context Summarization | SummarizingConversationManager compresses overflow instead of dropping turns |
| 9 Research APIs | Exa Β· Tavily Β· SerpAPI Β· NewsAPI Β· GDELT Β· HackerNews Β· Firecrawl Β· Google Trends Β· HaveIBeenPwned |
| Interactive CLI | Rich-powered terminal with panels, tables, banners, and follow-up chat |
flowchart TD
User([CLI Command + Startup Description]) --> BFS
subgraph Orchestration["Workflow Orchestrator (BFS Dependency Resolution)"]
BFS["required_agents_for_execution\nResolves stage graph from target agent"]
end
BFS --> Stage1
subgraph Stage1["Stage 1 β Parallel Research asyncio.gather"]
MA["Market Agent\nTAM Β· SAM Β· SOM\nTrends Β· Growth Rate"]
CA["Competitor Agent\nPositioning Β· Market Share\nDifferentiation"]
FA["Finance Agent\nFunding History Β· Burn Rate\nValuation Β· Revenue"]
FO["Founder Agent\nLeadership Β· Experience\nPrior Exits"]
end
Stage1 --> Stage2
subgraph Stage2["Stage 2 β Risk Synthesis"]
RA["Risk Agent\nTech Β· Market Β· Regulatory\nOperational Β· Execution Risk"]
end
Stage2 --> Stage3
subgraph Stage3["Stage 3 β Investment Scoring"]
IA["Investment Agent\nSWOT Β· Score 0 to 10\nStrong Invest / Pass"]
end
Stage3 --> Stage4
subgraph Stage4["Stage 4 β Report Generation"]
MemoA["Memo Agent\nInvestment Memo\nExecutive Summary"]
end
MemoA --> Output([Structured Investment Memo + Streaming Summary])
style Orchestration fill:#232F3E,color:#FF9900,stroke:#FF9900
style Stage1 fill:#1a3a5c,color:#ffffff,stroke:#4a90d9
style Stage2 fill:#3a1a1a,color:#ffffff,stroke:#d94a4a
style Stage3 fill:#1a3a1a,color:#ffffff,stroke:#4ad94a
style Stage4 fill:#2a1a3a,color:#ffffff,stroke:#9a4ad9
sequenceDiagram
autonumber
actor User
participant WF as Workflow Orchestrator
participant MA as Market Agent
participant CA as Competitor Agent
participant FO as Founder Agent
participant FA as Finance Agent
participant RA as Risk Agent
participant IA as Investment Agent
participant MEM as Memo Agent
User->>WF: /analyze <startup description>
WF->>WF: BFS resolves stage graph
par Stage 1 - asyncio.gather
WF->>MA: workflow_context
WF->>CA: workflow_context
WF->>FO: workflow_context
WF->>FA: workflow_context
end
MA-->>WF: MarketAnalysis
CA-->>WF: CompetitionAnalysis
FO-->>WF: FounderAnalysis
FA-->>WF: FinanceAnalysis
WF->>RA: workflow_context (+ Stage 1 results)
RA-->>WF: RiskAnalysis
WF->>IA: workflow_context (+ Stage 1 results + RiskAnalysis)
IA-->>WF: InvestmentAnalysis
WF->>MEM: workflow_context (+ InvestmentAnalysis)
MEM-->>User: MemoReport (streamed + summary panel)
graph LR
subgraph Agents
MA[Market Agent]
CA[Competitor Agent]
FO[Founder Agent]
FA[Finance Agent]
RA[Risk Agent]
end
subgraph Market Tools
MRT[market_research_tool]
MNT[market_news_tool]
MDT[market_discussion_tool]
MTT[market_trends_tool]
end
subgraph Competitor Tools
CST[competitor_search_tool]
CNT[competitor_news_tool]
CPT[competitor_pricing_tool]
PRT[product_reviews_tool]
end
subgraph Founder Tools
FRT[founder_research_tool]
FMT[founder_mentions_tool]
end
subgraph Finance Tools
FHT[funding_history_tool]
RST[revenue_signals_tool]
TGT[team_growth_tool]
end
subgraph Risk Tools
RRT[regulatory_risk_tool]
SIT[security_incidents_tool]
end
subgraph External Services
EXA[Exa]
TAV[Tavily]
SERP[SerpAPI]
NEWS[NewsAPI]
GDELT[GDELT]
HN[HackerNews]
FC[Firecrawl]
TRENDS[Google Trends]
HIBP[HaveIBeenPwned]
end
MA --> MRT & MNT & MDT & MTT
CA --> CST & CNT & CPT & PRT
FO --> FRT & FMT
FA --> FHT & RST & TGT
RA --> RRT & SIT
MRT --> EXA
MNT --> NEWS
MDT --> HN
MTT --> TRENDS
CST --> SERP
CNT --> GDELT
CPT --> FC
PRT --> TAV
FRT --> EXA
FMT --> SERP
FHT --> EXA
RST --> TAV
TGT --> SERP
RRT --> SERP
SIT --> HIBP
venture-sage/
βββ app.py # Entry point β credential check + CLI launch
β
βββ workflow/
β βββ due_diligence_workflow.py # BFS orchestrator β stages + cascade prevention
β
βββ agents/
β βββ base_agent.py # Abstract base β Strands Agent + streaming callback
β βββ market_agent.py # TAM/SAM/SOM + trends analysis
β βββ competitor_agent.py # Competitive landscape research
β βββ founder_agent.py # Leadership & team credibility
β βββ financial_agent.py # Funding history & financial health
β βββ risk_agent.py # Multi-dimensional risk scoring
β βββ investment_agent.py # SWOT + investment recommendation
β βββ memo_agent.py # Final investment memo generation
β
βββ guardrails/
β βββ input_guardrails.py # Validates startup descriptions (length, injection patterns)
β βββ output_guardrails.py # Validates agent outputs (completeness, score coherence)
β
βββ evals/
β βββ run_evals.py # Rich CLI runner β python -m evals.run_evals
β βββ guardrail_evals.py # Offline tests for input/output guardrail accept/reject
β βββ structural_evals.py # Schema constraint + cross-agent consistency evals
β βββ test_cases.py # Golden mock data for strong/weak startup profiles
β
βββ cli/
β βββ chat.py # Interactive chat loop β command dispatch
β βββ commands.py # Command handlers + follow-up chat support
β βββ registry.py # Command descriptions for /help
β
βββ tools/
β βββ market/ # Market research, news, trends, discussion tools
β βββ competitor/ # Competitor search, pricing, reviews, news tools
β βββ founder/ # Founder research & mentions tools
β βββ finance/ # Funding history, revenue signals, team growth tools
β βββ risk/ # Regulatory risk & security incident tools
β
βββ services/
β βββ base_service.py # Shared env-loading + HTTP helpers
β βββ exa_service.py # Exa neural search
β βββ tavily_service.py # Tavily AI search
β βββ serpapi_service.py # Google/Bing SERP results
β βββ newsapi_service.py # News API headlines
β βββ gdelt_service.py # GDELT global event database
β βββ hackernews_service.py # HackerNews discussions
β βββ firecrawl_service.py # Web scraping & crawling
β βββ trends_service.py # Google Trends pytrends
β βββ hibp_service.py # Have I Been Pwned β security checks
β βββ feedparser_service.py # RSS/Atom feed parser
β
βββ config/
β βββ settings.py # BedrockModel config (Nova Pro, us-east-1)
β βββ agent_registry.py # Agent registry β stage, deps, BFS resolver
β
βββ utils/
β βββ console.py # Rich console β streaming, panels, banners
β
βββ prompts/
βββ market_agent_prompt.md
βββ competitor_agent_prompt.md
βββ founder_agent_prompt.md
βββ financial_agent_prompt.md
βββ risk_agent_prompt.md
βββ investment_agent_prompt.md
βββ memo_agent_prompt.md
| Agent | Stage | Domain | Output Model | Tools Used |
|---|---|---|---|---|
| Market | 1 | Research | MarketAnalysis |
market_research, market_news, trends, discussions |
| Competitor | 1 | Research | CompetitionAnalysis |
competitor_search, pricing, reviews, news |
| Founder | 1 | Research | FounderAnalysis |
founder_research, mentions |
| Finance | 1 | Research | FinanceAnalysis |
funding_history, revenue_signals, team_growth |
| Risk | 2 | Analysis | RiskAnalysis |
regulatory_risk, security_incidents |
| Investment | 3 | Analysis | InvestmentAnalysis |
β (consumes Stage 1 + 2 context) |
| Memo | 4 | Reporting | MemoReport |
β (consumes full pipeline context) |
All agents extend BaseAgent, which wraps the Strands Agent with a BedrockModel, enforces structured output via a Pydantic v2 response_model, and streams tokens in real-time via a custom callback handler. Score category and recommendation fields use Literal types β invalid values are rejected at the Pydantic boundary before they can propagate downstream.
Launch VENTURE SAGE:
python app.pyOnce inside the interactive CLI:
| Command | Description |
|---|---|
/analyze <description> |
Full pipeline β runs all 7 agents through to the investment memo |
/market <description> |
Market sizing and trends analysis only |
/competition <description> |
Competitive landscape only |
/founder <description> |
Founder & team credibility analysis only |
/finance <description> |
Funding rounds and financial health only |
/risk <description> |
Risk assessment (requires Stage 1 results) |
/investment <description> |
SWOT scoring and investment recommendation |
/memo <description> |
Full memo generation (equivalent to /analyze) |
/agents |
List all registered agents with stage and domain |
/help |
Show all available commands |
/memo-export |
Export last memo as Markdown or JSON (e.g. /memo-export json , /memo-export md) |
/clear |
Clear the terminal |
/exit |
Exit VENTURE SAGE |
Inline descriptions β pass the startup name or description directly on the command:
you > /analyze cursor ai
you > /market stripe payments platform
you > /founder openai
Follow-up questions β after any command, continue the conversation naturally:
you > /founder anthropic
[founder analysis streams...]
you > which universities did the founders attend?
[agent replies using full conversation history]
| Layer | Technology |
|---|---|
| LLM Runtime | AWS Bedrock β us.amazon.nova-pro-v1:0 |
| Agent Framework | Strands Agents SDK |
| Prompt Caching | Bedrock CacheConfig(strategy="auto") β reduces latency and token cost |
| Structured Output | Pydantic v2 response_model enforced at every LLM boundary |
| Context Management | SummarizingConversationManager β LLM-compresses overflow, preserves recent turns |
| Concurrency | asyncio.gather β true parallel Stage 1 execution |
| Streaming | Custom callback_handler β raw LLM token streaming, no SDK noise |
| Web Research | Exa Β· Tavily Β· SerpAPI Β· NewsAPI Β· GDELT Β· HackerNews Β· Firecrawl |
| Signals | Google Trends Β· Have I Been Pwned Β· FeedParser (RSS) |
| CLI | Rich β panels, tables, streaming output, banners |
| Python | 3.12 with uv |
- Python 3.12+
- AWS account with Bedrock access in
us-east-1 - Model access enabled for
us.amazon.nova-pro-v1:0in the Bedrock console - AWS credentials configured via
~/.aws/credentials, environment variables, or an IAM role
# Clone the repository
git clone https://github.com/your-username/venture-sage.git
cd venture-sage
# Install with uv (recommended)
uv sync
# Or with pip (requirements.txt is pinned and generated from uv.lock)
pip install -r requirements.txtCreate a .env file in the project root:
# AWS (or use IAM role / aws configure)
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_DEFAULT_REGION=us-east-1
# Web research APIs
EXA_API_KEY=your_exa_key
TAVILY_API_KEY=your_tavily_key
SERPAPI_API_KEY=your_serpapi_key
NEWSAPI_KEY=your_newsapi_key
FIRECRAWL_API_KEY=your_firecrawl_key/analyze & /memo-export md & /memo-export json β Full Pipeline β Investment Memo + Export report
Before any startup description enters the agent pipeline, guardrails/input_guardrails.py enforces:
| Check | Rule |
|---|---|
| Empty / whitespace | Rejected immediately |
| Min length | Must be β₯ 20 characters |
| Max length | Must be β€ 5 000 characters |
| Readability | Must contain at least one alphabetic character |
| Prompt injection | 12 regex patterns block ignore previous instructions, system prompt, act as, pretend you are, always score this a 10, etc. |
If validation fails, the CLI prints a clear error and aborts β no agent is invoked.
After each agent returns a Pydantic model, guardrails/output_guardrails.py checks for:
- Hollow fields β string fields shorter than 15 characters (excluding short-by-design labels like
recommendationandround_name) - Empty lists β any list field that came back empty (the agent likely failed to gather data)
- Scoreβcategory coherence β warns when a numeric score contradicts its label (e.g.
investment_score=9.5paired withscore_category="Weak")
Warnings are non-blocking and surface in logs. Errors cause the workflow to treat the agent as failed and trigger cascade prevention.
Run all offline eval suites (no LLM calls required):
# Run all suites
python -m evals.run_evals
# Run only guardrail evals
python -m evals.run_evals --suite guardrail
# Run only structural evals
python -m evals.run_evals --suite structural| Suite | What it tests |
|---|---|
| Guardrail | Input guardrail blocks empty, short, long, and injected descriptions; output guardrail warns on hollow/incoherent outputs |
| Structural | Pydantic Literal / ge / le constraints are enforced; score ranges match profile strength in golden data; cross-agent scores are internally consistent |
Golden mock data for both a "strong startup" and a "weak startup" profile lives in evals/test_cases.py and is shared across suites.
BFS dependency resolution over a supervisor agent
required_agents_for_execution performs a BFS walk over the agent DAG to determine exactly which agents must run for any given target. This is fully deterministic and eliminates an extra LLM call for routing β no hallucinated shortcuts, no missed dependencies.
Cascade prevention on agent failure
A downstream agent is only blocked when every one of its dependencies has failed β if at least one dependency succeeded, the agent runs with whatever context is available. This allows partial pipeline results to reach the investment and memo stages even when one Stage 1 agent is unavailable. An agent whose sole dependency failed (e.g. investment_agent when risk_agent fails) is skipped entirely and the gap is surfaced in the CLI.
Streaming via custom callback_handler
Strands' default PrintingCallbackHandler emits tool call noise alongside LLM tokens. The custom handler intercepts only data events (raw text tokens), giving a clean real-time stream with no internal SDK logs leaking into the terminal.
SummarizingConversationManager over a sliding window
Agents that invoke many tools in a single run (e.g. risk_agent) accumulate large message histories. Rather than dropping the oldest turns (which loses analytical context), the summarizing manager compresses them with an LLM call and retains the summary alongside recent turns.
Singleton agents with per-run messages.clear()
Agents are instantiated once at registry load time to avoid repeated model initialization overhead. messages.clear() at the start of each run() ensures that one company's conversation history cannot contaminate the next analysis.
Pydantic response_model on every agent
Each agent's output is consumed as a typed input by the next stage. Enforcing the schema at the LLM boundary prevents silent data loss, missing fields, or hallucinated key names from propagating through the pipeline undetected.
Literal types for enumerated fields
score_category and recommendation on RiskAnalysis, FinanceAnalysis, and InvestmentAnalysis are Literal[...] rather than plain str. Pydantic rejects any value not in the allowed set at instantiation time, so an LLM that writes "Buy Now" instead of "INVEST" causes an immediate validation error rather than a silent downstream mismatch.
Input guardrails at the CLI boundary
Prompt-injection patterns (and simple length / readability checks) are applied in cli/commands.py before the workflow is invoked. Blocking at the boundary means no agent is loaded, no Bedrock call is made, and no partial pipeline state is left in an undefined condition.
Offline evals for schema and guardrail correctness
evals/ contains two suites that run without any LLM calls. Structural evals use golden mock data to verify that Pydantic constraints, score ranges, and cross-agent consistency rules hold. Guardrail evals verify that the input and output guardrails accept and reject exactly the cases they should. These run in CI and catch regressions in model definitions and guardrail patterns before they reach production.
- Fork the repository
- Create a feature branch (
git checkout -b feature/new-agent) - Commit your changes
- Open a Pull Request
MIT License β see LICENSE for details.
Built with the AWS Strands Agents SDK Β· Powered by Amazon Bedrock
VENTURE SAGE β Know before you invest.

