Built a Python CLI that runs a LangGraph agent + chat UI with one command — worth upstreaming?

Hi all — I’ve been building a CLI called langctl and I’d like a sanity check
on whether any of it is useful upstream, or whether I’ve rebuilt something that
already exists.

The gap I hit. create-agent-chat-app and the js-langsmith cookbook both
solve “run the agent and the UI together” — but only for JavaScript. With a
Python agent I was back to two terminals, copying http://localhost:2024 into
an env var, and hitting CORS. The cookbook’s pattern (concurrently + wait-on +
a same-origin proxy) is exactly right; there just wasn’t a Python equivalent.

What I built. langctl new scaffolds a LangGraph agent plus
agent-chat-ui (vendored, pinned commit). langctl dev starts the Agent Server,
waits for /ok, then starts Next.js pointed at a same-origin passthrough, and
tears both down on one Ctrl-C. langctl deploy puts both on one host.

Things I measured rather than assumed, in case any of it is useful data:

  • SSE genuinely streams through the passthrough — asserted on arrival timing,
    not just the final body. A buffering proxy passes every status-code check and
    still ruins the UX.
  • Long-term memory is lost on restart without an explicit store.path;
    proved with a real process-group kill and restart.
  • langgraph dev in a container: 162 MB resident, GET /ok → 200.

One concrete bug, which I’ll file separately if it’s news to you:
@langchain/langgraph-sdk builds requests with new URL(`${apiUrl}${path}`)
(client/base.js:119). That throws Invalid URL on a relative apiUrl like
/api — which is the natural value when using the Next.js passthrough, since
new URL("/api/threads") has no base. Present in 1.9.27–1.9.29. The health
check uses fetch(), which resolves relative paths fine, so the page loads and
only the first message fails.

My question: is a Python-side version of the proxy/dev pattern something
you’d want in the deployment cookbook or docs? Happy to contribute it in
whatever shape is most useful — or to hear that it’s already covered and I
missed it.