md

package module
v0.16.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2026 License: Apache-2.0 Imports: 40 Imported by: 0

README

md: My Development containers

Each container is locked to a repository-branch pair. No confusion. Safe parallel work.

Safe parallel work with multiple AI coding agents. Run Claude Code, Codex, Amp CLI, Gemini CLI, Kilo CLI, Pi, and other tools in isolated containers without branch conflicts, file interference, or environmental headaches.

codecov

Installation

curl caic.xyz/install.sh | bash
From source
go install github.com/caic-xyz/md/cmd/md@latest

Recommended: Also install git-maruel for the git squash and git rb helpers.

Quick Start

# Start container for your current branch; this automatically ssh in.
git checkout -b wip origin/main
md start

# You are now inside the container
cd ~/src/<repo-name>
claude
exit

# Check pending changes
md diff

# Pull changes back when done
md pull
Multiple mapped branches

md start --extra-branch <branch> maps additional branches into the same container. The first branch (Branches[0]: current branch or -b) remains the primary branch.

For now, md diff reports changes for the primary branch only. Extra mapped branches are available for push, pull, and fork, but they are not diffed by md diff; inspect them inside the container with Git directly.

Documentation

🔥 Full documentation is at docs.caic.xyz 🔥

Contributing

Made with ❤️ by Marc-Antoine Ruel. Contributions are very appreciated! Thanks in advance! 🙏

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

Examples

Constants

View Source
const DefaultBaseImage = "ghcr.io/caic-xyz/md-user"

DefaultBaseImage is the base image used when none is specified.

Variables

View Source
var HarnessMounts = map[Harness]AgentPaths{
	HarnessAmp:      {Description: "Amp", HomePaths: []string{".amp"}, XDGConfigPaths: []string{"amp"}, LocalSharePaths: []string{"amp"}},
	HarnessAndroid:  {Description: "Android Studio", HomePaths: []string{".android"}},
	HarnessClaude:   {Description: "Claude Code", HomePaths: []string{".claude"}},
	HarnessCodex:    {Description: "Codex", HomePaths: []string{".codex"}},
	HarnessGemini:   {Description: "Gemini CLI", HomePaths: []string{".gemini"}},
	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.

View Source
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 DefaultMaxCPUs added in v0.12.4

func DefaultMaxCPUs() int

DefaultMaxCPUs returns max(2, NumCPU-2), a sensible CPU limit that leaves headroom for the host while guaranteeing at least 2 cores.

func FormatBytes added in v0.9.0

func FormatBytes(n int64) string

FormatBytes formats n bytes as a human-readable string (e.g. "1.2 GB").

func ResolveContainerPath added in v0.13.5

func ResolveContainerPath(p string) string

ResolveContainerPath expands "~" or a leading "~/" to the container user's home directory; absolute paths are returned unchanged.

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
	LocalSharePaths []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 absolute path inside the container. "~" and "~/"
	// resolve to the container user's home directory via [ResolveContainerPath].
	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 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

func New(logger Logger, rt containers.Runtime, stdout io.Writer) (*Client, error)

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) Close added in v0.16.0

func (c *Client) Close() error

Close implements io.Closer.

func (*Client) Container

func (c *Client) Container(repos ...Repo) (*Container, error)

Container returns a Container handle for the given repos. It populates MountedPath 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

func (c *Client) Get(ctx context.Context, name string) (*Container, error)

Get returns a single Container by name, or an error if not found. Uses docker inspect for a targeted lookup.

func (*Client) List

func (c *Client) List(ctx context.Context) ([]*Container, error)

List returns running md containers sorted by name.

func (*Client) PruneImages added in v0.9.0

func (c *Client) PruneImages(ctx context.Context, stdout, stderr io.Writer) ([]string, error)

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 the user image is built, without starting a container. Returns true if a build was performed.

type Container

type Container struct {
	*Client

	// Repos are the git repositories in this container. Repos[0] is the
	// primary; the rest are pushed alongside it. Each repo's MountedPath
	// 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
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].MountedPath)+" && 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
}

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, extraArgs []string) error

Diff writes the diff between the host branch and current for Repos[repoIdx] to stdout/stderr. When stdout is a terminal, a TTY is allocated so git's pager and colors work.

func (*Container) DiskUsage added in v0.9.0

func (c *Container) DiskUsage(ctx context.Context) (int64, error)

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, p genai.Provider) error

Fetch commits any uncommitted changes in Repos[repoIdx] in the container and fetches them locally, updating the remote-tracking ref without integrating.

p controls AI commit message generation. Pass nil to use a default message.

