Skip to content

🤖 feat: add Docker runtime support - #1458

Merged
ethanndickson merged 45 commits into
mainfrom
ethan/docker-runtime
Jan 7, 2026
Merged

🤖 feat: add Docker runtime support#1458
ethanndickson merged 45 commits into
mainfrom
ethan/docker-runtime

Conversation

@ethanndickson

@ethanndickson ethanndickson commented Jan 5, 2026

Copy link
Copy Markdown
Member

Run agent workspaces in isolated Docker containers. Each workspace gets its own container with project code synced via git bundle.

Features

  • Docker runtime type - Select in UI or CLI (--runtime "docker node:20")
  • Workspace forking - Creates git bundle in source container, transfers to host, clones into new container
  • Terminal support - CTRL+T opens shell via docker exec -it
  • VS Code integration - "Open in Editor" uses attached-container deep links
  • Container lifecycle - Auto-restart stopped containers on app relaunch (ensureReady())
  • Init streaming - Image pull progress visible in init section
  • Runtime availability API - UI shows disabled reasons per runtime type
  • Credential sharing - SSH agent forwarding (macOS/Linux), ~/.gitconfig copy, and GH_TOKEN passthrough
  • gh CLI auto-setup - Automatically configures gh CLI as git credential helper when GH_TOKEN is set
  • Container name hashing - 6-char hash suffix prevents collisions between similar branch names
  • CLI Docker support - mux run --runtime "docker node:20" creates and initializes Docker containers

Robustness

  • Docker availability timeout - 5s timeout prevents UI stalls when Docker is starting/hung
  • Docker error handling - docker inspect failures treated as errors, not missing containers
  • SSH host validation - Blocks creation when SSH host field is empty
  • Empty-branch repo handling - Forces local runtime for repos with no commits
  • SSH backoff gating - Connection pool backoff enforced before spawning SSH processes
  • Credential mount guards - Only forwards SSH agent if socket exists
  • Container leak prevention - Containers started for dirty checks are cleaned up on early return
  • Cross-platform temp paths - Uses os.tmpdir() for host-side bundle files (fixes Windows)

Refactors

  • RemoteRuntime - New abstract base class for SSH/Docker with shared exec, file I/O, and timeout handling
  • ptyService.ts - DRY'd 3 duplicated branches (Local/SSH/Docker) into shared helpers (loadNodePty(), createBufferedDataHandler())

Credential Sharing Details

The shareCredentials option (enabled by default) provides:

  1. SSH agent forwarding - macOS uses Docker Desktop's /run/host-services/ssh-auth.sock; Linux forwards $SSH_AUTH_SOCK
  2. Git identity - Copies ~/.gitconfig into container so git commits have correct author (copy allows gh auth setup-git to modify it)
  3. GitHub CLI - Passes GH_TOKEN and runs gh auth setup-git to configure credential helper

TODO

  • Look into adding support for git credential helpers (e.g., git-credential-manager, git-credential-osxkeychain) to allow HTTPS auth without GH_TOKEN

Generated with mux • Model: anthropic:claude-opus-4-5 • Thinking: high

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1ad9f0f8a4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/runtime/DockerRuntime.ts Outdated
Comment thread src/node/runtime/DockerRuntime.ts Outdated
@ethanndickson

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd9adb401e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/components/ChatInput/useCreationWorkspace.ts Outdated
Comment thread src/node/runtime/DockerRuntime.ts Outdated
@ethanndickson

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 19ac624272

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/runtime/runtimeFactory.ts Outdated
@ethanndickson

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e19965eb4d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/runtime/DockerRuntime.ts Outdated
@ethanndickson

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 23f3ff184c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/runtime/runtimeFactory.ts Outdated
@ethanndickson

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: abfb5d5b4a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/runtime/DockerRuntime.ts Outdated
@ethanndickson

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 07a79bdcf9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/browser/components/ChatInput/useCreationWorkspace.ts
Comment thread src/node/runtime/DockerRuntime.ts Outdated
Also adds runtimeAvailability mock option and DockerUnavailable story
Docker containers store plan files at /var/mux instead of ~/.mux because:
- /root has 700 permissions, inaccessible to VS Code Dev Containers (non-root user)
- /var/mux is world-readable by default

