Skip to main content

langctl

Scaffold, run, and deploy production LangChain agents — frontend and agent in one command.

uv tool install langctl
langctl new my-agent
cd my-agent          # add your API key to .env
langctl dev

langctl dev starts the LangGraph Agent Server and your Next.js app, waits for the agent's health endpoint before booting the UI, proxies the agent behind the frontend's own origin, and tears both down cleanly on Ctrl-C. Like next dev, but the backend is an agent.

Long-term memory is on by default and needs nothing running.

Install

uv tool install langctl     # recommended — isolated environment, on PATH
pipx install langctl        # same idea
pip install langctl         # works, but shares your environment

Upgrade with uv tool upgrade langctl. If that reports no change when you expect one, it is uv's cached index: uv tool install --force --reinstall langctl.

Commands

Command What it does
langctl new Scaffold a project
langctl dev Run agent + frontend as one app
langctl add Add a feature to an existing project
langctl share Expose your local app on a public URL
langctl sync Regenerate derived files from agent.yaml
langctl doctor Check the environment before it bites

langctl new

langctl new my-agent                    # interactive
langctl new my-agent --yes              # all defaults
langctl new api-bot --yes --no-frontend
langctl new my-agent --yes --memory-backend postgres --semantic-search

--runtime · --model-provider · --model · --frontend/--no-frontend · --ui · --memory/--no-memory · --memory-backend · --semantic-search · --embeddings · --embedding-model · --yes · --no-install · --no-git

langctl dev

--backend-only · --frontend-only · --port · --backend-port · --no-open · --docker (runs langgraph up, port 8123) · --tunnel · --strict-port

langctl add

langctl add memory --backend postgres
langctl add frontend --ui minimal
langctl add tool "lookup order"

add regenerates the files langctl produced and skips the ones you edited, listing each. A file that still matches what the template last wrote is safe to update; anything else is yours. See Adding to an existing project.

langctl sync

Regenerates langgraph.json and pyproject.toml dependencies from agent.yaml. --check exits non-zero on drift, for CI. --force overwrites owned keys you edited.

langctl doctor

Toolchain, ports, API keys, Postgres reachability, and langgraph validate. Prints a fix for each failure.

Why the proxy

The browser only ever talks to /api/agent/... on the frontend's origin:

localhost:3000                      127.0.0.1:2024
┌────────────────────────┐          ┌──────────────────┐
│ Next.js                │          │ langgraph dev    │
│  /            chat UI  │          │  /threads /runs  │
│  /api/agent/* ─proxy───┼─────────▶│  /assistants /ok │
└────────────────────────┘          └──────────────────┘
        same origin ⇒ no CORS, ever

Three things fall out of this:

  • CORS never applies. There is no cross-origin request to preflight.
  • The API key stays on the server. The proxy runs in a route handler and attaches x-api-key there. Nothing secret reaches the browser.
  • Dev, tunnel, and production differ by one variable. AGENT_PROXY_TARGET points at localhost, then a container, then a deployed server. The frontend source never changes.

Chat UI

--ui What you get CSS
assistant-ui (default) assistant-ui runtime — threads, branching, composer — via npm, plus a converter you own Tailwind utilities
minimal one hand-written Chat.tsx, no UI dependencies Tailwind utilities
ai-elements (experimental) shadcn-registry components copied into web/components/ Tailwind @theme tokens

No template contains hand-written CSS: globals.css is @import "tailwindcss"; and nothing else. A test enforces it.

ai-elements currently fails npm run build. Its generated components pull streamdown, which resolves two incompatible copies of shiki; npm overrides do not dedupe them. Our own files typecheck clean. It is excluded from the wizard and reachable only via an explicit --ui ai-elements.

Memory

Long-term memory is on by default and needs nothing running. Verified against a real restart: without an explicit store, langgraph dev keeps memories in process and loses them all on exit.

backend when setup
sqlite (default) one machine, one process none
postgres more than one replica, or shared state set POSTGRES_URI

Semantic search is off by default — it needs an embeddings vendor and costs per item stored. Three ways to produce vectors:

--embeddings Trade-off
local sentence-transformers, no API key, no per-item cost, but pulls torch (GB)
provider hosted API, fastest to set up, needs a key
custom your own function

Two memories, opposite defaults, for a reason: overriding the store is a strict gain (it is otherwise lost on restart), while overriding the checkpointer loses adelete_for_runs, so threads stay server-managed unless you ask.

Adding to an existing project

Upgrading langctl does not touch projects you already created — templates are copied at creation, not linked. Use langctl add.

Projects from 0.1.x/0.2.x used single modules (tools.py, prompts.py) where 0.3+ uses packages (tools/, prompts/). After add, both exist and Python imports the package, so the old file is silently ignored. Move anything you wrote into the package and delete the module — editing it will have no effect.

Sharing and deploying

langctl share — shipped

Puts your locally running app on a public URL. One tunnel covers the whole thing, because the agent already sits behind the frontend's proxy — the agent port is never exposed and no API key leaves your machine.

langctl share                      # cloudflared if present, else ngrok
langctl share --provider ngrok
langctl share --backend-only       # expose the agent API instead (warns first)

cloudflared is preferred because its quick tunnels need no account. Nothing is hosted: close the laptop and the URL dies. Good for demos, client previews, webhook testing, and trying the app on a phone.

The URL is public and unauthenticated. Anyone with it can talk to your agent and spend your API credits.

langctl deploy — not built yet

The plan is both halves on one platform, with the frontend as the only public surface and the agent internal behind the proxy:

┌─ one host ────────────────────────────────────┐
│  web      Next.js        ← public             │
│   └ proxy → agent                             │
│  agent    Agent Server     internal only      │
│  postgres · redis          internal           │
└───────────────────────────────────────────────┘

Until then, deploying means langgraph deploy for the agent and setting AGENT_PROXY_TARGET + LANGSMITH_API_KEY on your frontend host.

Two constraints that shape the design, worth knowing now:

  • The Agent Server is licensed. Self-hosting it in production needs a LangSmith Enterprise licence key. The licence-free paths are langctl share, the JS embedded mode (agent inside Next.js route handlers, no Agent Server), and LangSmith Cloud.
  • A SQLite store on an ephemeral container filesystem loses every memory on restart, so deploy will have to switch long-term memory to Postgres or refuse.

Configuration

agent.yaml is the single source of truth; langgraph.json and the dependency list are generated from it. sync merges rather than overwrites, so hand-added keys and packages survive, and drift is reported instead of silently clobbered.

Development

uv venv && . .venv/bin/activate
uv pip install -e ".[dev]"
pytest
ruff check src tests

The suite spawns real child processes rather than mocking Popen: the failures that matter — orphaned grandchildren, ports left held, signals that never arrive — do not exist at the mock level.

Heavier checks need a scaffolded project:

export LANGCTL_E2E_PROJECT=/path/to/project
tests/e2e/dev_runtime.sh          # health gate, proxy, thread creation, teardown
tests/e2e/sse_streaming.sh        # asserts SSE arrives incrementally, not buffered
tests/e2e/memory_persistence.sh   # writes a memory, kills the process group, restarts
tests/e2e/share_tunnel.sh         # live tunnel: public URL, proxy, clean teardown

sse_streaming.sh measures arrival times: a buffering proxy passes every status-code assertion and still ruins the product. memory_persistence.sh kills by process group and requires the port to be released — an earlier version killed only the parent, left the uvicorn child serving, and reported a fake pass.

License

Apache-2.0. Generated projects carry no license obligation to this tool.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

langctl-0.7.0.tar.gz (114.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

langctl-0.7.0-py3-none-any.whl (93.6 kB view details)

Uploaded Python 3

File details

Details for the file langctl-0.7.0.tar.gz.

File metadata

  • Download URL: langctl-0.7.0.tar.gz
  • Upload date:
  • Size: 114.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for langctl-0.7.0.tar.gz
Algorithm Hash digest
SHA256 342b84c0c7636432310e9c80fd41cf65e185b2bccbbf94c89721f768b83ae50f
MD5 2948500a09dc9b321ed87ef4fe211e29
BLAKE2b-256 5878d1c8e631571ddd28da6294a4dc56101a21fba282c0befa2a0b01b265560d

See more details on using hashes here.

Provenance

The following attestation bundles were made for langctl-0.7.0.tar.gz:

Publisher: release.yml on Sami606713/agent_cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file langctl-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: langctl-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 93.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for langctl-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f02208c82c32729ac8f105a3c6ec8a2cf729186570294b0f18bb9160d09de734
MD5 949880e705ecbe10f77ffdbfcf8dd6e6
BLAKE2b-256 deab01363b3441a20f804f891fbe624def3c12ac5250b13d6ff4d1c258054205

See more details on using hashes here.

Provenance

The following attestation bundles were made for langctl-0.7.0-py3-none-any.whl:

Publisher: release.yml on Sami606713/agent_cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page