Skip to content

fix(docker): optimize image size — .dockerignore, drop dev deps, split build layers - #38749

Merged
benbarclay merged 2 commits into
NousResearch:mainfrom
thedavidweng:optimize/docker-image
Jun 10, 2026
Merged

fix(docker): optimize image size — .dockerignore, drop dev deps, split build layers#38749
benbarclay merged 2 commits into
NousResearch:mainfrom
thedavidweng:optimize/docker-image

Conversation

@thedavidweng

@thedavidweng thedavidweng commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

What

Three targeted changes to shrink the Docker image and speed up rebuilds:

1. .dockerignore — exclude ~69 MB of non-runtime content

The existing .dockerignore already excluded node_modules and .git (~1.6 GB). This PR adds the remaining directories that are never needed inside the container:

Directory Size Why exclude
apps/ 17 MB Tauri desktop app source — never installed in Docker
tests/ 22 MB Test suite
website/ 26 MB Docusaurus docs site source
docs/ 252 KB Supplementary documentation
infographic/ 1.2 MB README banner assets
plugins/hermes-achievements/docs/ 2.8 MB Plugin-level docs
nix/ + flake.* 156 KB Nix packaging
plans/ + .plans/ 52 KB Design docs
packaging/ 16 KB Homebrew/AUR metadata
assets/, acp_registry/ 32 KB README assets, ACP manifest
Dotfiles 44 KB .env.example, .envrc, .hadolint.yaml, .mailmap, .gitattributes

Impact: ~69 MB less build context transferred to the Docker daemon, and ~69 MB less content surviving into the final image via COPY . ..

2. pyproject.toml — new [docker] extra (drops [dev])

[all] includes [dev], which pulls in debugpy, pytest, pytest-asyncio, pytest-timeout, ty, ruff, and setuptools — none needed in the published image. The new [docker] extra is [all] - [dev].

Impact: ~30–50 MB fewer Python packages in the image.

3. Dockerfile — use --extra docker + split COPY for layer caching

  • uv sync --extra alluv sync --extra docker
  • Frontend build (web/ + ui-tui/) now has its own COPY layer, cached independently from Python source changes. A Python-only commit no longer triggers a redundant web/TUI rebuild.

What is NOT included (future work)

The build-only apt packages (gcc, python3-dev, libffi-dev, libolm-dev) remain in the final image. Removing them requires a true multi-stage build (builder → runtime), which is a larger refactor because the runtime code uses Path(__file__).parent.parent to locate optional-mcps/ and .hermes_build_sha — the editable install and full source tree must survive into the runtime stage.

Estimated total impact

Metric Before After Reduction
Build context ~82 MB ~13 MB 84%
Image content (from COPY . .) includes apps/tests/website excluded ~69 MB
Python packages includes dev tools docker extra ~30–50 MB

…plit build layers

Three changes to reduce the Docker image size and speed up rebuilds:

1. .dockerignore — exclude ~69 MB of files that are never needed inside
   the container: apps/ (desktop Tauri source), tests/, website/
   (Docusaurus), docs/, infographic/, nix/, plans/, packaging/, and
   various dotfiles (.envrc, .hadolint.yaml, .mailmap, etc.).  The
   existing .dockerignore already covered node_modules and .git; these
   additions prevent the remaining non-runtime content from inflating
   both the build context and the final image (COPY . .).

2. pyproject.toml — add a [docker] extra that mirrors [all] but omits
   [dev] (debugpy, pytest, pytest-asyncio, pytest-timeout, ty, ruff,
   setuptools).  The published image doesn't need test/debug tooling.
   Estimated savings: ~30-50 MB of Python packages.

3. Dockerfile — use --extra docker instead of --extra all in the
   uv sync layer.  Also split the COPY + npm run build so that the
   web/ and ui-tui/ frontend builds are cached independently from
   Python source changes (COPY . .).  A Python-only commit no longer
   invalidates the (slower) frontend build layer.

