Copying a manifest for every discovered member reached for paths that
.dockerignore may have removed from the build context, so a workspace with an
ignored member outside the closure failed with 'failed to compute cache key'.
uv only needs the target's manifest and those of its workspace dependencies to
resolve --package, so the closure is sufficient. It is also the set whose
sources are already copied and already validated against the ignore spec.
`uv export --package <member>` resolves a member by reading that member's own
pyproject.toml. The export stage copied only the workspace root's
pyproject.toml and uv.lock, so the root named the member but nothing on disk
defined it, and every workspace-member build failed with:
error: The workspace does not have a member <name>
This is not hypothetical: uv-examples/monorepo fails this way, and the
integration job that builds it has been red.
Copy each member's manifest at its relative path alongside the lockfile. Only
the manifests, since member sources are copied later per member. Single-package
projects are unaffected, as they have no members beyond the root and emit no
extra COPY lines.
## Summary
Adds native uv workspace/lockfile support to the LangGraph CLI's Docker
build pipeline. Instead of listing dependencies manually, users can
point at their existing `uv.lock` and the CLI will:
1. Discover workspace packages and their dependency graph
2. Export locked requirements via `uv export --package <name> --frozen`
3. Copy only the necessary workspace closure into the container
4. Install packages in dependency order with `--no-deps` for
reproducibility
5. Rewrite all import paths (graphs, auth, encryption, etc.) to
container paths
### New config field: `source`
Rather than using `pip` or `uv pip`, we add a new `uv_lock` installer.
The previous installers should still remain unchanged.
To avoid ambiguity, we discriminate by "source" field and **do not
permit** other arbitrary "dependencies". In this mode, we will treat the
provided root (defaults to the current directory) as the source of
truth.
This also would natively support uv workspaces, so you can specify the
target package within a larger workspace.
**Simple single-package project:**
```json
{
"python_version": "3.11",
"graphs": {
"agent": "./agent.py:graph"
},
"source": {
"kind": "uv"
}
}
```
**Multi-package workspace with explicit package:**
```json
{
"python_version": "3.11",
"graphs": {
"agent": "../../apps/agent/src/agent/graph.py:graph"
},
"source": {
"kind": "uv",
"root": "../..",
"package": "agent"
}
}
```
**Traditional pip deployment (unchanged):**
```json
{
"python_version": "3.11",
"dependencies": ["langgraph", "my-package"],
"graphs": {
"agent": "./agent.py:graph"
}
}
```
Config validation enforces mutual exclusivity. you must use either
`dependencies` or `source`, not both.
---------
Co-authored-by: Will Fu-Hinthorn <will@langchain.dev>