func (*Container) Fork added in v0.12.0

func (c *Container) Fork(ctx context.Context, stdout, stderr io.Writer, opts *ForkOpts) (*Container, error)

Fork snapshots a running 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 primary branch gets a unique destination branch derived from its source branch (e.g. "main" → "main-0").

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) Processes added in v0.14.2

func (c *Container) Processes(ctx context.Context) ([]ProcessInfo, error)

Processes returns the running processes inside the container.

func (*Container) Pull

func (c *Container) Pull(ctx context.Context, stdout, stderr io.Writer, repoIdx int, p genai.Provider) error

Pull fetches changes from the container and integrates all mapped branches into the local repository.

p controls AI commit message generation. Pass nil to use a default message.

func (*Container) Purge added in v0.9.0

func (c *Container) Purge(ctx context.Context, stdout, stderr io.Writer) error

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

func (c *Container) Revive(ctx context.Context, stdout, stderr io.Writer) error

Revive restarts a stopped (exited) container. It 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 push repos or send .env — the container's filesystem is preserved across stop/start.

func (*Container) SSHCommand added in v0.13.2

func (c *Container) SSHCommand(opts []string, cmd string) []string

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) Signal added in v0.14.2

func (c *Container) Signal(ctx context.Context, pid int, sig string) error

Signal sends sig to pid inside the container.

func (*Container) Status added in v0.13.3

func (c *Container) Status(ctx context.Context) string

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

func (c *Container) Stop(ctx context.Context) error

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

func (c *Container) SudoPassword(ctx context.Context) (string, error)

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

func (c *Container) SyncDefaultBranch(ctx context.Context, repoIdx int) error

SyncDefaultBranch force-pushes the host's default branch (e.g. origin/main) for Repos[repoIdx] into the container's remote-tracking refs. It also refreshes upstream refs for mapped branches so agents can diff against branch upstreams.

func (*Container) TailscaleFQDN

func (c *Container) TailscaleFQDN(ctx context.Context) string

TailscaleFQDN returns the Tailscale FQDN for the container, or "" if unavailable.

type ForkOpts added in v0.12.0

type ForkOpts struct {
	// ExtraRepos are additional repos to map into the fork beyond the
	// source container's repos. Branches are the source branches to push from
	// the host; if empty, defaults to the repo's default upstream branch.
	// Fork generates a unique destination for the primary branch only.
	ExtraRepos []Repo
	// 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] for a sensible default.
	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 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"
	HarnessClaude   Harness = "claude"
	HarnessCodex    Harness = "codex"
	HarnessGemini   Harness = "gemini"
	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     int
	Mounts       []Mount
	Caches       []CacheMount
}

InspectInfo describes observed Docker/Podman runtime configuration for a container.

type Logger added in v0.15.0

type Logger = containers.Logger

Logger receives structured log records. It is an alias of containers.Logger so that a single Logger value can be shared by md, containers, and git without conversion.

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 absolute path inside the container. "~" and "~/"
	// resolve to the container user's home directory via [ResolveContainerPath].
	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

func (p Platform) Architecture() (string, error)

Architecture returns the platform architecture component.

func (Platform) Resolve added in v0.14.0

func (p Platform) Resolve() Platform

Resolve returns the host's native Linux container platform when p is empty.

func (Platform) String added in v0.14.0

func (p Platform) String() string

String returns p as a Docker platform string.

func (Platform) Validate added in v0.14.0

func (p Platform) Validate() error

Validate returns an error unless p is a supported Linux container platform or PlatformDefault.

type ProcessInfo added in v0.14.2

type ProcessInfo struct {
	PID     int
	PPID    int
	User    string
	State   string
	CPU     float64
	Mem     float64
	Time    string
	Command string
}

ProcessInfo describes a single process running inside a container.

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 in the container, tracked from the fake "host" remote.
	Branches []string `json:"branches"`
	// MountedPath is the absolute destination path inside the
	// container, e.g. "/home/user/src/github/caic". When empty,
	// populateMountPath fills it from filepath.Base(GitRoot).
	// When two repos share the same basename, resolveMountPaths
	// disambiguates using relative paths from /home/user/src.
	// Callers may set it explicitly to override.
	MountedPath string `json:"mounted_path,omitempty"`
	// DefaultRemote is the host's default git remote.
	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) UnmarshalJSON added in v0.16.0

func (r *Repo) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes Repo, including legacy labels that used "branch".

func (*Repo) Validate added in v0.13.2

func (r *Repo) Validate() error

Validate returns an error for invalid repo fields.

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
	// 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] for a sensible default.
	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
}

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL