Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ You need **Docker Desktop** (macOS / Windows) or **Docker Engine + Compose v2**
```bash
git clone https://github.com/Forgeweb-ai/Forgeweb.git
cd Forgeweb
echo "FORGE_DATA_ROOT_HOST=$(pwd)/forge-data" > .env # creates the required .env AND pins the host data path
docker compose up -d
```

That one `echo` does two required things. It **creates `.env`** — compose declares `env_file: .env`, so a fresh clone won't start without the file (`Failed to load .env: no such file`). And it **pins `FORGE_DATA_ROOT_HOST`** to the absolute host path of `forge-data`. You need the explicit path: forge-server passes it to the Docker daemon to bind-mount each project's workspace into its preview container, and the daemon resolves that path on the host. The compose fallback (`${PWD}/forge-data`) breaks under `sudo` — `sudo` strips `$PWD`, so it resolves to a blank prefix (`/forge-data`, which doesn't exist on the host) and preview containers hang in `Created`. Capturing `$(pwd)` at install time avoids that whether or not you use `sudo`.

Everything else has a safe default (`${VAR:-default}` throughout `docker-compose.yml`), so no other config is needed to boot. To customize secrets or domains later, see `.env.example` — but note it ships **production** domains (`app.forge.com`, `preview.forge.com`), so keep those out of a local `.env`.

Then open <http://app.forge.localhost> and sign up. First boot builds 4 images (~10 minutes on a clean machine); subsequent boots are seconds.

The stack self-bootstraps: compose creates the `forge-net` network, Postgres comes up healthy, `forge-server`'s entrypoint waits for it, runs `alembic upgrade head`, builds the per-project `forge-runner` image if missing, then starts uvicorn. The default model is opencode zen's free DeepSeek V4 Flash, so a fresh sign-up can chat immediately without any API keys.
Expand Down
9 changes: 8 additions & 1 deletion forge-ui/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# syntax=docker/dockerfile:1
# Forge UI — Vite/SolidJS chat interface.
# ==========================================
# Build context MUST be the repo root (not ./forge-ui), because forge-ui is a
Expand Down Expand Up @@ -65,7 +66,13 @@ RUN sed -i '/minimumReleaseAge/d' opencode/bunfig.toml || true
# proceed; if any of those packages are actually needed, the build step
# below will fail with a clear "Cannot find module" pointing at the real
# culprit instead of bun's misleading summary.
RUN cd opencode && bun install --no-save --linker=hoisted || true
#
# tmpfs cache mount: same fix as opencode/Dockerfile.forge — bun's patch-apply
# fails with `EINVAL` on filesystems it flags as "slow/network" (e.g. NAS
# volumes), so we give its install cache a RAM-backed tmpfs. Keeps the build
# filesystem-agnostic on any host.
RUN --mount=type=tmpfs,target=/root/.bun/install/cache \
cd opencode && bun install --no-save --linker=hoisted || true

# Verify what's present so the log gives us a clear before/after for the
# packages bun complained about.
Expand Down
21 changes: 16 additions & 5 deletions opencode/Dockerfile.forge
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# syntax=docker/dockerfile:1
# Forge build of the vendored opencode fork
# ===========================================
# Runs opencode from source under bun (the project's declared package
Expand Down Expand Up @@ -71,11 +72,21 @@ RUN sed -i '/minimumReleaseAge/d' bunfig.toml || true
# /opencode/packages/opencode/node_modules/X and ENOENTs. Isolated places
# deps at the per-workspace-member path the runtime actually uses.
#
# First pass with `|| true` populates bun's local cache despite the same
# "Failed to install N packages" cascade. Second pass is strict — if it
# still can't materialise the tree we fail the build with bun's own error.
RUN bun install --no-save || true
RUN bun install --no-save
# First pass populates bun's local cache despite the same "Failed to install
# N packages" cascade; the retry is strict — if it still can't materialise the
# tree we fail the build with bun's own error.
#
# tmpfs cache mount (filesystem-agnostic install): bun's install + patch-apply
# IO is sensitive to the underlying filesystem. On some Docker storage backends
# (notably Synology NAS volumes) bun prints "Slow filesystem detected … network
# drive" and then fails patch-apply with `EINVAL: Invalid argument (read())` on
# every patchedDependency. bun's own remediation is to put its install cache on
# a fast local folder — so we mount a RAM-backed tmpfs at the cache path for the
# install step. The build then runs identically on a laptop, a cloud VM, or a
# NAS with no host-side prep. Both passes share the one tmpfs RUN so the strict
# retry reuses the warmed cache. (Needs the documented build RAM headroom.)
RUN --mount=type=tmpfs,target=/root/.bun/install/cache \
bun install --no-save || bun install --no-save

# Bun's isolated linker doesn't fully materialise every transitive dep into
# per-workspace-member node_modules — registry deps often end up only at
Expand Down
Loading