langctl
Scaffold, run, and deploy production LangChain agents — frontend and agent in one command.
langctl new my-agent # backend + chat UI, wired together
cd my-agent
langctl dev # one command, one URL, already talking to each other
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.
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-keythere. Nothing secret reaches the browser. - Dev and production differ by one variable.
AGENT_PROXY_TARGETunset means the local agent;langctl deploysets it to the deployed Agent Server URL. The frontend source does not change.
Commands
| Command | What it does |
|---|---|
langctl new [name] |
Scaffold backend (+ frontend), agent.yaml, langgraph.json, git init, install deps. |
langctl dev |
Run agent + frontend as one app. --backend-only, --frontend-only, --port, --backend-port, --docker, --tunnel, --no-open, --strict-port. |
langctl sync |
Regenerate langgraph.json from agent.yaml, preserving hand-written keys. --check for CI. |
langctl doctor |
Verify toolchain, ports, keys, and config before something fails mid-command. |
Configuration
agent.yaml is the single source of truth; langgraph.json is generated from it.
sync merges rather than overwrites, so hand-added keys (auth, checkpointer,
dockerfile_lines, …) survive, and drift in owned keys is reported instead of silently
clobbered.
Install
uv tool install -e . # editable: source edits take effect immediately
langctl --version
Install editable. A non-editable uv tool install . is cached by version, so
after changing the source uv tool install --force . reports Audited … and keeps
running the old code — the version string has to change for the cache to miss. If
you already hit that: uv tool install --force --reinstall -e .
When debugging which copy is running, call it by absolute path
(~/.local/bin/langctl): an activated project venv shadows the global binary.
Development
uv venv && . .venv/bin/activate
uv pip install -e ".[dev]"
pytest # unit + process-level integration
ruff check src tests
The suite spawns real child processes rather than mocking Popen: the failures
that matter here — orphaned grandchildren, ports left held, signals that never arrive —
do not exist at the mock level. See tests/test_supervisor.py and tests/test_signals.py.
Two heavier checks need a scaffolded project with dependencies installed:
export LANGCTL_E2E_PROJECT=/path/to/scaffolded/project
tests/e2e/dev_runtime.sh # health gate, proxy, thread creation, clean teardown
tests/e2e/sse_streaming.sh # asserts SSE arrives incrementally, not buffered
sse_streaming.sh measures arrival times, not just the final body — a buffering proxy
passes every status-code assertion and still ruins the product.
Status
Phase 1 (scaffold + unified dev runtime) works end to end. Deploy providers
(langsmith_cloud, vercel) are next — see plan/.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file langctl-0.1.0.tar.gz.
File metadata
- Download URL: langctl-0.1.0.tar.gz
- Upload date:
- Size: 58.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e456117f1fd870a30c6566c8ed1f992f40127f2504b82c9e0267a0794878edf3
|
|
| MD5 |
c57495950d034aa6d0de359c988431fb
|
|
| BLAKE2b-256 |
b4bb3e9e82f2378375cc87f55e2267b3bb89852d00354885e11bda7981212ed1
|
Provenance
The following attestation bundles were made for langctl-0.1.0.tar.gz:
Publisher:
release.yml on Sami606713/agent_cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langctl-0.1.0.tar.gz -
Subject digest:
e456117f1fd870a30c6566c8ed1f992f40127f2504b82c9e0267a0794878edf3 - Sigstore transparency entry: 2411561635
- Sigstore integration time:
-
Permalink:
Sami606713/agent_cli@b62f19dfbbe26d94bdcd7ab57b032bd51d0329bb -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Sami606713
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b62f19dfbbe26d94bdcd7ab57b032bd51d0329bb -
Trigger Event:
push
-
Statement type:
File details
Details for the file langctl-0.1.0-py3-none-any.whl.
File metadata
- Download URL: langctl-0.1.0-py3-none-any.whl
- Upload date:
- Size: 46.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee304deb6d9265b0770c88a40bdcac65c6f91034a8f6792834c81b2ebbc1e3eb
|
|
| MD5 |
a8e086f365e4143b4217ab2235fd9a50
|
|
| BLAKE2b-256 |
d938f6dbcb804493a3f92ab481e2d0d4618b1ade8f5313a133932c745a272732
|
Provenance
The following attestation bundles were made for langctl-0.1.0-py3-none-any.whl:
Publisher:
release.yml on Sami606713/agent_cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langctl-0.1.0-py3-none-any.whl -
Subject digest:
ee304deb6d9265b0770c88a40bdcac65c6f91034a8f6792834c81b2ebbc1e3eb - Sigstore transparency entry: 2411561696
- Sigstore integration time:
-
Permalink:
Sami606713/agent_cli@b62f19dfbbe26d94bdcd7ab57b032bd51d0329bb -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Sami606713
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b62f19dfbbe26d94bdcd7ab57b032bd51d0329bb -
Trigger Event:
push
-
Statement type: