This was written with the help of Claude code:
When using a uv workspace (multiple packages each with their own pyproject.toml under subdirectories), pycrucible --embed fails at runtime with:
error: Workspace member `/path/to/pycrucible_payload/src/my-package` is missing a `pyproject.toml`
Error: Custom { kind: Other, error: "uv run failed" }
Root cause:
The pyproject.toml for a uv workspace root declares [tool.uv.workspace] with members = ["src/pkg-a", "src/pkg-b", ...], each of which has its own pyproject.toml. pycrucible's flat archive format can only embed one file per basename, so the workspace member pyproject.toml files cannot be included. At runtime, uv reads the workspace config from the root pyproject.toml, tries to locate the member packages, and fails because their pyproject.toml files are absent from the bundle.
Workaround (for today):
Before calling pycrucible --embed, we use a Python script to strip the [tool.uv.workspace], [tool.uv.sources], and workspace package dependency entries from the root pyproject.toml, then restore it afterward. The workspace packages are located at runtime via PYTHONPATH set in pycrucible.toml:
cp -p pyproject.toml pyproject.toml.bundle_bak
trap 'mv -f pyproject.toml.bundle_bak pyproject.toml 2>/dev/null' EXIT
python3 <<'PYEOF'
import re
with open('pyproject.toml') as f:
content = f.read()
for pkg in ['pkg-a', 'pkg-b', 'pkg-c', 'pkg-d']:
content = re.sub('\n "' + pkg + '",', '', content)
content = re.sub(r'\n\[tool\.uv\.workspace\]\n.*?(?=\n\[)', '', content, flags=re.DOTALL)
content = re.sub(r'\n\[tool\.uv\.sources\]\n.*?(?=\n\[|\Z)', '', content, flags=re.DOTALL)
with open('pyproject.toml', 'w') as f:
f.write(content)
PYEOF
uv run pycrucible --embed . -o my-app
mv pyproject.toml.bundle_bak pyproject.toml
trap - EXIT
Suggested fix:
Ideally pycrucible would detect [tool.uv.workspace] in the root pyproject.toml and either:
- Automatically strip workspace-only sections before embedding (since the member pyproject.toml files can't be included anyway), or
- Embed each workspace member pyproject.toml under its full relative path (i.e. src/pkg-a/pyproject.toml) rather than flattening to pyproject.toml
Option 1 seems lower-risk and more immediately useful.
Environment:
This was written with the help of Claude code:
When using a uv workspace (multiple packages each with their own pyproject.toml under subdirectories), pycrucible --embed fails at runtime with:
Root cause:
The pyproject.toml for a uv workspace root declares [tool.uv.workspace] with members = ["src/pkg-a", "src/pkg-b", ...], each of which has its own pyproject.toml. pycrucible's flat archive format can only embed one file per basename, so the workspace member pyproject.toml files cannot be included. At runtime, uv reads the workspace config from the root pyproject.toml, tries to locate the member packages, and fails because their pyproject.toml files are absent from the bundle.
Workaround (for today):
Before calling pycrucible --embed, we use a Python script to strip the [tool.uv.workspace], [tool.uv.sources], and workspace package dependency entries from the root pyproject.toml, then restore it afterward. The workspace packages are located at runtime via PYTHONPATH set in pycrucible.toml:
Suggested fix:
Ideally pycrucible would detect [tool.uv.workspace] in the root pyproject.toml and either:
Option 1 seems lower-risk and more immediately useful.
Environment: