Documentation
¶
Overview ¶
Package md manages isolated Docker development containers for AI coding agents.
It provides programmatic access to create, manage, and tear down containers with SSH access. Containers optionally receive a full git clone of one or more repositories; repo-less containers are also supported for general agent workloads.
Index ¶
- Constants
- Variables
- func FormatBytes(n int64) string
- func IsHomeRelativeHostPath(p string) bool
- func ResolveContainerPath(p string) string
- func ResolveHostPath(p, home string) string
- func ResolveMountTarget(hostPath, containerPath string) (string, error)
- type AgentPaths
- type CacheMount
- type Client
- func (c *Client) AgentMounts(paths ...AgentPaths) ([]Mount, error)
- func (c *Client) BuildImage(ctx context.Context, stdout, stderr io.Writer, platform Platform) (retErr error)
- func (c *Client) Close() error
- func (c *Client) Container(repos ...Repo) (*Container, error)
- func (c *Client) Get(ctx context.Context, name string) (*Container, error)
- func (c *Client) List(ctx context.Context) ([]*Container, error)
- func (c *Client) PruneImages(ctx context.Context, stdout, stderr io.Writer) ([]string, error)
- func (c *Client) Warmup(ctx context.Context, stdout, stderr io.Writer, opts *WarmupOpts) (bool, error)
- type Container
- func (c *Container) Connect(ctx context.Context, stdout, stderr io.Writer, opts *StartOpts) (*StartResult, error)
- func (c *Container) Diff(ctx context.Context, stdout, stderr io.Writer, repoIdx int, opts *DiffOpts) error
- func (c *Container) DiskUsage(ctx context.Context) (int64, error)
- func (c *Container) Fetch(ctx context.Context, stdout, stderr io.Writer, repoIdx int, opts *FetchOpts) ([]FetchedBranch, error)
- func (c *Container) Fork(ctx context.Context, stdout, stderr io.Writer, opts *ForkOpts) (_ *Container, retErr error)
- func (c *Container) Inspect(ctx context.Context) (*InspectInfo, error)
- func (c *Container) Launch(ctx context.Context, stdout, stderr io.Writer, opts *StartOpts) (retErr error)
- func (c *Container) Pull(ctx context.Context, stdout, stderr io.Writer, repoIdx int, opts *PullOpts) error
- func (c *Container) Purge(ctx context.Context, stdout, stderr io.Writer) error
- func (c *Container) Push(ctx context.Context, stdout, stderr io.Writer, repoIdx int) (string, error)
- func (c *Container) Revive(ctx context.Context, stdout, stderr io.Writer) error
- func (c *Container) SSHCommand(opts []string, cmd string) []string
- func (c *Container) Status(ctx context.Context) string
- func (c *Container) Stop(ctx context.Context) error
- func (c *Container) SudoPassword(ctx context.Context) (string, error)
- func (c *Container) SyncDefaultBranch(ctx context.Context, repoIdx int) error
- func (c *Container) TailscaleFQDN(ctx context.Context) string
- type DiffOpts
- type FetchOpts
- type FetchedBranch
- type ForkOpts
- type ForkRepo
- type Harness
- type InspectInfo
- type Mount
- type Platform
- type PullOpts
- type Repo
- type Runtime
- type StartOpts
- type StartResult
- type WarmupOpts
Examples ¶
Constants ¶
const DefaultBaseImage = "ghcr.io/caic-xyz/md-user"
DefaultBaseImage is the base image used when none is specified.
const DefaultMaxCPUs = -1
DefaultMaxCPUs selects an automatic CPU limit at container launch: leave two CPUs available to the runtime, allowing at least two CPUs when available. The runtime's CPU count may differ from the host's with Docker Desktop or a remote daemon. Zero still means no limit in StartOpts and ForkOpts.
Variables ¶
var ErrDiffFound = errors.New("differences found")
ErrDiffFound is returned by Container.Diff when its Git arguments request an exit status for differences and at least one difference is found.
var HarnessMounts = map[Harness]AgentPaths{ HarnessAmp: {Description: "Amp", HomePaths: []string{".amp"}, XDGConfigPaths: []string{"amp"}, LocalSharePaths: []string{"amp"}}, HarnessAndroid: {Description: "Android Studio", HomePaths: []string{".android"}}, HarnessAntigravity: {Description: "Antigravity", HomePaths: []string{".gemini"}}, HarnessClaude: {Description: "Claude Code", HomePaths: []string{".claude"}}, HarnessCodex: {Description: "Codex", HomePaths: []string{".codex"}}, HarnessGoose: {Description: "Goose", XDGConfigPaths: []string{"goose"}, LocalSharePaths: []string{"goose"}}, HarnessKilo: {Description: "Kilo Code", HomePaths: []string{".kilocode"}}, HarnessKimi: {Description: "Kimi", HomePaths: []string{".kimi"}}, HarnessOpencode: {Description: "OpenCode", XDGConfigPaths: []string{"opencode"}, LocalSharePaths: []string{"opencode"}, LocalStatePaths: []string{"opencode"}}, HarnessPi: {Description: "Pi", HomePaths: []string{".pi"}}, HarnessQwen: {Description: "Qwen Code", HomePaths: []string{".qwen"}}, }
HarnessMounts maps each known harness to its path configuration.
var WellKnownCaches = map[string][]CacheMount{ "android-keys": { {Name: "android-keys", Description: "Android debug keystore and ADB keys", HostPath: "~/.android", ContainerPath: "/home/user/.android", Shallow: true}, }, "bun": { {Name: "bun", Description: "Bun package manager", HostPath: "~/.bun/install/cache", ContainerPath: "/home/user/.bun/install/cache"}, }, "cargo": { {Name: "cargo-registry", Description: "Rust cargo registry and git", HostPath: "~/.cargo/registry", ContainerPath: "/home/user/.cargo/registry"}, {Name: "cargo-git", Description: "Rust cargo registry and git", HostPath: "~/.cargo/git", ContainerPath: "/home/user/.cargo/git"}, }, "go-mod": { {Name: "go-mod", Description: "Go module cache", HostPath: "~/go/pkg/mod", ContainerPath: "/home/user/go/pkg/mod"}, }, "gradle": { {Name: "gradle-caches", Description: "Gradle caches and wrapper", HostPath: "~/.gradle/caches", ContainerPath: "/home/user/.gradle/caches"}, {Name: "gradle-wrapper", Description: "Gradle caches and wrapper", HostPath: "~/.gradle/wrapper/dists", ContainerPath: "/home/user/.gradle/wrapper/dists"}, }, "maven": { {Name: "maven", Description: "Maven repository", HostPath: "~/.m2/repository", ContainerPath: "/home/user/.m2/repository"}, }, "npm": { {Name: "npm", Description: "npm cache", HostPath: "~/.npm", ContainerPath: "/home/user/.npm"}, }, "pip": { {Name: "pip", Description: "Python pip cache", HostPath: "~/.cache/pip", ContainerPath: "/home/user/.cache/pip"}, }, "pnpm": { {Name: "pnpm", Description: "pnpm store", HostPath: "~/.local/share/pnpm/store", ContainerPath: "/home/user/.local/share/pnpm/store"}, }, "uv": { {Name: "uv", Description: "UV Python package manager", HostPath: "~/.cache/uv", ContainerPath: "/home/user/.cache/uv"}, }, }
WellKnownCaches is the set of predefined build-tool caches, keyed by short name. Each name may expand to multiple [CacheMount]s (e.g. "cargo" covers both the registry index and git sources). HostPath values use "~/" as a prefix that Container.Launch resolves to the host user's home directory at runtime; ContainerPath values may use "~/" for the container user's home directory.
Functions ¶
func FormatBytes ¶ added in v0.9.0
FormatBytes formats n bytes as a human-readable string (e.g. "1.2 GB").
func IsHomeRelativeHostPath ¶ added in v0.17.1
IsHomeRelativeHostPath reports whether p is a path within the host user's home directory using md's supported home-relative syntax.
func ResolveContainerPath ¶ added in v0.13.5
ResolveContainerPath expands "~" or a leading "~/" to the container user's home directory; other paths are returned unchanged.
func ResolveHostPath ¶ added in v0.17.1
ResolveHostPath expands "~" or a leading "~/" (or "~\" on Windows) to home; other paths are returned unchanged.
func ResolveMountTarget ¶ added in v0.17.1
ResolveMountTarget validates a host-to-container mapping and returns its effective container path. An empty container path mirrors a home-relative host path. The returned path retains "~" notation so ResolveContainerPath can expand it against the container user's home directory later.
Types ¶
type AgentPaths ¶ added in v0.8.0
type AgentPaths struct {
// Description is a short human-readable label for the harness (e.g.
// "Claude Code"). Displayed in settings UI.
Description string
// ReadOnly mounts all paths in this group read-only.
ReadOnly bool
HomePaths []string
XDGConfigPaths []string
LocalStatePaths []string
}
AgentPaths groups the relative host directory paths for one or more agent harnesses. Paths under HomePaths are relative to $HOME, XDGConfigPaths to $XDG_CONFIG_HOME (~/.config), LocalSharePaths to $XDG_DATA_HOME (~/.local/share), and LocalStatePaths to $XDG_STATE_HOME (~/.local/state).
type CacheMount ¶
type CacheMount struct {
// Name identifies the cache in progress output and Docker build contexts.
// It must match [a-z0-9][a-z0-9-]*, e.g. "go-mod".
Name string
// Description is a short human-readable label for the cache group (e.g.
// "Go module cache"). Displayed in settings UI.
Description string
// HostPath is the absolute path on the host. "~" and "~/" resolve to the
// host user's home directory.
HostPath string
// ContainerPath is the path inside the container. "~" and "~/" resolve to
// the container user's home directory via [ResolveContainerPath]. When empty,
// it mirrors a home-relative HostPath via [ResolveMountTarget].
ContainerPath string
// ReadOnly copies the cache into the image as root-owned, non-writable files.
ReadOnly bool
// Shallow copies only top-level files from HostPath, ignoring
// subdirectories. Useful for directories like ~/.android where only a few
// files (debug.keystore, adbkey) are needed but subdirectories (avd/,
// cache/) are large and unwanted.
Shallow bool
}
CacheMount defines a host directory to copy into the specialized container image. Well-known caches are defined in WellKnownCaches; custom caches can be constructed directly.
type Client ¶
type Client struct {
// Paths.
Home string
XDGConfigHome string
XDGDataHome string
XDGStateHome string
// SSH key paths.
HostKeyPath string // ~/.config/md/ssh_host_ed25519_key (generated)
UserKeyPath string // ~/.ssh/md
// Runtime is the Docker or Podman runtime.
Runtime containers.Runtime
// Logger receives md package logs. It must be non-nil.
Logger *slog.Logger
// ControlMaster enables SSH ControlMaster connection multiplexing.
// When true, SSH connections are shared via a persistent socket,
// reducing connection overhead. Disabled by default because stale
// sockets can cause connectivity issues that are hard to diagnose.
ControlMaster bool
// Tokens.
GithubToken string // GitHub API token for Docker build secrets.
// TailscaleAPIKey is the Tailscale API key for auth key generation and device deletion.
//
// It is necessary to setup ephemeral nodes. The key must be rotated every 90 days.
//
// See https://tailscale.com/docs/reference/tailscale-api and
// https://tailscale.com/docs/features/ephemeral-nodes
TailscaleAPIKey string
// DigestCacheTTL controls how long remote image digest lookups are cached.
// When zero, caching is disabled and the registry is queried on every start.
DigestCacheTTL time.Duration
// contains filtered or unexported fields
}
Client holds global MD tool state (paths, image config, SSH keys).
func New ¶
New creates a Client with global MD tool config and initialises SSH infrastructure (keys, authorized_keys, config.d include).
When logger is nil, slog.Default() is used. When runtime is nil, Docker or Podman is auto-detected.
func (*Client) AgentMounts ¶ added in v0.14.0
func (c *Client) AgentMounts(paths ...AgentPaths) ([]Mount, error)
AgentMounts returns runtime mounts for the provided agent path groups.
It creates the host directories before returning them. The shared agent directories are always included; pass values from HarnessMounts to include harness-specific directories.
func (*Client) BuildImage ¶
func (c *Client) BuildImage(ctx context.Context, stdout, stderr io.Writer, platform Platform) (retErr error)
BuildImage builds the base Docker images locally for platform: first md-root-local, then md-user-local on top of it.
func (*Client) Container ¶
Container returns a Container handle for the given repos. It populates ContainerPath on each repo from GitRoot if not already set (repos is mutated in place). The first repo is the primary. When called with no repos, the container has no associated git repository and a random name is generated automatically. It doesn't start it, it is just a reference.
func (*Client) Get ¶ added in v0.13.0
Get returns a single Container by name, or an error if not found. Uses docker inspect for a targeted lookup.
func (*Client) PruneImages ¶ added in v0.9.0
PruneImages removes md-built images (specialized builds and fork snapshots) that are not used by any container. Returns the list of removed image names.
func (*Client) Warmup ¶ added in v0.9.0
func (c *Client) Warmup(ctx context.Context, stdout, stderr io.Writer, opts *WarmupOpts) (bool, error)
Warmup ensures the base image is pulled and a specialized image with current coding agents is built, without starting a container. Force rebuilds the image even when its inputs are unchanged. Returns true if a build ran.
type Container ¶
type Container struct {
// Client is the client that created this container.
*Client
// Logger receives logs for this container. It includes the cntr attribute.
Logger *slog.Logger
// Repos are the git repositories in this container. Repos[0] is the
// primary; the rest are pushed alongside it. Each repo's ContainerPath
// gives the absolute destination path.
// Label: md.repos (base64-encoded JSON)
Repos []Repo
// Name is the Docker container name (e.g. "md-myrepo-main").
Name string
// State is the Docker container state (e.g. "running", "exited").
State string
// CreatedAt is when the container was created.
CreatedAt time.Time
// Labels contains all Docker/Podman labels observed on the container.
Labels map[string]string
// Display indicates the container was started with X11/VNC enabled.
// Label: md.display
Display bool
// Tailscale indicates the container was started with Tailscale networking.
// Label: md.tailscale
Tailscale bool
// USB indicates the container was started with USB passthrough.
// Label: md.usb
USB bool
// Sudo indicates root access via sudo is enabled.
// Label: md.sudo
Sudo bool
// SSHPort is the host port mapped to the container's SSH port.
// Set by Launch; available immediately after Launch returns.
SSHPort int32
// VNCPort is the host port mapped to the container's VNC port, if display is enabled.
// Set by Launch; available immediately after Launch returns. Zero if display is disabled.
VNCPort int32
// contains filtered or unexported fields
}
Container holds state for a single container instance.
Fields marked with a label are persisted as Docker container labels and restored by [unmarshalContainer] when listing containers.
Example ¶
// Examples demonstrate using md as a library.
package main
import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"os/signal"
"strings"
"github.com/caic-xyz/md"
)
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
client, err := md.New(nil, nil, os.Stdout)
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
return
}
base, err := client.Container(md.Repo{GitRoot: ".", Branches: []string{"main"}})
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
return
}
run := &md.Container{
Client: base.Client,
Repos: append([]md.Repo(nil), base.Repos...),
Name: base.Name + "-run",
}
opts := &md.StartOpts{}
if err = run.Launch(ctx, os.Stdout, os.Stderr, opts); err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
return
}
if _, err = run.Connect(ctx, os.Stdout, os.Stderr, opts); err == nil {
sshArgs := run.SSHCommand(nil, "cd "+shellQuote(run.Repos[0].ContainerPath)+" && go test ./...")
cmd := exec.CommandContext(ctx, sshArgs[0], sshArgs[1:]...) //nolint:gosec // SSH target and command are built from md container state.
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
}
if err = errors.Join(err, run.Purge(ctx, os.Stdout, os.Stderr)); err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
return
}
}
func shellQuote(s string) string {
if s == "" {
return "''"
}
for _, c := range s {
if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') &&
c != '@' && c != '%' && c != '+' && c != '=' && c != ':' && c != ',' && c != '.' &&
c != '/' && c != '-' && c != '_' {
return "'" + strings.ReplaceAll(s, "'", `'\''`) + "'"
}
}
return s
}
Output:
func (*Container) Connect ¶ added in v0.9.0
func (c *Container) Connect(ctx context.Context, stdout, stderr io.Writer, opts *StartOpts) (*StartResult, error)
Connect waits for SSH, pushes repos into the container, and completes startup. Must be called after Launch. Container.Repos must have branches set before this call.
func (*Container) Diff ¶
func (c *Container) Diff(ctx context.Context, stdout, stderr io.Writer, repoIdx int, opts *DiffOpts) error
Diff writes the checked-out container branch's changes, including untracked files, after verifying every mapped branch still matches the host.
By default it reports the changes not yet integrated into the host branch, using the point established by container creation or the last successful Push, Pull or Fork. Set DiffOpts.Full to report the whole branch instead.
opts may be nil, which selects the default of the zero DiffOpts.
When stdout is a terminal, a TTY is allocated so git's pager and colors work.
func (*Container) DiskUsage ¶ added in v0.9.0
DiskUsage returns the writable container layer size in bytes via docker inspect --size. Works for both running and stopped containers.
func (*Container) Fetch ¶
func (c *Container) Fetch(ctx context.Context, stdout, stderr io.Writer, repoIdx int, opts *FetchOpts) ([]FetchedBranch, error)
Fetch fetches the mapped branches of Repos[repoIdx] from the container and updates the host's remote-tracking refs without integrating them. It returns the exact branch tips fetched and does not change the base reported by Container.Diff.
The zero FetchOpts fetches only what the container already committed, which leaves its history and working tree untouched. Set FetchOpts.Commit to commit the container's pending changes first, so the host receives them too.
opts may be nil, which selects the default of the zero FetchOpts.
func (*Container) Fork ¶ added in v0.12.0
func (c *Container) Fork(ctx context.Context, stdout, stderr io.Writer, opts *ForkOpts) (_ *Container, retErr error)
Fork snapshots a running or stopped container and creates a new one where each mapped repository is checked out on a new primary branch.
The snapshot preserves the container's entire filesystem (installed packages, build artifacts, etc.) while giving each repo a fresh primary branch that diverges from the source container's working state. Extra mapped branches keep their original names.
Branch naming: the caller supplies the full repo set via ForkOpts.Repos, each entry naming its DestPrimary. Fork uses those names verbatim and only rejects a name the repo already maps, which it would destroy. Allocating a free name and avoiding other containers' branches belongs to the caller, symmetric with Launch, where the caller owns branch names too.
If setup fails, Fork removes the partial container and restores or deletes destination host branches that still point to the commits written by this attempt. Branches moved concurrently are preserved and reported.
func (*Container) Inspect ¶ added in v0.14.2
func (c *Container) Inspect(ctx context.Context) (*InspectInfo, error)
Inspect returns detailed observed runtime configuration for the container.
func (*Container) Launch ¶ added in v0.9.0
func (c *Container) Launch(ctx context.Context, stdout, stderr io.Writer, opts *StartOpts) (retErr error)
Launch prepares the image and starts the Docker container. It does NOT wait for SSH to become ready — call Connect to complete startup once the container's repos have their branches set (e.g. after concurrent branch allocation).
func (*Container) Pull ¶
func (c *Container) Pull(ctx context.Context, stdout, stderr io.Writer, repoIdx int, opts *PullOpts) error
Pull fetches changes from the container and integrates all mapped branches into the local repository.
opts controls AI commit message generation. Pass nil to use a default message.
func (*Container) Purge ¶ added in v0.9.0
Purge stops and removes the container, cleaning up SSH config and git remotes.
func (*Container) Push ¶
func (c *Container) Push(ctx context.Context, stdout, stderr io.Writer, repoIdx int) (string, error)
Push force-pushes local state for Repos[repoIdx] into the container, saving a backup of the container state and returning the backup branch name. All branches in Branches are synced.
func (*Container) Revive ¶ added in v0.9.0
Revive restarts a stopped (exited) container. It restores missing local upstream branches from the preserved container, validates git remotes, runs `docker start`, re-queries the SSH port (which changes on restart), rewrites the SSH config, and waits for SSH to become ready. It does NOT reset working branches or send .env — the container's filesystem is preserved across stop/start.
func (*Container) SSHCommand ¶ added in v0.13.2
SSHCommand returns SSH command args for this container. opts are SSH flags (e.g. "-q", "-t"); cmd is the remote command. The container name is always included as the SSH host target. If cmd is empty, only the base SSH args and host are returned (for interactive sessions).
func (*Container) Status ¶ added in v0.13.3
Status returns the Docker container state (e.g. "running", "exited", ""). Returns empty string when the container does not exist.
func (*Container) Stop ¶ added in v0.9.0
Stop stops the container without removing it. The container can be restarted later with Revive. SSH config is preserved (Revive rewrites it with the new port), but the ControlMaster socket is removed to prevent stale connections from interfering with subsequent SSH commands.
func (*Container) SudoPassword ¶ added in v0.13.0
SudoPassword retrieves the random sudo password set at container startup, or "" if no password was configured.
For containers created by Launch, the password is cached in-memory. For containers loaded from List (e.g. md sudo-password), it falls back to reading the md.sudo-password Docker label.
func (*Container) SyncDefaultBranch ¶
SyncDefaultBranch mirrors the host's cached remote branches for Repos[repoIdx] into the container. The historical name is retained for API compatibility.
type DiffOpts ¶ added in v0.18.0
type DiffOpts struct {
// Args are extra arguments forwarded to git diff, for example "--stat".
Args []string
// Full reports the whole branch, from the merge base with its upstream,
// instead of only the work not yet integrated into the host branch.
Full bool
}
DiffOpts configures Container.Diff. Its zero value reports container work not yet integrated into the host branch.
type FetchOpts ¶ added in v0.18.0
type FetchOpts struct {
// Provider generates the commit message when Commit is set. A nil Provider
// uses a fixed message.
Provider genai.Provider
// ContextTokens is the selected model's context window. Zero uses the
// commit-message generator default.
ContextTokens int
// Commit stages and commits the container's pending changes before
// fetching, so the host receives them as well. Leave it unset to observe
// the container without changing its history or its working tree.
Commit bool
// NoVerify passes --no-verify to the container commit, skipping the
// pre-commit and commit-msg hooks. It has no effect unless Commit is set.
NoVerify bool
}
FetchOpts configures Container.Fetch. Its zero value fetches only what the container already committed.
type FetchedBranch ¶ added in v0.18.0
type FetchedBranch struct {
// BranchName is the short local branch name in the container, such as
// "main" or "caic-1".
BranchName string
// CommitHash is the full Git object ID of the fetched branch tip.
CommitHash string
}
FetchedBranch identifies an exact container branch tip observed by Container.Fetch.
type ForkOpts ¶ added in v0.12.0
type ForkOpts struct {
// Repos is the full set of repositories the fork should contain. It must
// include an entry for every repo in the source container (identified by
// GitRoot); additional entries are new repos initialized in the fork and
// pushed from the host. Fork fails if a source-container repo is missing, if
// GitRoots are duplicated, or if a DestPrimary is empty.
Repos []ForkRepo
// Display enables X11/VNC virtual display on the forked container.
Display bool
// Tailscale enables Tailscale networking on the forked container.
Tailscale bool
// USB enables USB device passthrough on the forked container.
USB bool
// Sudo enables root access via sudo on the forked container.
Sudo bool
// Labels are additional Docker labels (key=value) applied to the forked container.
Labels []string
// Quiet suppresses informational output.
Quiet bool
// ExtraEnv holds environment updates to inject into the container's ~/.env.
// Entries use KEY=VALUE to set a value or KEY= to remove one. Values are
// shell-quoted before writing, so they may contain spaces and newlines.
ExtraEnv []string
// Mounts lists host directories to bind-mount into the running container.
// Missing host directories are rejected before the runtime is invoked.
Mounts []Mount
// MaxCPUs limits the number of CPU cores the forked container may use.
// Passed as --cpus to docker/podman. Zero means no limit.
// Use [DefaultMaxCPUs] to calculate a default from the runtime CPU count.
MaxCPUs int
// ExtraRunArgs are additional arguments passed verbatim to the
// container runtime's "run" command. Not portable across runtimes.
ExtraRunArgs []string
}
ForkOpts configures a container fork operation.
type ForkRepo ¶ added in v0.17.0
type ForkRepo struct {
// GitRoot is the absolute path of the host git repository. Fork matches it
// against the source container's repos: a match is re-branched from the
// snapshot, a non-match is initialized in the fork and pushed from the host.
GitRoot string
// SourceBranches are the branches to carry, primary first. For a repo present
// in the source container it must equal the branches recorded on that repo
// (Fork validates this). For a new repo it is the host branches to push; if
// empty, it defaults to the repo's default upstream branch.
SourceBranches []string
// ContainerPath is the absolute container path to mount a new repo at. It is
// used only for repos not already in the source container (existing repos
// keep the snapshot's mount path). When empty, it defaults to
// /home/user/src/<basename>.
ContainerPath string
// TagRegexp selects tags for a new repo. Existing source repos retain their
// persisted tag selection.
TagRegexp string
// DestPrimary is the fork's primary branch, created from SourceBranches[0].
// It must not be one of the repo's mapped branches, since Fork force-resets
// the destination host branch. Fork does not check it against other
// containers' branches or unrelated local refs, so the caller still owns
// uniqueness there. Additional (non-primary) branches keep their source
// names.
DestPrimary string
}
ForkRepo describes one repository in a fork and the branches it carries.
type Harness ¶ added in v0.8.0
type Harness string
Harness identifies an agent harness whose config directories are mounted into a container.
const ( HarnessAmp Harness = "amp" HarnessAndroid Harness = "android" HarnessAntigravity Harness = "antigravity" HarnessClaude Harness = "claude" HarnessCodex Harness = "codex" HarnessGoose Harness = "goose" HarnessKilo Harness = "kilo" HarnessKimi Harness = "kimi" HarnessOpencode Harness = "opencode" HarnessPi Harness = "pi" HarnessQwen Harness = "qwen" )
Known agent harnesses.
type InspectInfo ¶ added in v0.14.2
type InspectInfo struct {
Runtime string
ID string
Name string
State string
ImageRef string
ImageID string
Platform string
OS string
Architecture string
CPULimit float64 // Explicit quota in CPU units; zero means unrestricted.
CPUSet []int // Sorted configured logical CPU IDs; empty means inherited.
Mounts []Mount
Caches []CacheMount
}
InspectInfo describes observed Docker/Podman runtime configuration for a container.
type Mount ¶ added in v0.14.0
type Mount struct {
// HostPath is the absolute path on the host. "~" and "~/" resolve to the
// host user's home directory.
HostPath string
// ContainerPath is the path inside the container. "~" and "~/" resolve to
// the container user's home directory via [ResolveContainerPath]. When empty,
// it mirrors a home-relative HostPath via [ResolveMountTarget].
ContainerPath string
// ReadOnly mounts the host path read-only.
ReadOnly bool
}
Mount defines a host directory to bind-mount into the running container.
type Platform ¶ added in v0.14.0
type Platform string
Platform is a Linux container platform.
const ( // PlatformDefault uses the host's native Linux container platform. PlatformDefault Platform = "" // PlatformLinuxARM64 is the Linux arm64 container platform. PlatformLinuxARM64 Platform = "linux/arm64" // PlatformLinuxAMD64 is the Linux amd64 container platform. PlatformLinuxAMD64 Platform = "linux/amd64" )
func DefaultPlatform ¶ added in v0.14.0
func DefaultPlatform() Platform
DefaultPlatform returns the host's native Linux container platform.
func (Platform) Architecture ¶ added in v0.14.0
Architecture returns the platform architecture component.
func (Platform) Resolve ¶ added in v0.14.0
Resolve returns the host's native Linux container platform when p is empty.
type PullOpts ¶ added in v0.18.1
type PullOpts struct {
// Provider generates the commit message. A nil Provider uses a fixed message.
Provider genai.Provider
// ContextTokens is the selected model's context window. Zero uses the
// commit-message generator default.
ContextTokens int
// NoVerify passes --no-verify to the container commit, skipping the
// pre-commit and commit-msg hooks.
NoVerify bool
}
PullOpts configures Container.Pull.
type Repo ¶ added in v0.9.0
type Repo struct {
// GitRoot is the absolute path to the git repository root on the host.
GitRoot string `json:"git_root"`
// Branches lists the git branches to push into the container.
// Branches[0] is the primary branch (checked out in the working tree,
// used for container naming). Branches[1:] are also available as local
// branches. Each branch tracks the same upstream as its host branch.
Branches []string `json:"branches"`
// ContainerPath is the absolute destination path inside the
// container, e.g. "/home/user/src/github/caic". When empty,
// populateContainerPath fills it from filepath.Base(GitRoot).
// When two repos share the same basename, resolveContainerPaths
// disambiguates using relative paths from /home/user/src.
// Callers may set it explicitly to override.
ContainerPath string `json:"container_path,omitempty"`
// Remotes lists the host remotes whose cached branches are mirrored into the container.
Remotes []string `json:"remotes,omitempty"`
// TagRegexp selects host tags to mirror into the container. Empty selects no tags.
TagRegexp string `json:"tag_regexp,omitempty"`
// DefaultRemote is the host's default git remote. When empty, the upstream
// remote tracked by local main or master takes precedence over origin.
DefaultRemote string `json:"default_remote,omitempty"`
// DefaultBranch is the default branch for DefaultRemote.
DefaultBranch string `json:"default_branch,omitempty"`
}
Repo describes a git repository to push into a container.
func (*Repo) ResolveDefaults ¶ added in v0.19.0
ResolveDefaults populates Remotes, DefaultRemote, and DefaultBranch if not already set. It reads the host checkout without modifying its refs or configuration.
func (*Repo) UnmarshalJSON ¶ added in v0.16.0
UnmarshalJSON decodes Repo, including legacy persisted labels.
type Runtime ¶ added in v0.18.2
type Runtime string
Runtime identifies a workspace execution backend. RuntimeAuto leaves backend selection to md's normal detection.
const ( RuntimeAuto Runtime = "" RuntimeDocker Runtime = "docker" RuntimePodman Runtime = "podman" )
Runtime values identify supported workspace execution backends.
type StartOpts ¶
type StartOpts struct {
// BaseImage is the full Docker image reference (e.g.
// "ghcr.io/caic-xyz/md-user:v0.7.1" or "myregistry/custom:tag"). When empty,
// DefaultBaseImage is used.
BaseImage string
// Platform is the Linux container platform, e.g. "linux/amd64" or
// "linux/arm64". Empty means use the host's native platform.
Platform string
// GitObjectCopyMinBytes is the minimum object store size for copying Git
// objects into a new container before the initial push. Zero uses the
// default, -1 disables copying, and 1 includes every nonempty object store.
GitObjectCopyMinBytes int64
// Display enables X11/VNC virtual display (port 5901).
Display bool
// Tailscale enables Tailscale networking inside the container.
//
// It is recommended to set Client.TailscaleAPIKey to enable ephemeral nodes. If Client.TailscaleAPIKey is
// not set, the node will not be ephemeral. Instead, an authentication URL will be printed back by md.
Tailscale bool
// TailscaleAuthKey is a pre-authorized Tailscale auth key.
//
// When empty and Tailscale is true, Client.TailscaleAPIKey is used to generate an authentication key.
//
// The tailnet policy must allow "tag:md".
//
// https://tailscale.com/docs/features/access-control/auth-keys
TailscaleAuthKey string
// USB enables USB device passthrough (Linux only).
USB bool
// Sudo enables password-based sudo for the user account. A random
// password is generated per container and stored as a container label;
// retrieve it with `md sudo-password`. Defaults to false.
Sudo bool
// Caches lists host directories to COPY into the image at build time.
// Use well-known names from [WellKnownCaches] or construct [CacheMount]
// values directly. Paths that do not exist on the host are silently skipped.
Caches []CacheMount
// Mounts lists host directories to bind-mount into the running container.
// Missing host directories are rejected before the runtime is invoked.
Mounts []Mount
// Labels are additional Docker labels (key=value) applied to the container.
Labels []string
// Quiet suppresses informational output during startup.
Quiet bool
// ExtraEnv holds environment updates to inject into the container's ~/.env.
// Entries use KEY=VALUE to set a value or KEY= to remove one. Values are
// shell-quoted before writing, so they may contain spaces and newlines.
ExtraEnv []string
// MaxCPUs limits the number of CPU cores the container may use.
// Passed as --cpus to docker/podman. Zero means no limit.
// Use [DefaultMaxCPUs] to calculate a default from the runtime CPU count.
MaxCPUs int
// ExtraRunArgs are additional arguments passed verbatim to the
// container runtime's "run" command. Not portable across runtimes.
ExtraRunArgs []string
// contains filtered or unexported fields
}
StartOpts configures container startup.
type StartResult ¶
type StartResult struct {
// TailscaleFQDN is the Tailscale FQDN assigned to the container, if any.
TailscaleFQDN string
// TailscaleAuthURL is the Tailscale auth URL when no pre-auth key was provided.
TailscaleAuthURL string
}
StartResult contains Tailscale information from Connect. Port information is available on Container directly (SSHPort, VNCPort) after Launch returns.
type WarmupOpts ¶ added in v0.9.0
type WarmupOpts struct {
// BaseImage is the full Docker image reference. When empty,
// DefaultBaseImage+":latest" is used.
BaseImage string
// Platform is the Linux container platform. Empty means use the host's
// native platform.
Platform string
// Caches lists host directories to COPY into the image at build time.
Caches []CacheMount
// Quiet suppresses informational output.
Quiet bool
// Force rebuilds the specialized image even when its inputs are unchanged.
Force bool
}
WarmupOpts configures base image warmup.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
md
command
Package main implements the md CLI for isolated Docker development containers.
|
Package main implements the md CLI for isolated Docker development containers. |
|
Package containers wraps Docker and Podman command-line runtimes.
|
Package containers wraps Docker and Podman command-line runtimes. |
|
Package git provides git utility functions for repository introspection, branch management, and pushing.
|
Package git provides git utility functions for repository introspection, branch management, and pushing. |