Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
3b46344
Merge pull request #1056 from dimensionalOS/dev - Pre-Release v0.0.8:…
spomichter Jan 23, 2026
e4defcb
Merge pull request #1092 - v0.0.9 Release Patch: Git clone change to …
spomichter Jan 23, 2026
8e0f31a
Merge pull request #1336 from dimensionalOS/dev
spomichter Feb 21, 2026
593a7f3
Merge pull request #1340 from dimensionalOS/dev
spomichter Feb 21, 2026
758fbc4
add docker example
jeff-hykin Mar 5, 2026
4c9c27d
add docker module system
jeff-hykin Mar 5, 2026
a0e719d
fixup
jeff-hykin Mar 5, 2026
f559ff8
fix rerun imports
jeff-hykin Mar 5, 2026
13acbf5
fixup imports
jeff-hykin Mar 5, 2026
5ab56d5
fixup
jeff-hykin Mar 5, 2026
4fcd2bc
simplify stop logic
jeff-hykin Mar 5, 2026
057a373
simplify and explain
jeff-hykin Mar 5, 2026
0027258
parallel start of docker modules
jeff-hykin Mar 5, 2026
f685fc0
fix container name to be stable
jeff-hykin Mar 5, 2026
c8276e1
lazy import
jeff-hykin Mar 5, 2026
971d2f7
clean up
jeff-hykin Mar 5, 2026
0dd1dd1
Merge branch 'dev' into jeff/fix/docker3
jeff-hykin Mar 5, 2026
868e356
revert
jeff-hykin Mar 5, 2026
bea6f7a
cleanup
jeff-hykin Mar 5, 2026
16b2007
fixup deploy_parallel
jeff-hykin Mar 5, 2026
aa42ced
clean up reconnect logic
jeff-hykin Mar 5, 2026
6d07778
fixup
jeff-hykin Mar 5, 2026
d74173f
-
jeff-hykin Mar 5, 2026
d2aafee
fix deployment/coordinator timeline
jeff-hykin Mar 5, 2026
f6b4c57
fir enforcement of either dockerfile or image pull
jeff-hykin Mar 5, 2026
2c03652
fix reconnect system
jeff-hykin Mar 5, 2026
c225a9a
-
jeff-hykin Mar 5, 2026
4fd09b7
fix deploy_parallel
jeff-hykin Mar 5, 2026
b514747
better error
jeff-hykin Mar 5, 2026
cb18fd2
clean container name generation
jeff-hykin Mar 5, 2026
ff482c2
fixup typing for ModuleProxy
jeff-hykin Mar 5, 2026
1d22e60
misc
jeff-hykin Mar 5, 2026
8ecb905
testing fixup
jeff-hykin Mar 5, 2026
bf18c25
maintain order
jeff-hykin Mar 5, 2026
1bd1c95
refine
jeff-hykin Mar 6, 2026
90feac1
make pull out configurable
jeff-hykin Mar 6, 2026
e95fe97
have example show using normal config
jeff-hykin Mar 6, 2026
4f10e82
Add DockerWorkerManager
jeff-hykin Mar 6, 2026
8d6ef32
add proper cleanup handling if a module fails to deploy correctly
jeff-hykin Mar 6, 2026
951b1aa
mypy fixup
jeff-hykin Mar 6, 2026
55cc94c
-
jeff-hykin Mar 6, 2026
d2d761a
add docker_build_ssh and image rebuild check
jeff-hykin Mar 7, 2026
a41b9f1
simplify
jeff-hykin Mar 7, 2026
fadabd9
misc
jeff-hykin Mar 7, 2026
d6ec658
add docker_build_extra_args
jeff-hykin Mar 7, 2026
929229e
Merge branch 'dev' into jeff/fix/docker3
jeff-hykin Mar 7, 2026
87cdcc0
PR review fixes: better error messages, consistent API, restore insta…
jeff-hykin Mar 7, 2026
d7ef2db
fix pull problem
jeff-hykin Mar 7, 2026
7639f3d
fix reconnect edgecase and __getattr__ loop edgecase
jeff-hykin Mar 7, 2026
14e3d1e
change the ignore postfix
jeff-hykin Mar 7, 2026
7dc73b8
fix docker defaults, make deploy better
jeff-hykin Mar 8, 2026
0c29524
misc
jeff-hykin Mar 8, 2026
eb3d303
fix mypy
jeff-hykin Mar 9, 2026
614dde8
fix ExceptionGroup edgecase
jeff-hykin Mar 9, 2026
b19cd25
Merge branch 'dev' into jeff/fix/docker3
jeff-hykin Mar 9, 2026
2e895d0
Merge branch 'dev' of github.com:dimensionalOS/dimos into jeff/fix/do…
jeff-hykin Mar 11, 2026
8cf89e3
Merge pull request #1526 from dimensionalOS/dev
spomichter Mar 12, 2026
0071ccd
Merge pull request #1530 from dimensionalOS/dev
spomichter Mar 12, 2026
24c6c58
Merge pull request #1532 from dimensionalOS/dev
spomichter Mar 12, 2026
d6df62d
Merge pull request #1537 from dimensionalOS/dev
spomichter Mar 12, 2026
9b66c8e
Merge remote-tracking branch 'origin' into jeff/fix/docker3
jeff-hykin Mar 13, 2026
47ebf5e
chore: resolve conflicts with dev
jeff-hykin Mar 13, 2026
bf8b429
fix: update Docker deployment to use ModuleSpec format
jeff-hykin Mar 13, 2026
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
90 changes: 60 additions & 30 deletions dimos/core/docker_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from __future__ import annotations

import hashlib
import subprocess
from typing import TYPE_CHECKING

Expand All @@ -32,10 +33,11 @@

logger = setup_logger()

# Timeout for quick Docker commands
_BUILD_HASH_LABEL = "dimos.build.hash"

DOCKER_CMD_TIMEOUT = 20

# Sentinel value to detect already-converted Dockerfiles (UUID ensures uniqueness)
# the way of detecting already-converted Dockerfiles (UUID ensures uniqueness)
DIMOS_SENTINEL = "DIMOS-MODULE-CONVERSION-427593ae-c6e8-4cf1-9b2d-ee81a420a5dc"

# Footer appended to Dockerfiles for DimOS module conversion
Expand All @@ -53,28 +55,6 @@
"""


def _run(cmd: list[str], *, timeout: float | None = None) -> subprocess.CompletedProcess[str]:
"""Run a command and return the result."""
return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout, check=False)


def _run_streaming(cmd: list[str]) -> int:
"""Run command and stream output to terminal. Returns exit code."""
result = subprocess.run(cmd, text=True)
return result.returncode


def _docker_bin(cfg: DockerModuleConfig) -> str:
"""Get docker binary path."""
return cfg.docker_bin or "docker"


def _image_exists(docker_bin: str, image_name: str) -> bool:
"""Check if a Docker image exists locally."""
r = _run([docker_bin, "image", "inspect", image_name], timeout=DOCKER_CMD_TIMEOUT)
return r.returncode == 0


def _convert_dockerfile(dockerfile: Path) -> Path:
"""Append DimOS footer to Dockerfile. Returns path to converted file."""
content = dockerfile.read_text()
Expand All @@ -85,32 +65,82 @@ def _convert_dockerfile(dockerfile: Path) -> Path:

logger.info(f"Converting {dockerfile.name} to DimOS format")

converted = dockerfile.parent / f".{dockerfile.name}.dimos"
converted = dockerfile.parent / f".{dockerfile.name}.ignore"
converted.write_text(content.rstrip() + "\n" + DIMOS_FOOTER.lstrip("\n"))
return converted


def _compute_build_hash(cfg: DockerModuleConfig) -> str:
"""Hash Dockerfile contents and build args."""
assert cfg.docker_file is not None
digest = hashlib.sha256()
digest.update(cfg.docker_file.read_bytes())
for key, val in sorted(cfg.docker_build_args.items()):
digest.update(f"{key}={val}".encode())
for arg in cfg.docker_build_extra_args:
digest.update(arg.encode())
return digest.hexdigest()


def _get_image_build_hash(cfg: DockerModuleConfig) -> str | None:
"""Read the build hash label from an existing Docker image."""
r = subprocess.run(
[
cfg.docker_bin,
"image",
"inspect",
"-f",
'{{index .Config.Labels "' + _BUILD_HASH_LABEL + '"}}',
cfg.docker_image,
],
capture_output=True,
text=True,
timeout=DOCKER_CMD_TIMEOUT,
check=False,
)
if r.returncode != 0:
return None
value = r.stdout.strip()
# docker prints "<no value>" when the label is missing
return value if value and value != "<no value>" else None


def build_image(cfg: DockerModuleConfig) -> None:
"""Build Docker image using footer mode conversion."""
if cfg.docker_file is None:
raise ValueError("docker_file is required for building Docker images")

build_hash = _compute_build_hash(cfg)
dockerfile = _convert_dockerfile(cfg.docker_file)

context = cfg.docker_build_context or cfg.docker_file.parent
cmd = [_docker_bin(cfg), "build", "-t", cfg.docker_image, "-f", str(dockerfile)]
cmd = [cfg.docker_bin, "build", "-t", cfg.docker_image, "-f", str(dockerfile)]
cmd.extend(["--label", f"{_BUILD_HASH_LABEL}={build_hash}"])
for k, v in cfg.docker_build_args.items():
cmd.extend(["--build-arg", f"{k}={v}"])
cmd.extend(cfg.docker_build_extra_args)
cmd.append(str(context))

logger.info(f"Building Docker image: {cfg.docker_image}")
exit_code = _run_streaming(cmd)
if exit_code != 0:
raise RuntimeError(f"Docker build failed with exit code {exit_code}")
# Stream stdout to terminal so the user sees build progress, but capture
# stderr separately so we can include it in the error message on failure.
result = subprocess.run(cmd, text=True, stderr=subprocess.PIPE)
if result.returncode != 0:
raise RuntimeError(
f"Docker build failed with exit code {result.returncode}\nSTDERR:\n{result.stderr}"
)


def image_exists(cfg: DockerModuleConfig) -> bool:
"""Check if the configured Docker image exists locally."""
return _image_exists(_docker_bin(cfg), cfg.docker_image)
r = subprocess.run(
[cfg.docker_bin, "image", "inspect", cfg.docker_image],
capture_output=True,
text=True,
timeout=DOCKER_CMD_TIMEOUT,
check=False,
)
return r.returncode == 0


__all__ = [
Expand Down
Loading
Loading