{"slug": "show-hn-production-grade-langgraph-template", "title": "Show HN: Production-grade LangGraph template", "summary": "A developer released a production-grade open-source template for building multi-agent LangGraph systems on GitHub. The template includes a hardened FastAPI API, Helm and Terraform stubs, CI/CD, observability, and a mock provider for zero-cost testing, targeting ML and data engineers who want to self-host agent stacks on Kubernetes. It ships under the MIT license with features like per-run USD budgets, multi-version pack routing, and signed container images.", "body_md": "Production-grade\n\ntemplatefor multi-agent LangGraph systems — hardened FastAPI API, domain packs, Helm, Terraform stubs, CI, and observability. Multi-tenant identity isyourlayer ([Security guide]).\n\nA real session against the built-in **mock provider** — no API key, zero token cost, deterministic output (ideal for exploring the API, tests, and CI):\n\nA deployable starting point for ML / data engineers who want a **real** agent stack—not a notebook demo. The default pipeline is Research → Analysis (`ResearchAgent`\n\n+ `AnalystAgent`\n\n), exposed over FastAPI with SSE streaming, session history, cost tracking, and pack-based routing.\n\n**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`\n\n.\n\n**Not included:** OAuth2/OIDC, per-tenant API keys, or billing. The built-in `API_KEY`\n\nis a single shared Bearer secret for internal / single-tenant use.\n\n**…LangGraph Platform?** LangGraph Platform is a legitimate, well-supported managed option — use it if you want a hosted control plane and don't want to run infrastructure yourself. This repo is for the opposite case: you self-host on your own Kubernetes cluster, keep full control of observability (Prometheus/OTel) and per-run cost data, and ship under the MIT license with zero vendor lock-in. Neither is objectively \"better\" — it's a build-vs-buy trade-off, and this template is for teams who'd rather own the stack.\n\n**…a generic agent-service-toolkit template?** Beyond the usual FastAPI-around-LangGraph scaffolding, this repo ships production concerns already wired in: per-run USD budgets that return HTTP `402`\n\non overrun, multi-version pack routing with canary traffic weights, and a supply chain that signs container images with Cosign and publishes an SBOM on every release.\n\n**Prerequisites:** Python 3.12+, [ uv](https://docs.astral.sh/uv/getting-started/installation/) (package manager).\n\n```\ngit clone https://github.com/brescou/langgraph-agent-stack.git\ncd langgraph-agent-stack\nuv sync --extra anthropic\ncp .env.example .env   # set ANTHROPIC_API_KEY\nuv run uvicorn api.main:app --reload\n```\n\nTry it without any API key.Set`LLM_PROVIDER=mock`\n\nin`.env`\n\n(or`LLM_PROVIDER=mock uv run uvicorn api.main:app --reload`\n\n) to get deterministic, zero-cost responses from every endpoint — useful for exploring the API, running the test suite, or CI, before wiring up a real provider. Web search is also mocked by default (`SEARCH_PROVIDER=mock`\n\n); set`SEARCH_PROVIDER=tavily`\n\n(or`serpapi`\n\n) for real results.\n\n```\n# Legacy default pipeline (research_analysis pack)\ncurl -X POST http://localhost:8000/run \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"query\": \"What are the latest advances in quantum computing?\"}'\n\n# Pack registry\ncurl http://localhost:8000/packs\ncurl -X POST http://localhost:8000/packs/meeting_prep/run \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"company\": \"Acme\", \"person\": \"Jane\", \"meeting_goal\": \"discovery\"}'\n```\n\nInteractive API docs: `http://localhost:8000/docs`\n\n(disabled when `ENVIRONMENT=production`\n\n).\n\n**Cost:** with a real provider, a `research_analysis`\n\nrun (6 LLM calls) costs roughly **$0.01–0.05** on Claude Sonnet 5 pricing ($0.003 / $0.015 per 1K input/output tokens) — a rough order of magnitude from the pricing table in `core/cost.py`\n\n, not a measured benchmark. Set `PACK_DEFAULT_BUDGET_USD=0.50`\n\nto cap spend per run; requests over budget return HTTP `402`\n\n.\n\n```\nClient → FastAPI (auth · rate limit · validation)\n              → PackRegistry / control_plane policies\n              → domain_packs/* (LangGraph workflows)\n              → agents/* (reusable agent nodes)\n              → core/* (LLM · memory · security · cost · observability)\n              → connectors/* (optional retrieval)\n```\n\n| Layer | Path | Role |\n|---|---|---|\n| HTTP | `api/` |\nFastAPI app (`app.py` ), middlewares, endpoints, pack router factory |\n| Kernel | `pack_kernel/` |\n`BaseDomainPack` , `PackRegistry` , versioning, traffic split |\n| Workflows | `domain_packs/` |\nPacks grouped by domain — see\n|\n\n`agents/`\n\n`ResearchAgent`\n\n, `AnalystAgent`\n\n, …)`control_plane/`\n\n[control_plane/README.md](/Brescou/langgraph-agent-stack/blob/main/control_plane/README.md)`connectors/`\n\n[connectors/README.md](/Brescou/langgraph-agent-stack/blob/main/connectors/README.md)(`core/connectors.py`\n\nis a compat shim)`core/`\n\n`infra/`\n\n`core/graph.py`\n\nis a **compatibility shim** (`MultiAgentGraph`\n\n→ `ResearchAnalysisPack`\n\n). New orchestration belongs in a domain pack.\n\n13 built-in packs registered in `pack_kernel/builtin_packs.py`\n\n:\n\n| Category | Examples |\n|---|---|\nResearch (`domain_packs/research/` ) |\n`research_analysis` , `research_only` , `analysis_only` |\nProductivity (`domain_packs/productivity/` ) |\n`summariser` , `meeting_prep` , `rfp_assistant` , `support_triage` , `executive_brief` |\nHR (`domain_packs/hr/` ) |\n`talent_screening` , `job_description_writer` , `hr_policy_qa` |\nFinance (`domain_packs/finance/` ) |\n`financial_memo` |\nLegal (`domain_packs/legal/` ) |\n`contract_reviewer` |\n\nEach pack gets typed `POST /packs/{pack_id}/run`\n\nand `/run/stream`\n\nwhen schemas are declared. Versioning, traffic weights, and sticky sessions: `GET /packs`\n\n, `GET /packs/{id}/versions`\n\n, headers `X-Pack-Version`\n\n/ `X-Pack-Version-Used`\n\n.\n\nFull catalogue and authoring guide: ** domain_packs/README.md**.\n\nThe HR, legal, and finance packs demonstrate the pack system on regulated-adjacent use cases, but they are **off by default** (`REGULATED_PACKS_ENABLED=false`\n\n) — calling them with a valid body returns HTTP `403`\n\nuntil you complete the pack's `COMPLIANCE.md`\n\nchecklist and explicitly opt in (a body that fails schema validation returns `422`\n\nfirst, as on any pack route).\n\nThird-party packs ship as regular Python packages declaring an entry point in\nthe `langgraph_agent_stack.packs`\n\ngroup:\n\n```\n[project.entry-points.\"langgraph_agent_stack.packs\"]\nsentiment = \"acme_packs.sentiment:SentimentPack\"\n```\n\nDiscovery is **opt-in and allowlisted** (`PACK_PLUGINS_ENABLED=true`\n\n+\n`PACK_PLUGINS_ALLOWLIST=sentiment`\n\n): loading a plugin executes third-party\ncode, so nothing loads by default. At load time each class is validated\nagainst the pack contract — `BaseDomainPack`\n\nsubclass, complete metadata, and\n**strict** (`extra=\"forbid\"`\n\n) input/output schemas — and a broken plugin is\nlogged and skipped, never crashing startup. Built-in pack ids cannot be\noverridden. Registered plugins get the same typed `/packs/{id}/run`\n\nroutes,\nversioning, and canary weights as built-ins. Packaging walkthrough:\n[examples/custom_pack/README.md](/Brescou/langgraph-agent-stack/blob/main/examples/custom_pack/README.md).\n\n| Method | Path | Description |\n|---|---|---|\n`GET` |\n`/packs` |\nList registered packs and metadata |\n`POST` |\n`/packs/{pack_id}/run` |\nRun a pack (typed body per pack schema) |\n`POST` |\n`/packs/{pack_id}/run/stream` |\nSSE stream for a pack |\n`POST` |\n`/run` , `/run/stream` |\nLegacy routes → `DEFAULT_PACK_ID` (`research_analysis` ) |\n`POST` |\n`/research` |\nResearch phase only |\n`GET` |\n`/health` , `/ready` |\nProbes |\n`GET` |\n`/sessions/{id}/history` |\nSession run history |\n`GET` |\n`/metrics` |\nPrometheus (with `observability` extra) |\n\nResponses include `cost_usd`\n\nwhen cost tracking is active; HTTP **402** on budget exceed. See `/docs`\n\nfor request/response schemas.\n\nOpt-in streamable-HTTP MCP endpoint that auto-generates **one tool per registered domain pack** (same Pydantic schemas as `POST /packs/{id}/run`\n\n). Every tool call goes through the existing kernel (auth, rate limits, budgets → tool error mirroring HTTP 402, regulated-pack gating).\n\n```\nuv sync --extra mcp\n# .env\nMCP_SERVER_ENABLED=true\nLLM_PROVIDER=mock   # optional — CI / no API key\n```\n\nEndpoint: `http://localhost:8000/mcp`\n\n(mounted only when the flag is on). Regulated packs are omitted from the tool list while `REGULATED_PACKS_ENABLED=false`\n\n.\n\nWhen `API_KEY`\n\nis set, pass the same Bearer token the REST API expects — for example in Claude Desktop / a generic MCP client config:\n\n```\n{\n  \"mcpServers\": {\n    \"langgraph-agent-stack\": {\n      \"url\": \"http://localhost:8000/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\nInstall the matching client transport for streamable HTTP; stdio is not shipped in this release.\n\nSet `LLM_PROVIDER`\n\nand install the matching extra. Details and gateway overrides: `.env.example`\n\n.\n\n| Provider | Value | Extra | Key env vars |\n|---|---|---|---|\n| Anthropic | `anthropic` |\n`--extra anthropic` |\n`ANTHROPIC_API_KEY` |\n| OpenAI | `openai` |\n`--extra openai` |\n`OPENAI_API_KEY` |\n`google` |\n`--extra google` |\n`GOOGLE_API_KEY` |\n|\n| Bedrock | `bedrock` |\n`--extra bedrock` |\n`AWS_REGION` , `BEDROCK_MODEL` |\n| Azure OpenAI | `azure` |\n`--extra openai` |\n`AZURE_OPENAI_*` |\n| Ollama | `ollama` |\n`--extra ollama` |\n`OLLAMA_BASE_URL` |\n| Mock (CI/dev) | `mock` |\n(none) |\n— |\n\n**Docker Compose**\n\n```\ndocker compose -f infra/docker-compose.yml up\ndocker compose -f infra/docker-compose.yml --profile redis up   # Redis memory backend\n```\n\n**Helm**\n\n```\nhelm install langgraph ./infra/helm/langgraph-agent-stack \\\n  -f infra/helm/langgraph-agent-stack/values.prod.yaml \\\n  --namespace langgraph-agents --create-namespace\n```\n\nProduction: set `secrets.existingSecret`\n\n(External Secrets Operator), `config.environment=production`\n\n, `networkPolicy.enabled=true`\n\n. Autoscaling defaults to **KEDA** on `active_pipelines`\n\n(not CPU). See chart `values.yaml`\n\n/ `values.prod.yaml`\n\n.\n\nScaling note.`MEMORY_BACKEND=sqlite`\n\n(default) is for development and single-replica deployments only — it's a local file, so state is not shared across pods. For production, multi-replica deployments, switch to`MEMORY_BACKEND=redis`\n\nor`MEMORY_BACKEND=postgres`\n\nso checkpointing and session history are consistent across replicas.\n\n**Terraform** — entry points under `infra/terraform/{gke,eks,aks}/`\n\n(no shared root module). Configure a remote backend before production apply. GKE module expects [External Secrets Operator](/Brescou/langgraph-agent-stack/blob/main/docs/security.md#3-secret-management) installed before `ClusterSecretStore`\n\nresources.\n\n**Infra CI locally:** `make infra-check`\n\n(template Checkov profile). Before production hardening: `make infra-check-prod`\n\n([checklist](/Brescou/langgraph-agent-stack/blob/main/docs/security.md#before-going-to-production-checkov)).\n\nRate limiting (memory or Redis), request body cap, prompt-injection / SSRF input validation, security headers, optional `API_KEY`\n\nBearer auth, graceful shutdown drain. Full model, env vars, K8s hardening, and scanning pipeline: ** docs/security.md**.\n\n```\nmake help          # all targets\nmake check         # ruff + pyright (CI lint)\nmake test          # 800+ tests, mocked by default — no network, no API key required\nmake eval          # golden-dataset pack evaluations (deterministic)\nmake infra-check   # helm lint + kubeconform + checkov\n```\n\n| Symptom | Cause / fix |\n|---|---|\n`POST /run` returns 502 with `LLM provider 'anthropic' rejected the request credentials` |\nYour API key is missing or invalid. Set `ANTHROPIC_API_KEY` (or your provider's key) in `.env` , or set `LLM_PROVIDER=mock` to run without one. |\nResponses say `Mock insight 1: Key trend identified.` |\nYou are on `LLM_PROVIDER=mock` (deterministic canned output, $0). Set a real provider + key in `.env` . |\n`GET /metrics` returns 404 |\nPrometheus metrics need the observability extra: `uv sync --extra observability` . |\nRegulated pack (`talent_screening` , `contract_reviewer` , …) returns 403 |\nExpected: these packs are gated behind `REGULATED_PACKS_ENABLED=false` until you complete the pack's `COMPLIANCE.md` . A 422 means your request body doesn't match the pack's input schema — check `/docs` . |\n402 on `/run` or a pack route |\nThe per-run USD budget (`PACK_DEFAULT_BUDGET_USD` ) was exceeded. Raise it or unset it. |\n`/docs` is missing |\nInteractive docs are disabled when `ENVIRONMENT=production` . |\n| State/history lost across replicas | `MEMORY_BACKEND=sqlite` (default) is single-replica only — switch to `redis` or `postgres` for multi-replica deployments. |\n\nNot covered here? Check the pinned FAQ in [Discussions Q&A](https://github.com/brescou/langgraph-agent-stack/discussions/categories/q-a) before opening an issue.\n\n`evals/`\n\nruns golden datasets (`evals/datasets/<pack_id>.yaml`\n\n) through the\nreal pack code with scripted LLM responses — deterministic, no network. Each\ncase declares an input, the scripted responses, and checks\n(`required_fields`\n\n, `contains`\n\n, `min_length`\n\n, `numeric_range`\n\n, or\n`expect_error`\n\nfor guard rejections). Compare two registered versions of a\npack before shifting canary weights:\n\n```\nuv run python -m evals --pack summariser            # one pack\nuv run python -m evals --pack summariser --version 1.0 --compare 2.0\nuv run python -m evals --all --json                 # CI-friendly output\n```\n\nContributor workflow, pre-commit, and PR expectations: ** CONTRIBUTING.md**.\n\n**LangGraph patterns** (standalone scripts, not served by the API): [examples/README.md](/Brescou/langgraph-agent-stack/blob/main/examples/README.md).\n\n```\nlanggraph-agent-stack/\n├── api/                 # FastAPI (app.py, middleware, endpoints, router_factory)\n├── pack_kernel/         # Pack contract + PackRegistry\n├── domain_packs/        # research/, productivity/, hr/, finance/, legal/, common/\n├── agents/              # Reusable LangGraph agents\n├── connectors/          # Retrieval connector implementations\n├── control_plane/       # Pack policies\n├── core/                # Config, LLM, memory, security, cost, observability\n├── infra/               # Dockerfile, compose, helm/, terraform/\n├── examples/            # LangGraph pattern demos\n├── tests/\n├── docs/                # security.md, architecture.md, …\n└── scripts/             # infra-devsecops.sh, …\n```\n\n| Doc | Contents |\n|---|---|\n|\n\n[domain_packs/README.md](/Brescou/langgraph-agent-stack/blob/main/domain_packs/README.md)[connectors/README.md](/Brescou/langgraph-agent-stack/blob/main/connectors/README.md)[control_plane/README.md](/Brescou/langgraph-agent-stack/blob/main/control_plane/README.md)[examples/README.md](/Brescou/langgraph-agent-stack/blob/main/examples/README.md)[CONTRIBUTING.md](/Brescou/langgraph-agent-stack/blob/main/CONTRIBUTING.md)[CHANGELOG.md](/Brescou/langgraph-agent-stack/blob/main/CHANGELOG.md)MIT © [brescou](https://github.com/brescou)", "url": "https://wpnews.pro/news/show-hn-production-grade-langgraph-template", "canonical_source": "https://github.com/brescou/langgraph-agent-stack", "published_at": "2026-07-15 13:42:41+00:00", "updated_at": "2026-07-15 13:47:55.340115+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-infrastructure", "ai-tools", "ai-startups"], "entities": ["LangGraph", "FastAPI", "Kubernetes", "Helm", "Terraform", "Prometheus", "Cosign", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/show-hn-production-grade-langgraph-template", "markdown": "https://wpnews.pro/news/show-hn-production-grade-langgraph-template.md", "text": "https://wpnews.pro/news/show-hn-production-grade-langgraph-template.txt", "jsonld": "https://wpnews.pro/news/show-hn-production-grade-langgraph-template.jsonld"}}