A multi-agent financial research and recommendation system: supervisor +
9 specialist agents orchestrated with LangGraph, backed by a Postgres
schema, typed tool contracts, and a full test suite. This is the V1
scope from the blueprint: research and recommend, never autonomously
execute. Execution is structurally gated behind an explicit human
ApprovalRecord — the code refuses to trade without it, not just the
prompt.
Everything in this repo runs offline with zero API keys: all data
tools (tools/*/tool.py) are mock implementations with deterministic
synthetic data, built to the same contract real providers would use.
Swap the tool bodies for real integrations (OpenBB, EDGAR, a news API,
a broker) without touching agents, the graph, or the schema.
- Repo scaffold —
apps/ agents/ tools/ workflows/ schemas/ data/ prompts/ db/ tests/ docs/ infra/, matching the blueprint's brain/tools/data/policy/test separation. - SQL migrations —
db/migrations/0001..0006*.sql, 22 tables covering identity, documents, market data, research, risk/compliance/ trading, and full audit/tool-call traceability. Verified against a real local Postgres 16 instance (see "Verify the database" below). - LangGraph node definitions —
agents/*/agent.py+agents/supervisor/graph.py. A real, compiled, runnableStateGraphwith fan-out/fan-in across the 4 specialist agents and a conditional risk/compliance gate. - Prompts + JSON schemas —
prompts/system/,prompts/roles/(one file per agent, expanding the blueprint's short prompts into full behavioral specs) andschemas/tool_contracts/*.json(generated from the pydantic models — regenerate withpython -m schemas.tool_contracts.generate).
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# Run the full pipeline end-to-end (no API keys needed -- mocked tools)
python run_demo.py AAPL
# Run the full test suite (29 tests: unit, integration, e2e, safety)
python -m pytest tests/ -vrequest
-> research (retrieves market data, filings, news)
-> fan out: fundamentals | technicals | macro | sentiment (parallel)
-> synthesize (supervisor merges into a Thesis)
-> risk (schemas/policies/risk_policy.json; can BLOCK)
-> compliance (permissions/approval checks; can BLOCK)
-> [blocked] -> audit_close -> end
-> [proceed] -> execution (refuses without an ApprovalRecord) -> audit_close -> end
Every node appends to audit_trail in the graph state; nothing is
silently dropped. See agents/supervisor/graph.py for the exact wiring
and schemas/domain/state.py for the LangGraph state schema (a
TypedDict with operator.add reducers — nodes return deltas, not full
accumulated lists).
Migrations are plain numbered SQL, runnable by any migration tool or
raw psql:
createdb finance_super_agent
for f in db/migrations/*.sql db/views/*.sql; do psql finance_super_agent -f "$f"; done
psql finance_super_agent -f db/seeds/0001_demo_seed.sql # optional, dev onlyThis was verified against a real local Postgres 16 instance during development — all 6 migrations, both views, and the seed file run clean with zero errors, producing 22 tables.
Every mock tool in tools/*/tool.py implements the exact contract in
schemas/tool_contracts/contracts.py. To go live:
- Replace the body of
run()in the relevant tool file with a real API call (OpenBB for market data, EDGAR full-text search for filings, a real news API, a real doc-AI pipeline). - Keep the input/output pydantic models unchanged — agents, the graph, and the JSON schemas don't need to change.
- Point
.env(copy.env.example) at real credentials. - Wire
db/as the persistence layer: agent runs, findings, theses, and the full audit trail are designed to be written there (this scaffold keeps state in-memory in the LangGraph run for simplicity; add a persistence layer inagents/audit/agent.pyandagents/supervisor/graph.pywhen ready).
Verified by tests/safety/test_no_execution_without_approval.py:
- Execution refuses to act on any
trade_intentwhosestatusisn'tapproved. - Execution refuses without an exact-matching
ApprovalRecord(reference_id,action_type="place_order",approved=True). - Risk blocks on insufficient conviction (horizon-specific thresholds), insufficient distinct supporting agents, and records — without blocking — any agent-reported missing inputs.
- Every block carries a specific machine-readable and human-readable reason; nothing fails silently.
See docs/architecture/ (add your own diagrams here) and the inline
docstring at the top of each agents/*/agent.py file, which links back
to its corresponding prompt in prompts/roles/.