Self-hostable · Open source
LangGraph App
Streaming chat backed by a LangGraph StateGraph. A second graph quietly runs memory summarization, observability capture, and thread housekeeping after every turn. Ship the whole thing on a single VPS.
Everything the chat needs, nothing it doesn't.
The project ships the parts of an LLM product that you would otherwise rebuild every time. Each is small, observable, and swappable.
Chat anything
Ask the model about anything — web lookups, code reviews, prices, weather, even trade approvals. Tokens reach the chat live, the moment the model emits. Markdown, code blocks, and tool-call UI render inline on the same wire. A click stops the reply mid-flight — the SDK cancels, nothing half-written persists.
Memory + Knowledge Base
User facts surface in the system block; PDFs, images, plain text, markdown, and Office Open XML (DOCX / XLSX / PPTX) — plus pasted URLs fetched server-side — all go through a per-doc pipeline (OCR or structured parse → chunk → embed → entity) and become a hybrid-searchable index. Both are reviewable and deletable from settings.
Dual-graph agent
Chat handles the turn; a second graph runs memory, summarization, and observability capture behind the scenes.
Observability waterfall
Every span, every tool — one tree. Redacted at write, indexed by turn, viewable alongside the reply.
Evaluation & A/B
Per-agent rubrics, benchmark datasets, and an LLM-as-a-Judge that scores every run. Online executions surface judge work; benchmarks replay one prompt through any agent.
Human in the loop
LangGraph's interrupt() pauses the run for the user — locations, wallets, trade confirmations.
Self-host first
One docker-compose, one Postgres, one repo. No SaaS, no per-seat pricing, no tracking pixels.
How it works
Each piece of the system has a scroll-driven explainer below. They run on real code paths in the project — the same shapes, same state, same animation choices.
Streaming
Tokens appear the moment the model emits them.
Multi-graph
Two graphs, one turn. The chat hands off, the background finishes.
Memory
The model sees what you told it. Across threads.
system
Memory
- · User prefers TypeScript over JavaScript
- · Working on a self-hosted LangGraph chat project
- · Time zone: UTC+8
threads
Recent threads
- · Today · LangGraph checkpoint migration
- · Yesterday · Drizzle + Better Auth setup
- · Last week · Tailwind v4 theme tokens
user
What did I do with Tailwind last week?
Observability
Every span, every call, one waterfall.
Human in the loop
Some tools only run with your sign-off.
Client-side UI rendered while the graph pauses.
ask_locationShare your location so the agent can pull the forecast.
Tool execution paused — the graph resumes on click.
Knowledge base
Drop a file (or paste a URL), query the entity graph.
Seven source kinds plus pasted URLs land in one pipeline — PDF, images, plain text, markdown, and the three Office Open XML formats (DOCX, XLSX, PPTX). PDFs and images go through vision OCR; Office formats are parsed structurally by officeparser (one page per slide / sheet, with embedded images extracted to R2); text and markdown skip straight to chunking; pasted URLs are fetched server-side via Jina Reader and land as a markdown attachment. Every chunk is embedded and run through an entity-extraction pass — relationships, themes, and entity names all become structured columns the retrieval legs can score on.
Hybrid Search: three legs run in one round-trip — BM25 for the exact term, pgvector cosine for semantic closeness, and an entity-overlap leg that walks the graph from your query node. The three are fused with RRF (Reciprocal Rank Fusion).
[chunk 7 · vector + entity hit · 0.94] The BM25 leg finds the exact term; the entity leg ties it to the canonical name.
Evaluation
Score every run against the rubric — by hand or by AI Judge.
Online Executions: every chat turn, every KB ingest, every AI Judge scoring run shows up under its own agent card. Click a row for the per-turn waterfall; click the thumbs-up to stamp a 1–5 rating onto the same eval_run the model produced. The chat UI sends the assistant message id and the route resolves it against eval_run.parent_message_id — no match, silent no-op (the thumbs-up never crashes on a dangling row).
LLM-as-a-Judge: a separate evalAgent graph runs an LLM against the same span context the target agent saw and emits one structured score per rubric criterion plus a reasoning paragraph. The rubric lives in eval_rubric — seeded per agent (incl. judgeByLLM itself), editable in /admin/eval. Benchmarks replay one input through a target agent under the same harness; the judge scores the output and the result lands inline on the Benchmark Datasets table.
Self-host
One VPS. One Postgres. One repo.
The project ships as a single docker-compose on a single box. No SaaS, no per-seat pricing, no background services talking to a third party. Bring your own OpenAI-compatible endpoint and your own Postgres; the rest is in the repo.
- Next.js frontend (App Router, RSC, route groups)
- LangGraph dev server (`:2024`) with Postgres checkpointer
- Drizzle migrations + Better Auth email + OAuth
- OpenAI-compatible chat model — bring your own key
- Observability collector + retention cron
Paste this into your agent chat (Claude Code, Cursor, etc.). The agent reads the skill and walks you through the whole flow — anchors, cold start, daily CD, rollback, backup.
Please help me deploy LangGraph App by following the skill at https://github.com/FireTable/langgraph-app/blob/main/skills/langgraph-app-maintain.md.
Read the code. Run it. Skip the demo.
The repo is the documentation. README for the tour, docs/ for the design notes, the source for everything else. If something is unclear, open an issue — issues are answered in public.