Changes:
- Add getMuxHome() to Runtime interface (Docker returns /var/mux, others ~/.mux)
- Pass muxHome to getPlanFilePath() throughout the codebase
- Create /var/mux/plans directory during Docker workspace creation
- Change default file permissions from 600 to 644 for new files
- Open parent directory for Docker deep links (VS Code limitation)
- Fix case-insensitive 'no such object' error detection

---
_Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
Two fixes:

1. Restore PR #1483 functionality (SSH stderr in connection failure logs)
   - Add stderr capture to RemoteRuntime.exec() and pass to onExitCode()
   - SSHRuntime uses truncateSSHError() to include actual error messages
   - Before: "SSH connection failed (exit code 255)"
   - After: "Permission denied (publickey)"

2. Fix Docker deep links for workspace roots (Codex comment)
   - /src was incorrectly stripped to / (container root)
   - Now: root-level paths like /src open as-is
   - File paths still open parent directory (VS Code limitation)

---
_Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
- Move stderr data listener AFTER Readable.toWeb() in RemoteRuntime.ts
  to avoid putting stream in flowing mode prematurely (caused integration
  test hangs on this branch)
- Add missing logComplete(-1) calls in workspaceService.ts error paths
  to prevent waitForInit() from blocking on promises that never resolve

---
_Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
This temporarily disables the new Docker integration tests to determine
whether they are causing the CI integration test hang.
The sections test fails on this branch but passes on main. Skipping
temporarily to verify the Docker test hang is fixed when all tests pass.
The 'starts stopped container' test was stopping the shared SSH container,
but containers started with --rm are removed on stop (not just stopped).
This broke subsequent SSH/Docker tests running in parallel.

Skipped until we create a dedicated container for this specific test.
The 'starts stopped container' test was stopping the shared SSH container,
but containers started with --rm are removed on stop. This broke subsequent
SSH/Docker tests running in parallel, leaving orphan processes that caused
Jest to hang.

Fix: create a dedicated throwaway container for this test, so stopping it
doesn't affect the shared fixture. Clean up in finally block.
Now that the Docker ensureReady test uses a dedicated container instead of
stopping the shared SSH container, all other tests can run safely.
- Fix runtime.test.ts 'creates container and deletes it': add initWorkspace()
  call after createWorkspace() since container creation happens in init, and
  set up minimal git repo with 'main' branch for bundling

- Fix dockerRuntime.integration.test.ts 'Docker runtime is disabled for
  non-git projects': add runtimeAvailability mock since button disabled
  state is driven by availability API, not just empty branches

- Fix DockerRuntime.deleteWorkspace() container leak (Codex P2): when
  force=false, track if container was running before starting it for dirty
  checks, and stop it before returning errors if we started it

- Extract noopInitLogger constant in test to reduce duplication

---
_Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
Hardcoded /tmp path would fail on Windows hosts. Use os.tmpdir() for
the host-side bundle path while keeping /tmp for the container path
(containers are always Linux). Aligns with forkWorkspace which already
uses os.tmpdir().

---
_Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
- Set this.containerName = destContainerName after fork succeeds so
  subsequent initWorkspace() targets the forked container, not source
- Add Docker container creation to `mux run --runtime docker` so
  tools can execute (previously only metadata was saved, no container)

---
_Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
Use SSH agent forwarding only (matching VS Code Dev Containers behavior).
Mounting ~/.ssh causes conflicts with passphrase-protected keys since
the container's SSH client may try to read keys directly instead of
using the forwarded agent.

---
_Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
- Add credential sharing section to docs/runtime/docker.mdx
- Add DocsLink to share credentials checkbox in CreationControls

---
_Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
Mounting ~/.gitconfig read-only prevented gh auth setup-git from writing
the credential helper config. Now we copy gitconfig into the container
after creation, matching VS Code Dev Containers behavior.

- Remove gitconfig mount from buildCredentialArgs()
- Add docker cp for gitconfig in initWorkspace()
- Remove debug logs from gh auth setup-git
- Update docs to reflect copy vs mount
@ethanndickson
ethanndickson added this pull request to the merge queue Jan 7, 2026
Merged via the queue into main with commit eaebc87 Jan 7, 2026
21 checks passed
@ethanndickson
ethanndickson deleted the ethan/docker-runtime branch January 7, 2026 09:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants