'Support & document both DooD and DinD docker-isolation workflows (DooD = zero-copy/zero-disk image reuse for disk-constrained hosts)' - #1970
Conversation
Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: #1962
Resolve an explicit isolation mode (HIVE_MIND_DOCKER_ISOLATION_MODE), inferred from DIND_SKIP_DAEMON / DOCKER_HOST, defaulting to dind so existing deployments are unchanged. Verbose launch logging and the startup preflight adapt their wording per mode: DooD describes the host daemon and concrete-tag remediation and no longer false-warns about a nested daemon or host-image passthrough that does not exist in DooD. Add docs/DOCKER-ISOLATION.md (+ zh/hi/ru) covering the DinD-vs-DooD trade-off, both run recipes, the --group-add socket requirement, the concrete-tag requirement, and image-reuse verification; add a DinD-vs-DooD deploy subsection to docs/DOCKER.md (+ zh/hi/ru) and link both pages from the READMEs. Cover the new behavior with tests/test-issue-1962-dood-dind-isolation.mjs.
Working session summaryI'll await the notification from the monitor when the suite completes. This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost estimation:
📊 Context and tokens usage:Claude Opus 4.8: (3 sub-sessions)
Total: (43.9K new + 287.9K cache writes + 11.7M cache reads) input tokens, 116.9K output tokens, $11.847261 cost 🤖 Models used:
📎 Log file uploaded as Gist (6765KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
🔄 Auto-restart 1/5Detected uncommitted changes from previous run. Starting new session to review and commit or discard them. Uncommitted files: Auto-restart will stop after changes are committed or discarded, or after 4 more iterations. Please wait until working session will end and give your feedback. |
In DooD the isolated task runs on the HOST daemon, so the bot-home
credential mount sources (~/.config/gh, ~/.gitconfig, ~/.claude[.json],
~/.codex) don't exist on the host and Docker auto-creates them as empty
directories — breaking file mounts (.claude.json/.gitconfig 'directory
onto a file') and yielding an empty git identity ('fatal: empty ident
name'). Resolve the conventional ~/.x sources against
HIVE_MIND_HOST_CONFIG_DIR (host-side config root) in DooD so the host
daemon binds the real files, bypassing the bot-FS existence gate.
Add preflightDockerIsolationAuthMounts: detect DooD and warn, before the
first task, when sources are still bot-home paths and the host config dir
is unset — turning a raw Docker mount failure into an actionable message.
Wire it into telegram-bot startup preflights. Docs (en/zh/hi/ru) and tests
updated.
Working session summaryThe last background poller has finished. The work is complete and verified — no further action needed. Final state:
The issue #1962 solution (explicit DinD/DooD isolation modes plus the DooD credential-mount fix via This summary was automatically extracted from the AI working session output. |
🔄 Auto-restart 1/5 LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost estimation:
📊 Context and tokens usage:
Total: (4.2K new + 52.6K cache writes + 1.7M cache reads) input tokens, 11.4K output tokens, $1.693755 cost 🤖 Models used:
📎 Log file uploaded as Gist (7906KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
✅ Ready to mergeThis pull request is now ready to be merged:
Monitored by hive-mind with --auto-restart-until-mergeable flag |
|
|
🤖 AI Work Session Started Starting automated work session at 2026-06-22T08:12:31.957Z The PR has been converted to draft mode while work is in progress. This comment marks the beginning of an AI work session. Please wait for the session to finish, and provide your feedback. |
… trap (#1962) The isolated task only reads the git identity to commit, and ~/.gitconfig is the one credential that breaks as a writable single-file bind mount: git config --global (e.g. gh-setup-git-identity --repair) writes a temp file and rename()s it over the target, and a rename over a mountpoint fails with 'Device or resource busy' (git config exits 4). - getDockerIsolationAuthMounts now marks the git identity mounts (~/.gitconfig, ~/.config/git) read-only; buildDockerIsolationStartArgs emits the :ro suffix on those --volume specs. Writable credentials (gh/claude/codex) are unchanged. - Verbose launch diagnostics annotate read-only mounts with '(ro)'. - docs/DOCKER-ISOLATION.md (+ zh/hi/ru): new section on the .gitconfig write trap with write-then-copy and mounted-directory (GIT_CONFIG_GLOBAL) remedies, and the rule to never populate identity through the mount. - Tests: assert git-identity mounts are read-only and the :ro suffix reaches the --volume spec, while gh/claude stay writable (66 passing).
|
Thanks — addressed the Code: Docs (en/zh/hi/ru): new "The
It also explicitly warns that the path Tests: +7 assertions (66 passing) covering that the git-identity mounts are read-only, the |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $4.781401📊 Context and tokens usage:
Total: (16.1K new + 145.6K cache writes + 4.8M cache reads) input tokens, 41.0K output tokens, $4.781401 cost 🤖 Models used:
📎 Log file uploaded as Gist (2645KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
✅ Ready to mergeThis pull request is now ready to be merged:
Monitored by hive-mind with --auto-restart-until-mergeable flag |
Summary
Implements #1962: support and document both Docker isolation workflows — DinD (Docker-in-Docker, nested daemon, the existing behavior) and DooD (Docker-out-of-Docker, share the host daemon) — across the isolation runner, startup preflights, and docs (en/zh/hi/ru).
DooD lets disk-constrained hosts reuse the host's copy of the multi-GB isolation image with zero copy / zero pull / zero extra disk, where the DinD passthrough model would otherwise duplicate the image into a nested store.
What changed
Explicit isolation mode
HIVE_MIND_DOCKER_ISOLATION_MODE(dind/dood) and infers it from theDIND_SKIP_DAEMON/DOCKER_HOSTsignals, defaulting todindso existing deployments are unchanged.docker pull <exact tag>on the host, pinHIVE_MIND_DOCKER_ISOLATION_IMAGE_TAG) and no longer false-warn about a nested daemon or host-image passthrough that doesn't exist in DooD.DooD credential-mount fix (the host-daemon mount-source trap)
In DooD an isolated task runs on the host daemon, which resolves bind-mount sources against the host filesystem. The bot's home credential sources (
~/.config/gh,~/.gitconfig,~/.claude[.json],~/.codex) don't exist there, so Docker auto-creates each missing source as an empty directory, breaking the task two ways:.claude.json,.gitconfig) fail with "Are you trying to mount a directory onto a file?" — the task dies before it starts.fatal: empty ident name) because the mounted~/.gitconfigis an empty dir.Fix: in DooD, resolve the conventional
~/.xmount sources againstHIVE_MIND_HOST_CONFIG_DIR(the host-side config root) so the host daemon binds the real files. Because the bot can't stat host-daemon paths, relocated sources bypass the bot-FS existence gate and trust the operator's host layout. DinD is unchanged (it shares the bot filesystem, so the sources are already the real files).A new startup preflight
preflightDockerIsolationAuthMountsdetects DooD and warns — before the first task — when mount sources are still the bot's home paths andHIVE_MIND_HOST_CONFIG_DIRis unset, turning a raw mid-run Docker mount failure into an actionable message. It's wired intotelegram-bot.mjsalongside the existing image and git-identity preflights (best-effort; never throws).~/.gitconfigwrite trap — git identity mounted read-only (:ro)~/.gitconfigis the one credential that cannot be a writable single-file bind mount.git config --global(run bygh-setup-git-identity --repair, which the startup git-identity preflight invokes) writes a temp file andrename()s it over the target — and a rename over a mountpoint fails witherror: could not write config file …: Device or resource busy(git config exits 4). By contrast~/.claude.jsonis rewritten in place, so a single-file mount there is fine.Fix: the git identity (
~/.gitconfig,~/.config/git) is now mounted read-only (:ro) into each task —getDockerIsolationAuthMountsflags it andbuildDockerIsolationStartArgsemits the:rosuffix. The task only reads the identity to commit, so:romakes the contract explicit and turns any stray write-through-the-mount into an immediate, legible error. The writable credentials (gh/claude/codex) are unchanged; verbose diagnostics annotate read-only mounts with(ro).Docs
docs/DOCKER-ISOLATION.md(+ zh/hi/ru): the DinD-vs-DooD trade-off, both run recipes, the--group-add <host-docker-gid>socket requirement, the DooD credential-mount requirement (HIVE_MIND_HOST_CONFIG_DIR/ matching host paths), the~/.gitconfigwrite trap (write-then-copy or a mounted directory withGIT_CONFIG_GLOBAL; never populate the identity through the mounted file), the concrete-tag requirement, and how to verify image reuse.docs/DOCKER.md(+ zh/hi/ru): a DinD-vs-DooD deploy subsection recommending DooD where disk is tight.How to reproduce / verify
The trap reproduces by running the bot in DooD (
-v /var/run/docker.sock:/var/run/docker.sock -e DIND_SKIP_DAEMON=1) without exposing host config: the first--isolation dockertask fails with the "directory onto a file" mount error / empty git identity. WithHIVE_MIND_HOST_CONFIG_DIRset (or matching host symlinks), the host daemon binds the real files and the task runs.Tests
tests/test-issue-1962-dood-dind-isolation.mjs— 66 passing assertions covering:resolveDockerIsolationConfigSourceHome(DinD keeps bot home; DooD relocates only whenHIVE_MIND_HOST_CONFIG_DIRis set and non-blank);getDockerIsolationAuthMounts(DinD existence-gated; DooD relocation bypasses the gate, preserves per-tool scoping, keeps container targets);:roflag is set on~/.gitconfig/~/.config/gitand reaches the--volumespec, whilegh/claudestay writable;preflightDockerIsolationAuthMounts(silent in DinD, one actionable warning in unconfigured DooD, cleared once the host config dir is set).npm run lintis clean on the changed sources.Closes #1962.