Production-grade template for multi-agent LangGraph systems — hardened FastAPI API, domain packs, Helm, Terraform stubs, CI, and observability. Multi-tenant identity is your layer (Security guide).
A deployable starting point for ML / data engineers who want a real agent stack—not a notebook demo. The default pipeline is Research → Analysis (ResearchAgent + AnalystAgent), exposed over FastAPI with SSE streaming, session history, cost tracking, and pack-based routing.
Included: Docker, Helm chart, Terraform entry points (GKE / EKS / AKS), rate limiting, input validation, structured logging, Prometheus metrics, CI security scans, GHCR images with SBOM + Cosign on main.
Not included: OAuth2/OIDC, per-tenant API keys, or billing. The built-in API_KEY is a single shared Bearer secret for internal / single-tenant use.
git clone https://github.com/brescou/langgraph-agent-stack.git
cd langgraph-agent-stack
uv sync --extra anthropic
cp .env.example .env # set ANTHROPIC_API_KEY
uv run uvicorn api.main:app --reload# Legacy default pipeline (research_analysis pack)
curl -X POST http://localhost:8000/run \
-H "Content-Type: application/json" \
-d '{"query": "What are the latest advances in quantum computing?"}'
# Pack registry
curl http://localhost:8000/packs
curl -X POST http://localhost:8000/packs/meeting_prep/run \
-H "Content-Type: application/json" \
-d '{"company": "Acme", "person": "Jane", "meeting_goal": "discovery"}'Interactive API docs: http://localhost:8000/docs (disabled when ENVIRONMENT=production).
Client → FastAPI (auth · rate limit · validation)
→ PackRegistry / control_plane policies
→ domain_packs/* (LangGraph workflows)
→ agents/* (reusable agent nodes)
→ core/* (LLM · memory · security · cost · observability)
→ connectors/* (optional retrieval)
| Layer | Path | Role |
|---|---|---|
| HTTP | api/ |
FastAPI app (app.py), middlewares, endpoints, pack router factory |
| Kernel | pack_kernel/ |
BaseDomainPack, PackRegistry, versioning, traffic split |
| Workflows | domain_packs/ |
Packs grouped by domain — see domain_packs/README.md |
| Agents | agents/ |
Reusable LangGraph agents (ResearchAgent, AnalystAgent, …) |
| Policies | control_plane/ |
Per-pack limits (query size, budget, stream timeout) — control_plane/README.md |
| Connectors | connectors/ |
Retrieval adapters — connectors/README.md (core/connectors.py is a compat shim) |
| Foundation | core/ |
Config, LLM factory, memory, security, cost, observability |
| Ops | infra/ |
Dockerfile, Compose, Helm, Terraform |
core/graph.py is a compatibility shim (MultiAgentGraph → ResearchAnalysisPack). New orchestration belongs in a domain pack.
13 built-in packs registered in pack_kernel/builtin_packs.py:
| Category | Examples |
|---|---|
Research (domain_packs/research/) |
research_analysis, research_only, analysis_only |
Productivity (domain_packs/productivity/) |
summariser, meeting_prep, rfp_assistant, support_triage, executive_brief |
HR (domain_packs/hr/) |
talent_screening, job_description_writer, hr_policy_qa |
Finance (domain_packs/finance/) |
financial_memo |
Legal (domain_packs/legal/) |
contract_reviewer |
Each pack gets typed POST /packs/{pack_id}/run and /run/stream when schemas are declared. Versioning, traffic weights, and sticky sessions: GET /packs, GET /packs/{id}/versions, headers X-Pack-Version / X-Pack-Version-Used.
Full catalogue and authoring guide: domain_packs/README.md.
Third-party packs ship as regular Python packages declaring an entry point in
the langgraph_agent_stack.packs group:
[project.entry-points."langgraph_agent_stack.packs"]
sentiment = "acme_packs.sentiment:SentimentPack"Discovery is opt-in and allowlisted (PACK_PLUGINS_ENABLED=true +
PACK_PLUGINS_ALLOWLIST=sentiment): loading a plugin executes third-party
code, so nothing loads by default. At load time each class is validated
against the pack contract — BaseDomainPack subclass, complete metadata, and
strict (extra="forbid") input/output schemas — and a broken plugin is
logged and skipped, never crashing startup. Built-in pack ids cannot be
overridden. Registered plugins get the same typed /packs/{id}/run routes,
versioning, and canary weights as built-ins. Packaging walkthrough:
examples/custom_pack/README.md.
| Method | Path | Description |
|---|---|---|
GET |
/packs |
List registered packs and metadata |
POST |
/packs/{pack_id}/run |
Run a pack (typed body per pack schema) |
POST |
/packs/{pack_id}/run/stream |
SSE stream for a pack |
POST |
/run, /run/stream |
Legacy routes → DEFAULT_PACK_ID (research_analysis) |
POST |
/research |
Research phase only |
GET |
/health, /ready |
Probes |
GET |
/sessions/{id}/history |
Session run history |
GET |
/metrics |
Prometheus (with observability extra) |
Responses include cost_usd when cost tracking is active; HTTP 402 on budget exceed. See /docs for request/response schemas.
Set LLM_PROVIDER and install the matching extra. Details and gateway overrides: .env.example.
| Provider | Value | Extra | Key env vars |
|---|---|---|---|
| Anthropic | anthropic |
--extra anthropic |
ANTHROPIC_API_KEY |
| OpenAI | openai |
--extra openai |
OPENAI_API_KEY |
google |
--extra google |
GOOGLE_API_KEY |
|
| Bedrock | bedrock |
--extra bedrock |
AWS_REGION, BEDROCK_MODEL |
| Azure OpenAI | azure |
--extra openai |
AZURE_OPENAI_* |
| Ollama | ollama |
--extra ollama |
OLLAMA_BASE_URL |
| Mock (CI/dev) | mock |
(none) | — |
Docker Compose
docker compose -f infra/docker-compose.yml up
docker compose -f infra/docker-compose.yml --profile redis up # Redis memory backendHelm
helm install langgraph ./infra/helm/langgraph-agent-stack \
-f infra/helm/langgraph-agent-stack/values.prod.yaml \
--namespace langgraph-agents --create-namespaceProduction: set secrets.existingSecret (External Secrets Operator), config.environment=production, networkPolicy.enabled=true. Autoscaling defaults to KEDA on active_pipelines (not CPU). See chart values.yaml / values.prod.yaml.
Terraform — entry points under infra/terraform/{gke,eks,aks}/ (no shared root module). Configure a remote backend before production apply. GKE module expects External Secrets Operator installed before ClusterSecretStore resources.
Infra CI locally: make infra-check (template Checkov profile). Before production hardening: make infra-check-prod (checklist).
Rate limiting (memory or Redis), request body cap, prompt-injection / SSRF input validation, security headers, optional API_KEY Bearer auth, graceful shutdown drain. Full model, env vars, K8s hardening, and scanning pipeline: docs/security.md.
make help # all targets
make check # ruff + pyright (CI lint)
make test # pytest (mocked; use -m integration for testcontainers)
make eval # golden-dataset pack evaluations (deterministic)
make infra-check # helm lint + kubeconform + checkovevals/ runs golden datasets (evals/datasets/<pack_id>.yaml) through the
real pack code with scripted LLM responses — deterministic, no network. Each
case declares an input, the scripted responses, and checks
(required_fields, contains, min_length, numeric_range, or
expect_error for guard rejections). Compare two registered versions of a
pack before shifting canary weights:
uv run python -m evals --pack summariser # one pack
uv run python -m evals --pack summariser --version 1.0 --compare 2.0
uv run python -m evals --all --json # CI-friendly outputContributor workflow, pre-commit, and PR expectations: CONTRIBUTING.md.
LangGraph patterns (standalone scripts, not served by the API): examples/README.md.
langgraph-agent-stack/
├── api/ # FastAPI (app.py, middleware, endpoints, router_factory)
├── pack_kernel/ # Pack contract + PackRegistry
├── domain_packs/ # research/, productivity/, hr/, finance/, legal/, common/
├── agents/ # Reusable LangGraph agents
├── connectors/ # Retrieval connector implementations
├── control_plane/ # Pack policies
├── core/ # Config, LLM, memory, security, cost, observability
├── infra/ # Dockerfile, compose, helm/, terraform/
├── examples/ # LangGraph pattern demos
├── tests/
├── docs/ # security.md, architecture.md, …
└── scripts/ # infra-devsecops.sh, …
| Doc | Contents |
|---|---|
| docs/security.md | Auth, secrets, K8s hardening, CI scans, supply chain, Checkov prod gate |
| domain_packs/README.md | Pack catalogue and authoring |
| connectors/README.md | Connector contract and wiring |
| control_plane/README.md | Policy registry |
| examples/README.md | Sequential, parallel, supervisor, human-in-loop |
| CONTRIBUTING.md | Dev setup, tests, PR process |
| CHANGELOG.md | Release history |
MIT © brescou