Note: the build-only apt packages (gcc, python3-dev, libffi-dev,
libolm-dev) are still installed in the final image.  Removing them
requires a true multi-stage build (builder → runtime), which is a
larger refactor tracked separately.
@thedavidweng
thedavidweng requested a review from a team June 4, 2026 05:28
@alt-glitch alt-glitch added type/refactor Code restructuring, no behavior change P3 Low — cosmetic, nice to have area/docker Docker image, Compose, packaging labels Jun 4, 2026

@austinpickett austinpickett left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hermes Agent Review — 🔴 Request Changes (the new [docker] extra is a no-op duplicate of [all]; the rest is good)

Two of the three changes are genuinely useful. The new dependency extra, however, rests on a false premise.

✅ Keep

  • .dockerignore additions — excluding apps/, tests/, website/, docs/, nix/, packaging/, acp_registry/, etc. meaningfully shrinks the build context. Correct (none of those are read by the container runtime).
  • Frontend-build layer reordering — copying web/ + ui-tui/ and building them before COPY . . so Python-only source changes don't invalidate the slow web/ui-tui build layer is a real caching win. Good.

🔴 Blocking — the [docker] extra duplicates [all] verbatim

The PR's rationale is that [docker] is "[all] minus [dev]". But [all] on current origin/main does not contain [dev] — there was a deliberate 2026-05-12 policy change (documented in the [all] comment) that already restricts [all] to non-lazy-installable extras only. [all] today is exactly:

cron, cli, pty, mcp, homeassistant, sms, acp, google, web, youtube

…and your new [docker] extra is that same list, member-for-member. So uv sync --extra docker resolves to identical deps as --extra all — the Dockerfile swap changes nothing dependency-wise. What it does add is a second extra that must be kept in lockstep with [all] forever: the moment [all] gains a member, [docker] silently won't, and the image quietly loses a production dep. That's a maintenance/drift hazard for zero benefit.

Ask: drop the [docker] extra from pyproject.toml and revert the Dockerfile back to --extra all (keeping your other --extra anthropic/bedrock/azure-identity/hindsight args, which are unchanged). Keep the .dockerignore and layer-reordering changes — those are the real improvements and I'd approve them on their own.

(If the intent is to guarantee [dev] can never leak into the image, note [all] already excludes it; a regression guard test asserting devall would express that intent without a duplicate extra.)

Reviewed by Hermes Agent (diffed the new [docker] extra against [all] on origin/main — identical membership).

The [docker] extra was identical to [all] on main — the PR had added [dev]
to [all] then created [docker] as [all] minus [dev], a no-op round-trip.
Revert [all] to its original form and drop the [docker] extra.

Keep the .dockerignore additions and frontend build layer reordering.
@thedavidweng

Copy link
Copy Markdown
Contributor Author

@austinpickett Addressed your review — removed the redundant extra and reverted to . The extra now matches main exactly (no added). Kept the additions and frontend build layer reordering. Ready for re-review.

@benbarclay
benbarclay dismissed austinpickett’s stale review June 10, 2026 09:41

Requested change addressed: the author removed the redundant [docker] extra (commit dc5751f) and reverted to --extra all, exactly as this review asked. Verified against current origin/main — [all] already excludes [dev] (2026-05-12 policy), so the surviving changes are just the .dockerignore additions + frontend-build layer reorder, both of which this review explicitly approved. Built the image on amd64 + arm64 (qemu): clean build, dashboard/TUI assets ship, gateway imports, pytest/ruff correctly absent. Dismissing the stale block.

@benbarclay
benbarclay enabled auto-merge (squash) June 10, 2026 09:44
@kshitijk4poor
kshitijk4poor self-requested a review June 10, 2026 10:07
@benbarclay
benbarclay merged commit a72bb03 into NousResearch:main Jun 10, 2026
28 checks passed
changman pushed a commit to changman/hermes-agent that referenced this pull request Jun 10, 2026
…t build layers (NousResearch#38749)

* fix(docker): optimize image size with .dockerignore, drop dev deps, split build layers

Three changes to reduce the Docker image size and speed up rebuilds:

1. .dockerignore — exclude ~69 MB of files that are never needed inside
   the container: apps/ (desktop Tauri source), tests/, website/
   (Docusaurus), docs/, infographic/, nix/, plans/, packaging/, and
   various dotfiles (.envrc, .hadolint.yaml, .mailmap, etc.).  The
   existing .dockerignore already covered node_modules and .git; these
   additions prevent the remaining non-runtime content from inflating
   both the build context and the final image (COPY . .).

2. pyproject.toml — add a [docker] extra that mirrors [all] but omits
   [dev] (debugpy, pytest, pytest-asyncio, pytest-timeout, ty, ruff,
   setuptools).  The published image doesn't need test/debug tooling.
   Estimated savings: ~30-50 MB of Python packages.

3. Dockerfile — use --extra docker instead of --extra all in the
   uv sync layer.  Also split the COPY + npm run build so that the
   web/ and ui-tui/ frontend builds are cached independently from
   Python source changes (COPY . .).  A Python-only commit no longer
   invalidates the (slower) frontend build layer.

Note: the build-only apt packages (gcc, python3-dev, libffi-dev,
libolm-dev) are still installed in the final image.  Removing them
requires a true multi-stage build (builder → runtime), which is a
larger refactor tracked separately.

* fix(docker): remove redundant [docker] extra, revert to --extra all

The [docker] extra was identical to [all] on main — the PR had added [dev]
to [all] then created [docker] as [all] minus [dev], a no-op round-trip.
Revert [all] to its original form and drop the [docker] extra.

Keep the .dockerignore additions and frontend build layer reordering.
@thedavidweng
thedavidweng deleted the optimize/docker-image branch June 11, 2026 02:36
alt-glitch pushed a commit that referenced this pull request Jun 14, 2026
…t build layers (#38749)

* fix(docker): optimize image size with .dockerignore, drop dev deps, split build layers

Three changes to reduce the Docker image size and speed up rebuilds:

1. .dockerignore — exclude ~69 MB of files that are never needed inside
   the container: apps/ (desktop Tauri source), tests/, website/
   (Docusaurus), docs/, infographic/, nix/, plans/, packaging/, and
   various dotfiles (.envrc, .hadolint.yaml, .mailmap, etc.).  The
   existing .dockerignore already covered node_modules and .git; these
   additions prevent the remaining non-runtime content from inflating
   both the build context and the final image (COPY . .).

2. pyproject.toml — add a [docker] extra that mirrors [all] but omits
   [dev] (debugpy, pytest, pytest-asyncio, pytest-timeout, ty, ruff,
   setuptools).  The published image doesn't need test/debug tooling.
   Estimated savings: ~30-50 MB of Python packages.

3. Dockerfile — use --extra docker instead of --extra all in the
   uv sync layer.  Also split the COPY + npm run build so that the
   web/ and ui-tui/ frontend builds are cached independently from
   Python source changes (COPY . .).  A Python-only commit no longer
   invalidates the (slower) frontend build layer.

Note: the build-only apt packages (gcc, python3-dev, libffi-dev,
libolm-dev) are still installed in the final image.  Removing them
requires a true multi-stage build (builder → runtime), which is a
larger refactor tracked separately.

* fix(docker): remove redundant [docker] extra, revert to --extra all

The [docker] extra was identical to [all] on main — the PR had added [dev]
to [all] then created [docker] as [all] minus [dev], a no-op round-trip.
Revert [all] to its original form and drop the [docker] extra.

Keep the .dockerignore additions and frontend build layer reordering.
davidgut1982 pushed a commit to davidgut1982/hermes-agent that referenced this pull request Jun 17, 2026
…t build layers (NousResearch#38749)

* fix(docker): optimize image size with .dockerignore, drop dev deps, split build layers

Three changes to reduce the Docker image size and speed up rebuilds:

1. .dockerignore — exclude ~69 MB of files that are never needed inside
   the container: apps/ (desktop Tauri source), tests/, website/
   (Docusaurus), docs/, infographic/, nix/, plans/, packaging/, and
   various dotfiles (.envrc, .hadolint.yaml, .mailmap, etc.).  The
   existing .dockerignore already covered node_modules and .git; these
   additions prevent the remaining non-runtime content from inflating
   both the build context and the final image (COPY . .).

2. pyproject.toml — add a [docker] extra that mirrors [all] but omits
   [dev] (debugpy, pytest, pytest-asyncio, pytest-timeout, ty, ruff,
   setuptools).  The published image doesn't need test/debug tooling.
   Estimated savings: ~30-50 MB of Python packages.

3. Dockerfile — use --extra docker instead of --extra all in the
   uv sync layer.  Also split the COPY + npm run build so that the
   web/ and ui-tui/ frontend builds are cached independently from
   Python source changes (COPY . .).  A Python-only commit no longer
   invalidates the (slower) frontend build layer.

Note: the build-only apt packages (gcc, python3-dev, libffi-dev,
libolm-dev) are still installed in the final image.  Removing them
requires a true multi-stage build (builder → runtime), which is a
larger refactor tracked separately.

* fix(docker): remove redundant [docker] extra, revert to --extra all

The [docker] extra was identical to [all] on main — the PR had added [dev]
to [all] then created [docker] as [all] minus [dev], a no-op round-trip.
Revert [all] to its original form and drop the [docker] extra.

Keep the .dockerignore additions and frontend build layer reordering.
T02200059 pushed a commit to T02200059/hermes-agent that referenced this pull request Jun 18, 2026
…t build layers (NousResearch#38749)

* fix(docker): optimize image size with .dockerignore, drop dev deps, split build layers

Three changes to reduce the Docker image size and speed up rebuilds:

1. .dockerignore — exclude ~69 MB of files that are never needed inside
   the container: apps/ (desktop Tauri source), tests/, website/
   (Docusaurus), docs/, infographic/, nix/, plans/, packaging/, and
   various dotfiles (.envrc, .hadolint.yaml, .mailmap, etc.).  The
   existing .dockerignore already covered node_modules and .git; these
   additions prevent the remaining non-runtime content from inflating
   both the build context and the final image (COPY . .).

2. pyproject.toml — add a [docker] extra that mirrors [all] but omits
   [dev] (debugpy, pytest, pytest-asyncio, pytest-timeout, ty, ruff,
   setuptools).  The published image doesn't need test/debug tooling.
   Estimated savings: ~30-50 MB of Python packages.

3. Dockerfile — use --extra docker instead of --extra all in the
   uv sync layer.  Also split the COPY + npm run build so that the
   web/ and ui-tui/ frontend builds are cached independently from
   Python source changes (COPY . .).  A Python-only commit no longer
   invalidates the (slower) frontend build layer.

Note: the build-only apt packages (gcc, python3-dev, libffi-dev,
libolm-dev) are still installed in the final image.  Removing them
requires a true multi-stage build (builder → runtime), which is a
larger refactor tracked separately.

* fix(docker): remove redundant [docker] extra, revert to --extra all

The [docker] extra was identical to [all] on main — the PR had added [dev]
to [all] then created [docker] as [all] minus [dev], a no-op round-trip.
Revert [all] to its original form and drop the [docker] extra.

Keep the .dockerignore additions and frontend build layer reordering.
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
…t build layers (NousResearch#38749)

* fix(docker): optimize image size with .dockerignore, drop dev deps, split build layers

Three changes to reduce the Docker image size and speed up rebuilds:

1. .dockerignore — exclude ~69 MB of files that are never needed inside
   the container: apps/ (desktop Tauri source), tests/, website/
   (Docusaurus), docs/, infographic/, nix/, plans/, packaging/, and
   various dotfiles (.envrc, .hadolint.yaml, .mailmap, etc.).  The
   existing .dockerignore already covered node_modules and .git; these
   additions prevent the remaining non-runtime content from inflating
   both the build context and the final image (COPY . .).

2. pyproject.toml — add a [docker] extra that mirrors [all] but omits
   [dev] (debugpy, pytest, pytest-asyncio, pytest-timeout, ty, ruff,
   setuptools).  The published image doesn't need test/debug tooling.
   Estimated savings: ~30-50 MB of Python packages.

3. Dockerfile — use --extra docker instead of --extra all in the
   uv sync layer.  Also split the COPY + npm run build so that the
   web/ and ui-tui/ frontend builds are cached independently from
   Python source changes (COPY . .).  A Python-only commit no longer
   invalidates the (slower) frontend build layer.

Note: the build-only apt packages (gcc, python3-dev, libffi-dev,
libolm-dev) are still installed in the final image.  Removing them
requires a true multi-stage build (builder → runtime), which is a
larger refactor tracked separately.

* fix(docker): remove redundant [docker] extra, revert to --extra all

The [docker] extra was identical to [all] on main — the PR had added [dev]
to [all] then created [docker] as [all] minus [dev], a no-op round-trip.
Revert [all] to its original form and drop the [docker] extra.

Keep the .dockerignore additions and frontend build layer reordering.
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
…t build layers (NousResearch#38749)

* fix(docker): optimize image size with .dockerignore, drop dev deps, split build layers

Three changes to reduce the Docker image size and speed up rebuilds:

1. .dockerignore — exclude ~69 MB of files that are never needed inside
   the container: apps/ (desktop Tauri source), tests/, website/
   (Docusaurus), docs/, infographic/, nix/, plans/, packaging/, and
   various dotfiles (.envrc, .hadolint.yaml, .mailmap, etc.).  The
   existing .dockerignore already covered node_modules and .git; these
   additions prevent the remaining non-runtime content from inflating
   both the build context and the final image (COPY . .).

2. pyproject.toml — add a [docker] extra that mirrors [all] but omits
   [dev] (debugpy, pytest, pytest-asyncio, pytest-timeout, ty, ruff,
   setuptools).  The published image doesn't need test/debug tooling.
   Estimated savings: ~30-50 MB of Python packages.

3. Dockerfile — use --extra docker instead of --extra all in the
   uv sync layer.  Also split the COPY + npm run build so that the
   web/ and ui-tui/ frontend builds are cached independently from
   Python source changes (COPY . .).  A Python-only commit no longer
   invalidates the (slower) frontend build layer.

Note: the build-only apt packages (gcc, python3-dev, libffi-dev,
libolm-dev) are still installed in the final image.  Removing them
requires a true multi-stage build (builder → runtime), which is a
larger refactor tracked separately.

* fix(docker): remove redundant [docker] extra, revert to --extra all

The [docker] extra was identical to [all] on main — the PR had added [dev]
to [all] then created [docker] as [all] minus [dev], a no-op round-trip.
Revert [all] to its original form and drop the [docker] extra.

Keep the .dockerignore additions and frontend build layer reordering.
donbowman pushed a commit to donbowman/hermes-agent that referenced this pull request Jul 13, 2026
…t build layers (NousResearch#38749)

* fix(docker): optimize image size with .dockerignore, drop dev deps, split build layers

Three changes to reduce the Docker image size and speed up rebuilds:

1. .dockerignore — exclude ~69 MB of files that are never needed inside
   the container: apps/ (desktop Tauri source), tests/, website/
   (Docusaurus), docs/, infographic/, nix/, plans/, packaging/, and
   various dotfiles (.envrc, .hadolint.yaml, .mailmap, etc.).  The
   existing .dockerignore already covered node_modules and .git; these
   additions prevent the remaining non-runtime content from inflating
   both the build context and the final image (COPY . .).

2. pyproject.toml — add a [docker] extra that mirrors [all] but omits
   [dev] (debugpy, pytest, pytest-asyncio, pytest-timeout, ty, ruff,
   setuptools).  The published image doesn't need test/debug tooling.
   Estimated savings: ~30-50 MB of Python packages.

3. Dockerfile — use --extra docker instead of --extra all in the
   uv sync layer.  Also split the COPY + npm run build so that the
   web/ and ui-tui/ frontend builds are cached independently from
   Python source changes (COPY . .).  A Python-only commit no longer
   invalidates the (slower) frontend build layer.

Note: the build-only apt packages (gcc, python3-dev, libffi-dev,
libolm-dev) are still installed in the final image.  Removing them
requires a true multi-stage build (builder → runtime), which is a
larger refactor tracked separately.

* fix(docker): remove redundant [docker] extra, revert to --extra all

The [docker] extra was identical to [all] on main — the PR had added [dev]
to [all] then created [docker] as [all] minus [dev], a no-op round-trip.
Revert [all] to its original form and drop the [docker] extra.

Keep the .dockerignore additions and frontend build layer reordering.
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
…t build layers (NousResearch#38749)

* fix(docker): optimize image size with .dockerignore, drop dev deps, split build layers

Three changes to reduce the Docker image size and speed up rebuilds:

1. .dockerignore — exclude ~69 MB of files that are never needed inside
   the container: apps/ (desktop Tauri source), tests/, website/
   (Docusaurus), docs/, infographic/, nix/, plans/, packaging/, and
   various dotfiles (.envrc, .hadolint.yaml, .mailmap, etc.).  The
   existing .dockerignore already covered node_modules and .git; these
   additions prevent the remaining non-runtime content from inflating
   both the build context and the final image (COPY . .).

2. pyproject.toml — add a [docker] extra that mirrors [all] but omits
   [dev] (debugpy, pytest, pytest-asyncio, pytest-timeout, ty, ruff,
   setuptools).  The published image doesn't need test/debug tooling.
   Estimated savings: ~30-50 MB of Python packages.

3. Dockerfile — use --extra docker instead of --extra all in the
   uv sync layer.  Also split the COPY + npm run build so that the
   web/ and ui-tui/ frontend builds are cached independently from
   Python source changes (COPY . .).  A Python-only commit no longer
   invalidates the (slower) frontend build layer.

Note: the build-only apt packages (gcc, python3-dev, libffi-dev,
libolm-dev) are still installed in the final image.  Removing them
requires a true multi-stage build (builder → runtime), which is a
larger refactor tracked separately.

* fix(docker): remove redundant [docker] extra, revert to --extra all

The [docker] extra was identical to [all] on main — the PR had added [dev]
to [all] then created [docker] as [all] minus [dev], a no-op round-trip.
Revert [all] to its original form and drop the [docker] extra.

Keep the .dockerignore additions and frontend build layer reordering.
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
…t build layers (NousResearch#38749)

* fix(docker): optimize image size with .dockerignore, drop dev deps, split build layers

Three changes to reduce the Docker image size and speed up rebuilds:

1. .dockerignore — exclude ~69 MB of files that are never needed inside
   the container: apps/ (desktop Tauri source), tests/, website/
   (Docusaurus), docs/, infographic/, nix/, plans/, packaging/, and
   various dotfiles (.envrc, .hadolint.yaml, .mailmap, etc.).  The
   existing .dockerignore already covered node_modules and .git; these
   additions prevent the remaining non-runtime content from inflating
   both the build context and the final image (COPY . .).

2. pyproject.toml — add a [docker] extra that mirrors [all] but omits
   [dev] (debugpy, pytest, pytest-asyncio, pytest-timeout, ty, ruff,
   setuptools).  The published image doesn't need test/debug tooling.
   Estimated savings: ~30-50 MB of Python packages.

3. Dockerfile — use --extra docker instead of --extra all in the
   uv sync layer.  Also split the COPY + npm run build so that the
   web/ and ui-tui/ frontend builds are cached independently from
   Python source changes (COPY . .).  A Python-only commit no longer
   invalidates the (slower) frontend build layer.

Note: the build-only apt packages (gcc, python3-dev, libffi-dev,
libolm-dev) are still installed in the final image.  Removing them
requires a true multi-stage build (builder → runtime), which is a
larger refactor tracked separately.

* fix(docker): remove redundant [docker] extra, revert to --extra all

The [docker] extra was identical to [all] on main — the PR had added [dev]
to [all] then created [docker] as [all] minus [dev], a no-op round-trip.
Revert [all] to its original form and drop the [docker] extra.

Keep the .dockerignore additions and frontend build layer reordering.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docker Docker image, Compose, packaging P3 Low — cosmetic, nice to have type/refactor Code restructuring, no behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants