Summary
install.sh fails on a fresh clone because it invokes uv sync before building the frontend. pyproject.toml declares a force-include of frontend/dist, which is gitignored and therefore absent on a fresh checkout, so hatchling's editable build aborts.
Environment
- macOS 15 (Darwin 25.2.0)
- Python 3.12.12 (mise)
- Node v24.13.0, npm 11.6.2
- uv 0.9.28
- Fresh
git clone of main (commit 6366ca7)
Reproduction
git clone https://github.com/Detrol/quorum-cli.git
cd quorum-cli
chmod +x install.sh # required because the executable bit isn't preserved on some clones
./install.sh
Actual behavior
Environment checks pass, then Installing Python dependencies... fails:
× Failed to build `quorum-cli @ file:///.../quorum-cli`
├─▶ The build backend returned an error
╰─▶ Call to `hatchling.build.build_editable` failed (exit status: 1)
...
File ".../hatchling/builders/plugin/interface.py", line 239, in recurse_forced_files
raise FileNotFoundError(msg)
FileNotFoundError: Forced include not found:
/.../quorum-cli/frontend/dist
Expected behavior
./install.sh completes and produces a runnable installation, matching the README's "Manual installation" section.
Root cause
The script orders steps like this:
install.sh:86 — uv sync --quiet (triggers hatchling.build.build_editable for the local project)
install.sh:93–99 — cd frontend && npm install && npm run build (creates frontend/dist/)
But:
pyproject.toml:63–65 — [tool.hatch.build.targets.wheel.force-include] requires frontend/dist to exist at build time:
[tool.hatch.build.targets.wheel.force-include]
"frontend/dist" = "quorum/_frontend"
".env.example" = "quorum/.env.example"
.gitignore:48 excludes frontend/dist/, so a fresh clone never has it.
Hatchling's force-include is a hard requirement; it raises FileNotFoundError if the referenced path is missing. The PyPI install path is unaffected because the wheel is built upstream with frontend/dist already populated.
The README's "Manual installation" section lists the steps in the correct order (frontend build before Python install), so the intended sequence is clear — install.sh simply has them flipped.
What worked on my setup
Reordering install.sh so the frontend build runs before uv sync resolved this on my machine:
- # Install Python dependencies with uv
- echo "Installing Python dependencies..."
- uv sync --quiet
- echo -e "${GREEN}Done${NC}"
-
- echo
-
# Install and build frontend
echo "Installing frontend dependencies..."
cd frontend
npm install --silent
echo -e "${GREEN}Done${NC}"
echo "Building frontend..."
npm run build --silent
echo -e "${GREEN}Done${NC}"
cd ..
echo
+
+ # Install Python dependencies with uv
+ echo "Installing Python dependencies..."
+ uv sync --quiet
+ echo -e "${GREEN}Done${NC}"
+
+ echo
Workaround (without modifying the script)
cd frontend && npm install && npm run build && cd ..
uv sync
cp .env.example .env
Summary
install.shfails on a fresh clone because it invokesuv syncbefore building the frontend.pyproject.tomldeclares aforce-includeoffrontend/dist, which is gitignored and therefore absent on a fresh checkout, so hatchling's editable build aborts.Environment
git cloneofmain(commit6366ca7)Reproduction
Actual behavior
Environment checks pass, then
Installing Python dependencies...fails:Expected behavior
./install.shcompletes and produces a runnable installation, matching the README's "Manual installation" section.Root cause
The script orders steps like this:
install.sh:86—uv sync --quiet(triggershatchling.build.build_editablefor the local project)install.sh:93–99—cd frontend && npm install && npm run build(createsfrontend/dist/)But:
pyproject.toml:63–65—[tool.hatch.build.targets.wheel.force-include]requiresfrontend/distto exist at build time:.gitignore:48excludesfrontend/dist/, so a fresh clone never has it.Hatchling's
force-includeis a hard requirement; it raisesFileNotFoundErrorif the referenced path is missing. The PyPI install path is unaffected because the wheel is built upstream withfrontend/distalready populated.The README's "Manual installation" section lists the steps in the correct order (frontend build before Python install), so the intended sequence is clear —
install.shsimply has them flipped.What worked on my setup
Reordering
install.shso the frontend build runs beforeuv syncresolved this on my machine:Workaround (without modifying the script)