Documentation
¶
Overview ¶
Package docker is the docker engine: it builds `docker run`, `docker exec` and thin-image build argv, manages images, the shared nix-store volume and devcell containers, watches in-container boot progress, and implements `cell build df`, `cell build prune` and `cell cleanup`.
Index ¶
- Constants
- Variables
- func BootGroupCount(cellCfg cfg.CellConfig) int
- func BuildArgv(spec RunSpec, fs FS, lookPath func(string) (string, error)) []string
- func BuildCleanupPrompt(closures []LiveClosure) string
- func BuildCleanupScript(closures []LiveClosure) string
- func BuildExecArgv(spec ExecSpec) []string
- func BuildLabel(prefix, stack string, explicit bool) string
- func BuildPrunePrompt(opts PruneOpts) string
- func BuilderContainerState(ctx context.Context, name string) (exists, running bool)
- func BuilderOrphanedByCancel(runErr, ctxErr error) bool
- func CleanupOrphanedProxies(ctx context.Context, skipCellName string) error
- func ClosureAliveArgv(volume, image string) []string
- func ClosureDeadWarning(alive bool) (warning string, dead bool)
- func CollectRunningContainers(ctx context.Context) ([]string, error)
- func CollectVolumeMounts(ctx context.Context) map[string][]string
- func ConfirmDestructive(out io.Writer, in io.Reader, skipYes bool, isTTY bool, warning string) bool
- func ConfirmProceed(out io.Writer, in io.Reader, isTTY bool, warning string) bool
- func ConsumeContainerEventsPanel(events <-chan ContainerEvent, panel ux.BootView) bool
- func ContainerLabel(ctx context.Context, name, key string) string
- func ContainerRunning(ctx context.Context, name string) bool
- func DebugArgv(argv []string) string
- func DetectArch() string
- func DockerBindProbeArgv(image, volume, source, marker string) []string
- func DockerDaemonReachable(ctx context.Context) error
- func DockerHostPath(p string) string
- func DockerPlatform(arch string) string
- func DockerResolveContainerLink(ctx context.Context, container, link string) (string, error)
- func DockerRunningDevcellContainers(ctx context.Context) ([]string, error)
- func DockerVolumeDebug(ctx context.Context, volume string) string
- func EnsureIsolatedNetwork(ctx context.Context, name string, isolateGateway bool) error
- func EnsureNetwork(ctx context.Context) error
- func EnsureProxySidecar(ctx context.Context, opts ProxySidecarOpts) error
- func EnsureVolumeShell(ctx context.Context, volumeName, coreImage string) error
- func EnsureVolumeShellArgv(volumeName, coreImage string) []string
- func FlakeNixImage() string
- func FormatJSON(snap DFSnapshot, opts FormatOpts, w io.Writer) error
- func FormatNixStoreSection(r NixStoreReport, w io.Writer)
- func FormatTable(snap DFSnapshot, opts FormatOpts, w io.Writer) error
- func FormatTableWithVM(snap DFSnapshot, opts FormatOpts, vm VMDiskInfo, containers []string, ...) error
- func GenerateACLFiles(allow, block []string) map[string]string
- func GenerateSquidConf(mode string) string
- func HydrateNixCache(ctx context.Context, volumeName, registry, arch string) error
- func ImageExists(ctx context.Context, tag string) bool
- func ImageExistsForPlatform(ctx context.Context, tag, platform string) bool
- func ImageLabel(ctx context.Context, image, key string) string
- func ImageVersions(ctx context.Context) (base, user string)
- func InternalNetworkName(cellName string) string
- func KVMProbeArgv() []string
- func LocalImageIDFor(ctx context.Context, tag string) (string, error)
- func LocalImageSize(ctx context.Context, tag string) int64
- func NixCacheDockerArch(arch string) string
- func NixCacheImageRef(registry, arch string) string
- func NixHealthProbeArgv(volume string) []string
- func ParseClosureAliveResult(stdout string, err error) (resolvedPath string, alive bool)
- func ParseSize(s string) (int64, error)
- func PickImageTag(impure bool) string
- func PickImageTagThin() string
- func PrepareWireguard(cellHome string, cellCfg cfg.CellConfig) error
- func ProbeDockerBind(ctx context.Context, image, volume, source, marker string) (string, error)
- func ProbeKVM(ctx context.Context) bool
- func ProjectNixpkgsRev(baseDir string) (string, error)
- func ProxyConfDir(cellHome, cellName string) string
- func ProxySidecarName(cellName string) string
- func PullImageForPlatform(ctx context.Context, tag, platform string, verbose bool) error
- func ReclaimBuilderSlot(name string, exists, running bool) (remove bool, err error)
- func RemoveNetwork(ctx context.Context, name string) error
- func RemoveOrphanedContainer(ctx context.Context, name string) error
- func RemoveProxySidecar(ctx context.Context, name string) error
- func ResolveBuildTag(custom, derived string) string
- func ResolveTrustFlake(baseDir, cellHome string) bool
- func RunCleanup(a RunCleanupArgs) error
- func RunDF(a RunDFArgs) error
- func RunPrune(a RunPruneArgs) error
- func ShouldHydrateFromCache(hydrated bool, getenv func(string) string) bool
- func StaleCellWarning(projectRev string, h NixStoreHealth) (string, bool)
- func StampRootsScript(closures []LiveClosure) string
- func ThinBuildArgvFull(...) []string
- func ThinBuildArgvWithPackages(...) []string
- func ThinBuilderContainerName(appName string) string
- func ThinStoreVolume() string
- func UpdateFlakeLock(ctx context.Context, configDir string, lockOnly bool, verbose bool, ...) error
- func UserImageTag() string
- func UserImageTagPure() string
- func UserImageTagThin() string
- func ValidateProxyCompatibility(c cfg.CellConfig) error
- func VolumeContains(ctx context.Context, volumeName, sentinelPath string) bool
- func VolumeContainsArgv(volumeName, sentinelPath string) []string
- func VolumeExists(ctx context.Context, name string) bool
- func VolumeHydrated(volumeName, sentinelPath string, exists func(string) bool, ...) bool
- func WriteThinBuildContext(w io.Writer, buildDir string) error
- type BuildLimits
- type ContainerEvent
- type ContainerLogWatcher
- type DFCache
- type DFCollector
- type DFContainer
- type DFImage
- type DFOpts
- type DFSnapshot
- type DFVolume
- type DockerCapacity
- type DockerDebugInfo
- type Engine
- type EntryKind
- type ExecCollector
- type ExecSpec
- type FS
- type FSFunc
- type FormatOpts
- type ImageMetadata
- type LiveClosure
- type NixRootEntry
- type NixRootMeta
- type NixStoreHealth
- type NixStoreReport
- type ProxySidecarOpts
- type PruneOpts
- type PruneStep
- type RankedEntry
- type RunCleanupArgs
- type RunDFArgs
- type RunPruneArgs
- type RunSpec
- type VMDiskInfo
Constants ¶
const ( ContainerProfileLink = "/opt/devcell/.local/state/nix/profiles/profile" ContainerGenerationLink = "/opt/devcell/.local/state/nix/profiles/home-manager" )
Symlinks inside a running container that resolve to its closure's volume-resident store paths. Resolved with `docker exec <c> readlink -f`.
const ( // DefaultRegistry is the fallback registry prefix for devcell images. DefaultRegistry = "ghcr.io/devcell-sh/devcell" // BootContainerPath is the container-side path where the host boot // directory is bind-mounted. Hosts the Go-generated entrypoint script. BootContainerPath = "/tmp/devcell-boot" )
const ( // DefaultBuildCPUs is "0" — no CFS quota by default. The memory ceiling // plus the max-jobs derived from it are the OOM guard; a CPU quota only // starves per-job cores (nproc ignores it anyway) and slows the build. DefaultBuildCPUs = "0" )
Resource ceiling for the thin-build container (CELL-359).
The builder used to run uncapped, so a `nix build` spike was arbitrated by the VM-wide OOM killer only after the whole VM was already starved. Capping trades that for a deterministic cgroup kill confined to the builder: sibling cells survive and the failure names its own cause.
These are ceilings, NOT reservations, and they are only emitted when they actually constrain the daemon — see clampBuildLimits. A ceiling at or above what the daemon has protects nothing, and dockerd rejects a --cpus larger than its CPU count outright ("range of CPUs is from 0.01 to 2.00", exit 125), which is fatal on a stock 2-CPU Colima VM.
Two properties make a ceiling safe to emit, and the first cut of CELL-359 shipped with neither:
nix's own concurrency must be derived from the ceiling. `--cpus` is a CFS bandwidth quota, not a core count: nproc inside a `--cpus 4` container still reports every host CPU, so `max-jobs = auto` kept scheduling one job per host CPU. Eight concurrent derivations under an 8 GiB ceiling is ~1 GiB each, and `npm ci` over a large dependency tree needs several — the cgroup OOM killer took it out mid-install ("Killed", exit 137).
The ceiling cannot lean on swap as a cushion. Leaving --memory-swap unset gives Docker's 2x default, but Lima and Docker Desktop VMs both run swapless in practice (SwapTotal: 0), so the ceiling is hard at --memory and the concurrency derived from it is the only thing keeping the build inside it.
const DefaultSquidImage = "docker.io/ubuntu/squid:latest@sha256:6a097f68bae708cedbabd6188d68c7e2e7a38cedd05a176e1cc0ba29e3bbe029"
const DefaultThinStoreVolume = "devcell-nix-store"
DefaultThinStoreVolume is the named Docker volume that holds the thin-mode /nix store across builds and cell runs. Single shared volume by default so stack rebuilds reuse the existing nix store.
const NixCoreImage = "docker.io/nixos/nix:2.34.9"
NixCoreImage is the default nix base image for thin builds. Prefer cfg.DefaultNixImage for the canonical constant; this alias exists for call sites inside the docker engine that don't take a config parameter.
const NixDFReportScript = NixHealthProbeScript + "\n" + nixRootsListScript
NixDFReportScript is the health probe plus the root/meta listing — still purely read-only.
const NixGCRootReportScript = `` /* 1045-byte string literal not displayed */
NixGCRootReportScript prints the current GC root state: how many roots, how many unique hashes, and details from each -meta file. Used by the prune preflight to give drift visibility before destructive operations. Exported for test assertions.
const NixHealthProbeScript = `` /* 1582-byte string literal not displayed */
NixHealthProbeScript emits one machine-readable line:
total=N stale=N hashes=N generations=N orphaned=N
total/stale: devcell root symlinks and how many dangle. hashes: distinct profile hashes (>1 means config/lock drift). generations/orphaned: per-user profile generations and how many no devcell root protects (reclaimable by `cell build prune --pure`).
const ProfilePath = "/opt/devcell/.local/state/nix/profiles/profile"
ProfilePath is the canonical location of the home-manager profile baked into every thin image by thin_build.go.
const SafeNixGCScript = `` /* 1451-byte string literal not displayed */
SafeNixGCScript is the shell script that performs project-aware nix garbage collection. It removes only orphaned profile generations that aren't protected by project-scoped GC roots, then runs nix-store --gc.
CELL-334: also reads *-meta files to identify and clean up stale roots (roots whose metadata exists but whose profile target is dangling). Reports stale root count for drift visibility.
Exported for test assertions.
const ThinEntrypointSentinel = "/nix/var/nix/profiles/devcell-tools/bin/tini"
ThinEntrypointSentinel is the path the thin image's ENTRYPOINT references (built by thin_build.go:259). Used as the hydration probe in cmd/root.go's auto-build gate (CELL-38).
Variables ¶
var ErrBuilderRunning = errors.New("builder already running")
ErrBuilderRunning is returned when the app's builder slot is occupied by a live container. Callers must never remove it; wait or let it finish.
var ErrDockerDaemonUnreachable = errors.New("Docker is not running. Please start Docker and retry")
ErrDockerDaemonUnreachable is returned by DockerDaemonReachable when the docker daemon doesn't respond. Stable so callers can match on it.
var Modules []string
Modules is the list of extra nix modules composed on top of the stack. Set from CellConfig at startup.
var PerCellImage bool
PerCellImage tags user images per cell instead of per stack. Set from CellConfig at startup; defaults to false (stack-based).
var Registry = DefaultRegistry
Registry is the active container registry. Set via cfg.ResolvedRegistry() at startup; defaults to DefaultRegistry.
var Stack = "base"
Stack is the resolved nix stack name (e.g. "ultimate", "go"). Set from CellConfig at startup; defaults to "base".
Functions ¶
func BootGroupCount ¶
func BootGroupCount(cellCfg cfg.CellConfig) int
BootGroupCount is how many group rows bootGroups will draw for cellCfg: the three fixed groups and Environment, plus Services when the GUI is on. The cage sizes its boot popup from it before the engine builds the groups.
func BuildArgv ¶
BuildArgv constructs the full docker run argv for the given spec. It is pure given injectable FS and LookPath.
func BuildCleanupPrompt ¶
func BuildCleanupPrompt(closures []LiveClosure) string
BuildCleanupPrompt is the confirmation text for `cell cleanup`. States the retention rule (running-only) and how many containers stay protected — the primary non-debug UX for the reaper.
func BuildCleanupScript ¶
func BuildCleanupScript(closures []LiveClosure) string
BuildCleanupScript emits the reaper shell: remove gcroots/devcell/ entries whose hash is not in the live set. Only root symlinks and their -meta files are touched — never auto/ roots (namespace-local, CELL-330) and never the store itself (that's `cell build prune`'s job).
func BuildExecArgv ¶
BuildExecArgv constructs a docker exec argv for attaching to a running container.
func BuildLabel ¶
BuildLabel renders a progress label for an image build. When the stack was explicitly chosen by the user (TOML `stack = "..."` or `--stack`/env override), the qualifier is surfaced so they know what's about to run. Otherwise it's omitted because stacks are deprecated (CELL-6/337) and surfacing the resolved-default misleads — implies an opt-in that wasn't made.
func BuildPrunePrompt ¶
BuildPrunePrompt returns the user-facing confirmation warning text for the given prune mode. All prompts share the format:
⚠ This will delete ALL <specific-list>. Target: <host-specific-detail> Continue? [y/N]
The exact list and target line are mode-specific, per CELL-101.
func BuilderContainerState ¶
BuilderContainerState reports whether a container with the given name exists and whether it is currently running.
func BuilderOrphanedByCancel ¶
BuilderOrphanedByCancel is true when the `docker run` client died because the caller's context was cancelled (Ctrl-C / SIGTERM). The client is SIGKILLed but the container keeps running — an orphan holding the shared /nix volume — so the caller must remove its own builder in that case.
func CleanupOrphanedProxies ¶
CleanupOrphanedProxies finds proxy sidecars whose corresponding cell container is no longer running, and removes them along with their internal networks. skipCellName is the current cell being started: its gateway is not orphaned, just pre-created before the container boots.
func ClosureAliveArgv ¶
ClosureAliveArgv returns the docker argv for the closure-alive probe. Runs inside the target image with the nix volume mounted so the profile's /nix/store/... symlink target can be resolved.
func ClosureDeadWarning ¶
ClosureDeadWarning returns a user-facing warning and dead=true when the closure probe reports the image's nix paths are gone.
func CollectRunningContainers ¶
CollectRunningContainers returns `docker ps` output for display.
func CollectVolumeMounts ¶
CollectVolumeMounts returns a map of volume name → container names that mount it.
func ConfirmDestructive ¶
ConfirmDestructive prints `warning` to out, reads one line from in, and returns true iff the user typed y/Y/yes/YES (case-insensitive, trimmed).
skipYes=true bypasses the prompt entirely (used for `-y` / `--yes`). The warning is not printed in this case — the user already opted in.
isTTY=false without skipYes refuses to proceed (returns false after printing a refusal message that mentions --yes). This prevents accidental destruction when stdin is piped (e.g. `echo y | cell build prune --force`).
func ConfirmProceed ¶
ConfirmProceed is the default-YES twin of ConfirmDestructive: a nudge, not a gate. Prints the warning; bare Enter or anything except n/no proceeds. Non-TTY prints the warning and proceeds unconditionally — automation is never blocked by a hygiene nudge.
func ConsumeContainerEventsPanel ¶
func ConsumeContainerEventsPanel(events <-chan ContainerEvent, panel ux.BootView) bool
ConsumeContainerEventsPanel reads JSONL events from a ContainerLogWatcher and updates the boot panel. Handles both system events (from _notify in the entrypoint) and service events (from devcell-event in s6 services). Returns true when boot.ready arrived (clean finish), false on channel close.
func ContainerLabel ¶
ContainerLabel returns the value of a Docker label on a running or stopped container, or "" if the container or label is missing.
func ContainerRunning ¶
ContainerRunning checks if a container with the given name is currently running.
func DebugArgv ¶
DebugArgv renders an argv for --debug output. Multi-line elements (embedded `sh -c` scripts) are elided to a one-line placeholder — dumping the probe script made the health check look like it printed the script instead of running it.
func DetectArch ¶
func DetectArch() string
DetectArch returns "aarch64" or "x86_64". Respects DEVCELL_ARCH env override ("amd64"→"x86_64", "arm64"→"aarch64") for cross-architecture builds.
func DockerBindProbeArgv ¶
DockerBindProbeArgv composes the non-mutating debug probe command.
func DockerDaemonReachable ¶
DockerDaemonReachable probes the daemon with a single `docker info` call. Cheap (~30ms warm) and avoids the confusing fallout (`Pulling core image nixos/nix:latest failed`) when the socket is unreachable. Call once at the top of any path that will later invoke docker (CELL-44).
func DockerHostPath ¶
DockerHostPath translates container-local paths (e.g. /devcell-256/nixhome) to Docker-accessible host paths when running inside a devcell container. Uses DEVCELL_HOST_PROJECT_DIR env var set by the entrypoint.
func DockerPlatform ¶
DockerPlatform returns the docker --platform value for the given nix arch.
func DockerResolveContainerLink ¶
DockerResolveContainerLink resolves a symlink inside a running container to its final target — the only namespace where /opt/devcell resolves.
func DockerRunningDevcellContainers ¶
DockerRunningDevcellContainers lists RUNNING devcell containers by the devcell.basedir label every `cell` launch stamps (runner.go BuildArgv). Running-only on purpose: `docker ps` without -a (CELL-334 retention decision, 2026-08-01).
func DockerVolumeDebug ¶
DockerVolumeDebug returns daemon-side metadata for a named volume.
func EnsureIsolatedNetwork ¶
EnsureIsolatedNetwork creates an --internal docker network if it doesn't exist. If isolateGateway is true, the bridge gateway mode is set to "isolated" so the host is unreachable from containers on the network. Returns an error if the network exists but is not internal.
func EnsureNetwork ¶
EnsureNetwork creates the devcell-network docker network if it doesn't exist.
func EnsureProxySidecar ¶
func EnsureProxySidecar(ctx context.Context, opts ProxySidecarOpts) error
EnsureProxySidecar starts the squid proxy sidecar container. It generates the squid config, writes it to disk, starts the container on the internal network, connects it to the egress network, and waits for TCP readiness on port 3128.
func EnsureVolumeShell ¶
EnsureVolumeShell ensures the nix volume contains the shell closure from the core image so /bin/sh resolves when the volume mounts at /nix.
The nixos/nix image's /bin/sh is a symlink into /nix/store/<hash>/bin/bash. When the shared nix-store volume mounts over /nix, the symlink target must exist on the volume. A stale volume (from a prior image version) has different store hashes, making /bin/sh dangle and the thin build unbootable.
The fix: mount the volume at /mnt/nix (leaving the image's own /nix intact) and copy the default profile's closure to the volume. This also covers coreutils, nix, git, and other tools the thin build script needs.
No-op when the volume does not exist yet (Docker auto-populates on first mount) or the closure is already present.
func EnsureVolumeShellArgv ¶
EnsureVolumeShellArgv returns the docker argv that bootstraps the nix volume with the core image's shell closure. Pure for testing.
func FlakeNixImage ¶
func FlakeNixImage() string
FlakeNixImage returns the lightweight nixos/nix image used for flake lock/update and stack discovery. Decoupled from the binary version so dev builds with -dirty tags don't require a registry push.
func FormatJSON ¶
func FormatJSON(snap DFSnapshot, opts FormatOpts, w io.Writer) error
FormatJSON emits a stable schema for scripting. Keys are camelCase so `jq` recipes can be pinned across releases. The order of entries is the same as FormatTable — sorted by ReclaimBytes desc — so a single `jq '.entries[0]'` always picks the biggest reclaimable thing.
func FormatNixStoreSection ¶
func FormatNixStoreSection(r NixStoreReport, w io.Writer)
FormatNixStoreSection renders the nix block of `cell build df`. An empty report (no volume data) renders nothing.
func FormatTable ¶
func FormatTable(snap DFSnapshot, opts FormatOpts, w io.Writer) error
FormatTable renders the ranked entries as a human-readable table with a totals footer and bottom reclaim hint. Mirrors the layout shown in the `cell build df` design (CELL-98).
func FormatTableWithVM ¶
func FormatTableWithVM(snap DFSnapshot, opts FormatOpts, vm VMDiskInfo, containers []string, volMounts map[string][]string, w io.Writer) error
FormatTableWithVM renders the ranked entries table plus Docker VM disk info, running containers, volume-to-container mapping, and cleanup instructions.
func GenerateACLFiles ¶
GenerateACLFiles classifies allow and block entries into domain and CIDR files suitable for squid dstdomain and dst ACLs. Returns a map of filename to file content.
func GenerateSquidConf ¶
GenerateSquidConf returns a complete squid.conf for the proxy sidecar. mode is "allow" (deny by default) or "block" (allow by default).
func HydrateNixCache ¶
HydrateNixCache pulls the nix cache image from GHCR into the named Docker volume. Shows a progress spinner. Errors are non-fatal: a failed pull means the build runs from scratch (slower but correct).
func ImageExists ¶
ImageExists returns true if a Docker image with the given tag exists locally.
func ImageExistsForPlatform ¶
ImageExistsForPlatform returns true if a Docker image with the given tag exists locally AND matches the requested platform (e.g. "linux/amd64"). Empty platform falls back to ImageExists (host default).
func ImageLabel ¶
ImageLabel returns one label of a local image, or "" when the image or the label is missing.
func ImageVersions ¶
ImageVersions reads build metadata from the user image. Returns (base, user) strings for backward compatibility with callers. Format: user = "<commit> built <date>" when both known,
"built <date>" when only date, "<commit>" when only commit, "" otherwise (falls through to legacy file read).
func InternalNetworkName ¶
InternalNetworkName returns the internal network name for a given cell.
func KVMProbeArgv ¶
func KVMProbeArgv() []string
KVMProbeArgv returns the argv for a throwaway container that tests whether the Docker daemon host exposes /dev/kvm. The container does nothing: if docker can attach the device node the exit code is 0; otherwise docker itself errors out before the container starts.
func LocalImageIDFor ¶
LocalImageIDFor returns the full image ID (sha256:...) for tag. Used to pin the running container to the exact image just built, rather than the mutable tag which could race with a concurrent build.
func LocalImageSize ¶
LocalImageSize returns the on-daemon size in bytes of the local image with the given tag. Used post-build to show "Loaded: 1.4 GB" alongside the spinner success — skopeo's per-blob progress is empty when stdout isn't a TTY, so we synthesize a summary from `docker image inspect` instead.
Returns 0 on any error; callers treat 0 as "size unknown, skip the summary".
func NixCacheDockerArch ¶
NixCacheDockerArch normalizes a nix-style arch ("aarch64", "x86_64") to Docker convention ("arm64", "amd64").
func NixCacheImageRef ¶
NixCacheImageRef returns the GHCR nix cache image reference for the given registry and Docker-convention arch (arm64 or amd64).
func NixHealthProbeArgv ¶
NixHealthProbeArgv wraps the probe in a docker-run of the given volume.
func ParseClosureAliveResult ¶
ParseClosureAliveResult interprets the probe's stdout + error. Returns the resolved store path and whether the closure is alive.
func ParseSize ¶
ParseSize handles docker's CLI size format. Examples:
"29.8GB" → 29_800_000_000 (decimal GB, not GiB — docker convention) "813.6kB" → 813_600 (lowercase k, like docker prints) "0B" → 0 "N/A" or "" → -1 (volume with no size info)
Returns -1 for unknown so the caller can distinguish "small but real" from "size not reported."
func PickImageTag ¶
PickImageTag is the single seam every runtime caller (`cell claude`, `cell shell`, `cell codex`, `cell gemini`, …) uses to decide which local image variant to exec into.
After the 2026-05-15 flip (CELL-183) + CELL-165 vocab rename, pure is the default and `impure` (was `debian`) is the opt-in legacy path:
impure=false (default): UserImageTagPure() (nix2container, devcell-user:<stack>-pure) impure=true (--impure): UserImageTag() (bare Dockerfile-built, devcell-user:<stack>)
func PickImageTagThin ¶
func PickImageTagThin() string
PickImageTagThin returns the thin image tag for runtime callers.
func PrepareWireguard ¶
func PrepareWireguard(cellHome string, cellCfg cfg.CellConfig) error
PrepareWireguard writes WireGuard config files for each enabled entry to <cellHome>/.wg/<name>.conf. PrivateKey lines are stripped from the config; a PostUp directive loads the key from /run/secrets/wg-private-key at runtime. No-op when no entries are enabled.
func ProbeDockerBind ¶
ProbeDockerBind verifies both that the daemon accepts source and that marker is visible inside a container. It is intended for --debug diagnostics only.
func ProbeKVM ¶
ProbeKVM runs a throwaway container to detect /dev/kvm on the daemon host. Results are cached for kvmCacheTTL so the ~100ms probe runs at most once per session.
func ProjectNixpkgsRev ¶
ProjectNixpkgsRev reads the scaffolded flake.lock under <baseDir>/.devcell/flake.lock and returns nodes.nixpkgs.locked.rev. A missing or unparsable lock returns "" without error — the warning simply won't fire (never fatal, never blocking).
func ProxyConfDir ¶
ProxyConfDir returns the host-side directory for squid config files.
func ProxySidecarName ¶
ProxySidecarName returns the gateway sidecar container name for a given cell.
func PullImageForPlatform ¶
PullImageForPlatform pulls a Docker image for a specific platform. Empty platform uses Docker's default (host architecture). When verbose is true, docker pull output is streamed to os.Stderr.
func ReclaimBuilderSlot ¶
ReclaimBuilderSlot decides what to do with a pre-existing builder container of the same name before starting a new build: nothing when absent, remove when it exited (a crashed or interrupted run left it behind), and refuse — never kill — when it is running.
func RemoveNetwork ¶
RemoveNetwork removes a docker network by name. Best-effort.
func RemoveOrphanedContainer ¶
RemoveOrphanedContainer removes a stopped container with the given name if it exists. Returns nil if the container doesn't exist or was successfully removed. Returns an error if the container is currently running.
func RemoveProxySidecar ¶
RemoveProxySidecar removes the proxy sidecar container. Best-effort.
func ResolveBuildTag ¶
ResolveBuildTag returns the tag a `cell build` invocation should use: custom (typically from --image) when non-empty, falling back to the auto-derived stack tag. Trims whitespace on custom to forgive copy-paste.
func ResolveTrustFlake ¶
resolveTrustFlake checks if the project has a flake.nix and whether the user has trusted it. On first encounter, prompts interactively and caches the answer in cellHome. Returns true if DEVCELL_FLAKE_TRUST=1 should be passed to the container. ResolveTrustFlake answers "install this project's flake.nix packages?" once per workspace: a recorded answer wins, otherwise the user is asked on the terminal. The cage calls it before opening its boot popup, since no prompt can be answered while the popup owns the keyboard.
func RunCleanup ¶
func RunCleanup(a RunCleanupArgs) error
RunCleanup orchestrates the reaper: build the plan, prompt, execute. Rejection is a clean no-op (user intent, not an error).
func RunDF ¶
RunDF orchestrates: collect → parse → format. The pure-data steps live in df.go; this function just wires them.
func RunPrune ¶
func RunPrune(a RunPruneArgs) error
RunPrune orchestrates: build the step plan, prompt the user, execute the steps. DryRun steps are printed but not executed. IgnoreError steps don't abort the loop on failure. Returns nil if the prompt was rejected (not an error — user intent).
func ShouldHydrateFromCache ¶
ShouldHydrateFromCache decides whether to pull the nix cache before building. Returns true when the volume is not yet hydrated AND the user hasn't disabled cache hydration via DEVCELL_NIX_CACHE=0.
func StaleCellWarning ¶
func StaleCellWarning(projectRev string, h NixStoreHealth) (string, bool)
StaleCellWarning decides whether this project's closure is behind the newest rev live on the volume, and renders the warning if so. Unknown revs on either side mean silence — a nudge must never fire on guesswork.
func StampRootsScript ¶
func StampRootsScript(closures []LiveClosure) string
StampRootsScript emits the shell that stamps hash-named GC roots for every live closure. Idempotent — re-stamping the same closure is a no-op (`ln -sfT` to the identical target). Only creates; never deletes, never GCs. Empty input yields an empty script (nothing to stamp).
func ThinBuildArgvFull ¶
func ThinBuildArgvFull(coreImage, containerName, volumeName, nixhomeRef, thinTag, hmTarget, arch, stack, modules, projectName string) []string
ThinBuildArgvFull composes the docker run argv for the thin build. Runs nixos/nix with the nix store volume + docker socket. Inside: home-manager switch (uses volume cache), then docker build to produce the thin image (nix-core + config, no /nix/store baked in).
hmTarget is the home-manager flake target name (typically "local" for thin); stack is the user-facing stack name written to DEVCELL_STACK/metadata.json; modules is a CSV of module names written to DEVCELL_MODULES (CELL-41); projectName is the project directory basename used to scope GC roots so different projects don't overwrite each other's nix store references (CELL-320).
nixhomeRef accepts EITHER:
- a filesystem path (e.g. /home/bob/nixhome): the caller streams a tar archive to stdin, which is extracted at /opt/nixhome before home-manager
- a flake reference (e.g. github:devcell-sh/home/main): no archive; home-manager runs against `<ref>#devcell-<stack><arch>` directly, letting nix fetch and cache under /nix/store. This is the clean-machine path (CELL-38), no local nixhome required.
Detected by prefix: anything starting with a flake-scheme (github:, git+, path:, http:, etc.) is treated as remote; everything else is treated as a local filesystem path.
func ThinBuildArgvWithPackages ¶
func ThinBuildArgvWithPackages(coreImage, containerName, volumeName, nixhomeRef, thinTag, hmTarget, arch, stack, modules, projectName, packages string) []string
ThinBuildArgvWithPackages is ThinBuildArgvFull plus the per-module package counts ("desktop: 69, base: 35") stamped on the image as the devcell.packages label, so `cell <agent>` can show them at start without evaluating nix again. Empty when the build could not evaluate them.
func ThinBuilderContainerName ¶
ThinBuilderContainerName names the thin builder for one cell (`<project>-<cellID>`, the same key as `devcell-<cell>`). One fixed name for every project meant a build starting in project B force-removed — SIGKILLed, exit 137 with no OOM anywhere — the build project A had in flight.
func ThinStoreVolume ¶
func ThinStoreVolume() string
ThinStoreVolume returns the volume name to use for the thin /nix store. Reads DEVCELL_NIX_VOLUME (trimmed); falls back to DefaultThinStoreVolume. When DEVCELL_ARCH requests a non-native architecture (e.g. amd64 on an ARM host), the default volume name gets an arch suffix so cross-arch builds use a separate nix store — mixing architectures on a single volume wastes space and causes dangling-symlink issues on every build.
func UpdateFlakeLock ¶
func UpdateFlakeLock(ctx context.Context, configDir string, lockOnly bool, verbose bool, out io.Writer) error
UpdateFlakeLock runs nix flake lock (or update) inside a lightweight nixos/nix container with configDir bind-mounted.
func UserImageTag ¶
func UserImageTag() string
UserImageTag returns the user's local image tag — the bare-name local devcell image. Unchanged across the 2026-05-15 flip: this name is the user's "current image" concept and existing local images keep working.
Default (stack-based): devcell-user:<stack> or devcell-user:<stack>-<mod1>-<mod2>-<sha8> Legacy (per_cell_image=true): devcell-user:<cell>
Used by:
- `cell <agent> --impure` (PickImageTag(true) → bare local tag)
- `cell build --impure` (docker build → tags this name)
Override with DEVCELL_USER_IMAGE env var.
func UserImageTagPure ¶
func UserImageTagPure() string
UserImageTagPure returns the local tag for nix2container-built (pure) images — the DEFAULT path after the 2026-05-15 flip (CELL-189). Same repo as UserImageTag with a "-pure" suffix.
Example: UserImageTag()="devcell-user:ultimate" → UserImageTagPure()="devcell-user:ultimate-pure".
func UserImageTagThin ¶
func UserImageTagThin() string
UserImageTagThin returns the local tag for thin images — nix store lives on a Docker named volume, not baked into the image.
Resolution order:
- DEVCELL_USER_IMAGE_THIN — legacy explicit override
- DEVCELL_USER_IMAGE — modern unified override; used as-is (no suffix). CELL-286 prep: every devcell image we publish is thin, so the `-thin` suffix on the env-driven path is redundant. CI sets `DEVCELL_USER_IMAGE=ghcr.io/devcell-sh/devcell:v<ver>-<arch>` and expects this exact tag at runtime (no suffix appended).
- UserImageTag() + "-thin" — local-dev fallback, preserves the suffix convention so `devcell-user:<stack>-thin` doesn't collide with `-pure`/`-impure` legacy local tags.
Example (no env): UserImageTag()="devcell-user:ultimate" → "devcell-user:ultimate-thin".
func ValidateProxyCompatibility ¶
func ValidateProxyCompatibility(c cfg.CellConfig) error
ValidateProxyCompatibility checks that no docker/cell settings conflict with proxy-mode network isolation. Returns nil when everything is compatible. Each error names the offending TOML key and suggests --force-insecure-network.
The denied caps and mount paths come from SolitaryPolicy as the canonical source of truth, keeping validation and BuildArgv enforcement in sync.
func VolumeContains ¶
VolumeContains spawns a throwaway busybox container (~5 MB) to test whether a sentinel path exists inside the named volume. sentinelPath must be the absolute in-container path the image's ENTRYPOINT references (e.g. /nix/var/nix/profiles/devcell-tools/bin/tini); see VolumeContainsArgv for the mount-layout rationale.
func VolumeContainsArgv ¶
VolumeContainsArgv returns the docker argv used by VolumeContains. Pure so the mount layout can be unit-tested without spawning docker.
The volume MUST be mounted at /nix (not /probe). Nix profile entries are absolute symlinks rooted at /nix/store/...; mounting elsewhere makes `test -e` follow a dangling target and report MISSING for a perfectly hydrated volume (CELL-45). Mounting at /nix matches what the builder and runner already do, so absolute symlinks resolve in-container.
func VolumeExists ¶
VolumeExists shells out to `docker volume inspect` — returns true on exit 0.
func VolumeHydrated ¶
func VolumeHydrated(volumeName, sentinelPath string, exists func(string) bool, probe func(string, string) bool) bool
VolumeHydrated reports whether a named Docker volume exists AND contains the given sentinel path. Use to gate auto-build in `cell shell`/`claude`/... so a stale or pruned `/nix` volume triggers a rebuild instead of failing later at the kernel's `exec: tini: no such file or directory` (CELL-40/332).
Pure function — caller injects the two probes so unit tests don't need docker. For runtime use, see VolumeExists and VolumeContains below.
func WriteThinBuildContext ¶
WriteThinBuildContext writes the local nixhome overlay needed by the thin builder. Streaming this through the Docker API avoids asking a VM-backed daemon to resolve a host path for a second-generation container.
Types ¶
type BuildLimits ¶
type BuildLimits struct {
Memory string // --memory value, "" to omit
CPUs string // --cpus value, "" to omit
MaxJobs int // nix max-jobs, 0 to leave at "auto"
Cores int // nix cores, 0 to leave at nix's own default
}
BuildLimits is what the builder may use: the docker ceilings plus the nix concurrency derived from them. A zero field means "emit nothing".
func ResolveBuildLimits ¶
func ResolveBuildLimits() BuildLimits
ResolveBuildLimits returns the build resource limits that will be applied. Exported for debug logging in cmd/build.go.
type ContainerEvent ¶
type ContainerEvent struct {
TS time.Time `json:"ts"`
Scope string `json:"scope"`
Service string `json:"service,omitempty"`
Status string `json:"status,omitempty"`
Msg string `json:"msg,omitempty"`
}
ContainerEvent is one parsed JSONL event from docker logs.
type ContainerLogWatcher ¶
type ContainerLogWatcher struct {
// contains filtered or unexported fields
}
ContainerLogWatcher follows docker logs for a running container, parses JSONL lines into ContainerEvent structs, and emits them on a buffered channel. Non-JSONL lines are silently skipped.
func NewContainerLogWatcher ¶
func NewContainerLogWatcher(ctx context.Context, container string, since time.Time) *ContainerLogWatcher
NewContainerLogWatcher starts `docker logs --follow --since=<since> <container>` and parses JSONL into ContainerEvents on the returned watcher's channel.
func (*ContainerLogWatcher) Close ¶
func (w *ContainerLogWatcher) Close()
Close stops the docker logs subprocess and waits for the reader goroutine.
func (*ContainerLogWatcher) Events ¶
func (w *ContainerLogWatcher) Events() <-chan ContainerEvent
Events returns the channel of parsed container events.
type DFCollector ¶
DFCollector is the test seam for `cell build df` — production wires ExecCollector, which shells to `docker system df -v --format json`. Tests inject a fake that returns a canned JSON fixture.
type DFContainer ¶
type DFOpts ¶
type DFOpts struct {
TopN int // 0 = all rows
Kinds []EntryKind // empty = all kinds
JSON bool // true → FormatJSON, false → FormatTable
}
DFOpts controls a single `cell build df` invocation.
type DFSnapshot ¶
type DFSnapshot struct {
Images []DFImage
Containers []DFContainer
Volumes []DFVolume
BuildCache []DFCache
}
DFSnapshot is the typed shape of `docker system df -v --format json`. All numeric fields arrive from docker as strings ("29.8GB", "3", "N/A") and are parsed once via parseSize / strconv.Atoi at unmarshal time.
func ParseSystemDF ¶
func ParseSystemDF(raw []byte) (DFSnapshot, error)
ParseSystemDF unmarshals the JSON blob produced by `docker system df -v --format json` into typed structs with parsed sizes.
type DockerCapacity ¶
DockerCapacity is what the build daemon advertises for itself. Note this is the daemon's own ceiling, which on macOS is the Colima/Docker Desktop VM — not the host Mac's specs, and not necessarily the daemon this process runs under if contexts differ.
type DockerDebugInfo ¶
type DockerDebugInfo struct {
Context string
Endpoint string
DockerHostEnv string
Runtime string
Name string
ServerVersion string
OperatingOS string
Architecture string
RootDir string
CPUs int
MemoryBytes int64
Socket string
SocketTarget string
}
DockerDebugInfo describes the client-to-daemon connection used by Cell. It deliberately excludes registry and authentication configuration.
func CollectDockerDebugInfo ¶
func CollectDockerDebugInfo(ctx context.Context) (DockerDebugInfo, error)
CollectDockerDebugInfo reports the actual daemon selected by the current Docker CLI environment. This matters inside a cell, where /var/run/docker.sock was fixed when the outer container was created.
type Engine ¶
type Engine struct{}
Engine runs a cell as a docker container built from a thin image: a small image whose /nix lives on the shared nix-store volume. It registers itself as engine.Docker.
Docker-only commands (cell stop, cell cleanup, cell build df, cell build prune) are not engine verbs; cmd/ calls this package for them directly.
func (Engine) Build ¶
Build builds the cell's thin image: it syncs the nixhome flake into the build dir, writes the overlay flake for the cell's stack and modules, and runs home-manager and `docker build` in a builder container. opts.Stack (else DEVCELL_STACK) overrides the stack, opts.Image the tag, and opts.Update empties the nix-store volume first. opts.DryRun, opts.Force, opts.NoCache and opts.Stage are not honored.
func (Engine) Init ¶
Init scaffolds devcell.toml and the .devcell/ build context in the project, then locks the nix flake inputs, or updates them with opts.Update or opts.Force. It builds no image; Build does.
func (Engine) Run ¶
Run acquires the thin image (building it when it is missing, the nix-store volume is unpopulated, or opts.Rebuild is set), runs the boot checklist, and runs the agent in a new container with the terminal attached. With opts.Detach the container starts in the background and Run returns once docker started it; with opts.DryRun it prints the docker run argv instead. A non-zero agent exit is *engine.ExitError.
Part of the checklist is engine-neutral but so far runs only here: the system prompt, git identity, 1Password secrets, the OpenRouter key, the Claude session ID, the cell home backup, the cellrun record and the command_finish telemetry event. opts.Force, opts.Update and opts.Background are not honored; --force and --stack=<name> in opts.Args reach the agent.
type EntryKind ¶
type EntryKind string
EntryKind tags a RankedEntry's origin so the formatter can render the right reclaim hint and column heading.
type ExecCollector ¶
type ExecCollector struct{}
ExecCollector is the real collector. It runs docker once and returns the raw JSON for ParseSystemDF to handle.
func (ExecCollector) CollectSystemDF ¶
func (ExecCollector) CollectSystemDF(ctx context.Context) ([]byte, error)
type ExecSpec ¶
type ExecSpec struct {
ContainerName string
User string
Binary string
Args []string
TTY bool
Env map[string]string
}
ExecSpec holds the parameters for building a docker exec argv.
type FormatOpts ¶
FormatOpts controls FormatTable / FormatJSON output.
type ImageMetadata ¶
type ImageMetadata struct {
BaseImage string `json:"base_image"`
Stack string `json:"stack"`
Modules []string `json:"modules"`
GitCommit string `json:"git_commit"`
BuildDate string `json:"build_date"`
Packages int `json:"packages"`
}
ImageMetadata holds structured build metadata from /etc/devcell/metadata.json.
func ImageMetadataFromContainer ¶
func ImageMetadataFromContainer(ctx context.Context) ImageMetadata
ImageMetadataFromContainer reads build metadata for the current launch's image.
Source-of-truth flip (2026-05-16): the date/rev now come from the OCI image manifest (labels + Created field) rather than /etc/devcell/metadata.json inside the image. Why: when metadata.json carried a real per-build timestamp, every `cell build` invocation perturbed homeRoot's tar hash and forced skopeo to re-push the ~3.9GB customization layer even when no source had changed. Pinning metadata.json to static placeholders eliminates that; the date moves to OCI manifest labels (which only affect the tiny manifest blob, not layer content).
Reads:
- .Created — OCI manifest creation timestamp (= our buildDate)
- .Config.Labels — devcell.stack, org.opencontainers.image.revision, etc.
- .Config.Env — DEVCELL_STACK (falls back to DEVCELL_PROFILE for older images)
Falls back to a runtime `cat /etc/devcell/metadata.json` for older images that predate the manifest-based stamping.
func ParseImageMetadata ¶
func ParseImageMetadata(data []byte) ImageMetadata
ParseImageMetadata parses JSON into ImageMetadata. Returns zero value on error.
type LiveClosure ¶
type LiveClosure struct {
Container string
ProfilePath string // /nix/store/<hash>-home-manager-path
GenerationPath string // /nix/store/<hash>-home-manager-generation
}
LiveClosure is one running container's protected store paths.
func CollectLiveClosures ¶
func CollectLiveClosures( ps func() ([]string, error), resolve func(container, link string) (string, error), logf func(format string, args ...any), ) ([]LiveClosure, error)
CollectLiveClosures enumerates running devcell containers via ps and resolves each one's profile + generation store paths via resolve. Dependency-injected for tests; the runtime call site wires `docker ps` and `docker exec readlink -f`.
A running container whose closure cannot be resolved fails the whole collection: an unknown closure means neither the reaper nor the prune gate can guarantee safety, so both must refuse — naming the cell.
logf, when non-nil, receives one line per datapoint (--debug visibility).
type NixRootEntry ¶
NixRootEntry is one GC root symlink on the volume.
type NixRootMeta ¶
NixRootMeta is the parsed -meta file for one root hash.
type NixStoreHealth ¶
type NixStoreHealth struct {
TotalRoots int
StaleRoots int
ProfileHashes int
Generations int
OrphanedGenerations int
// Lock-drift datapoints from the *-meta files stamped at container
// start (CELL-332). Zero values on pre-CELL-332 volumes. CELL-391
// consumes these for the stale-cell warning.
DistinctRevs int // distinct nixpkgs revs across metas
NewestRev string // rev with the most recent stamped= timestamp
NewestProjects int // how many metas sit on NewestRev
}
NixStoreHealth is the parsed probe result.
func ParseNixStoreHealth ¶
func ParseNixStoreHealth(out string) (NixStoreHealth, error)
ParseNixStoreHealth finds the datapoint line in probe output (docker may prepend image-pull noise) and parses its key=value fields. Missing keys are zero values (older probes / pre-CELL-332 volumes emit fewer fields). No datapoint line means the probe degraded — callers treat that as "skip silently", never as fatal.
func (NixStoreHealth) Summary ¶
func (h NixStoreHealth) Summary() (tag, detail string, warn bool)
Summary returns a short tag for the phase row, a longer diagnostic detail for debug output, and whether the result is a warning. The tag is what users see next to the dot; the detail carries counts and remediation hints.
type NixStoreReport ¶
type NixStoreReport struct {
Volume string
Health NixStoreHealth
Roots []NixRootEntry
Metas []NixRootMeta
}
NixStoreReport is the full parsed df report for the nix volume.
func CollectNixStore ¶
func CollectNixStore(ctx context.Context) (NixStoreReport, bool)
CollectNixStore runs the report against the thin store volume. Any failure returns ok=false — the df section is simply omitted, matching the CELL-390 degrade-to-silence contract.
func ParseNixStoreReport ¶
func ParseNixStoreReport(volume, out string) (NixStoreReport, error)
ParseNixStoreReport parses combined probe + listing output.
type ProxySidecarOpts ¶
type ProxySidecarOpts struct {
CellName string
WorkspaceName string
CellID string
WorkspaceHome string
InternalNet string
EgressNet string // "devcell-network"
Proxy cfg.NetworkProxySection
SquidImage string // defaults to DefaultSquidImage if empty
}
ProxySidecarOpts holds everything needed to start a proxy sidecar.
type PruneOpts ¶
type PruneOpts struct {
// GOOS is the target operating system: "darwin" or "linux".
// Tests pass this explicitly; the runtime call site passes runtime.GOOS.
GOOS string
// Force enables nuclear cleanup mode (docker desktop wipe / qcow nuke /
// aggressive nix GC). Default mode is the standard prune sequence.
Force bool
// Pure selects the nix path instead of the docker path.
Pure bool
// Rootless indicates a rootless Docker daemon on Linux. Only relevant
// when GOOS == "linux" && !Pure && Force. The runtime call site
// auto-detects this via `docker info`.
Rootless bool
// NixOS indicates /etc/NIXOS is present. Only relevant when
// GOOS == "linux" && Pure && Force; triggers system-profile cleanup.
NixOS bool
// HomeDir is the resolved user home (e.g. /home/warden). Used to
// compose absolute paths in macOS Docker Desktop wipe and the
// `~/.cache/nix` wipe on Linux. Tests pass a fixed value.
HomeDir string
// LinuxBuilderHost is the SSH target for the macOS linux-builder VM.
// Default: "builder@linux-builder".
LinuxBuilderHost string
// LiveClosures are the running containers' resolved store paths
// (CollectLiveClosures). When set, the pure prune plan stamps GC roots
// for them before the safe GC step, so "running implies rooted" holds
// by construction instead of being assumed (CELL-334 preflight gate).
LiveClosures []LiveClosure
}
PruneOpts describes a `cell build prune` invocation.
type PruneStep ¶
type PruneStep struct {
// Argv is the command and arguments.
Argv []string
// Func, when non-nil, is called instead of exec'ing Argv. Use this
// to replace shell-substituted commands with pure Go. When set, Argv
// is still joined for display (progress/dry-run output).
Func func(ctx context.Context) error
// IgnoreError lets the step fail without aborting the plan
// (e.g. `docker rm` with no containers exits non-zero).
IgnoreError bool
// DryRun, when true, signals the runtime to print the argv as a
// `# (dry-run)` comment instead of executing. Used for the macOS
// linux-builder qcow nuke until paths are verified on a live setup.
DryRun bool
}
PruneStep is one command in a prune plan.
func BuildCleanupSteps ¶
func BuildCleanupSteps(closures []LiveClosure) []PruneStep
BuildCleanupSteps wraps the reaper script in a docker-run step mounting the nix volume — the only namespace where the devcell roots and their volume-resident targets both resolve (CELL-333 lesson).
func BuildDockerPruneSteps ¶
BuildDockerPruneSteps composes the docker prune plan. Default mode is the cleandocker sequence (identical on Darwin and Linux). Force mode branches by OS.
func BuildNixPruneSteps ¶
BuildNixPruneSteps composes the nix prune plan. Default mode runs `nix-collect-garbage -d` + `nix-store --optimise` (via ssh on macOS, locally on Linux native). Force mode branches by OS (Darwin: dry-run qcow nuke plan; Linux: aggressive local GC).
type RankedEntry ¶
type RankedEntry struct {
Kind EntryKind
ID string
Label string // e.g. "devcell-user:ultimate-pure" or "nix profile install (truncated)"
SizeBytes int64
ReclaimBytes int64
PinCount int // >0 means "in use" — formatter hides reclaim hint
}
RankedEntry is the unified row type used by ranking + formatting. ReclaimBytes is the sort key — for images that's UniqueBytes; for everything else it's the full SizeBytes.
func RankEntries ¶
func RankEntries(snap DFSnapshot, topN int) []RankedEntry
RankEntries flattens the snapshot into a single list sorted by ReclaimBytes desc. topN <= 0 returns all entries.
type RunCleanupArgs ¶
type RunCleanupArgs struct {
Closures []LiveClosure
Exec func(step PruneStep) error
Out io.Writer
In io.Reader
SkipYes bool
IsTTY bool
}
RunCleanupArgs bundles inputs to RunCleanup, mirroring RunPruneArgs.
type RunDFArgs ¶
RunDFArgs bundles inputs to RunDF — keeps the call site readable (matches the pattern of RunPruneArgs).
type RunPruneArgs ¶
type RunPruneArgs struct {
Opts PruneOpts
Exec func(step PruneStep) error
Out io.Writer
In io.Reader
SkipYes bool // --yes / -y
IsTTY bool // term.IsTerminal(int(os.Stdin.Fd()))
}
RunPruneArgs bundles inputs to RunPrune. Keeps the call site readable when callers wire in real stdin/stdout/exec.
type RunSpec ¶
type RunSpec struct {
Config config.Config
CellCfg cfg.CellConfig
Binary string
DefaultFlags []string
UserArgs []string
Debug bool // pass DEVCELL_DEBUG=true into the container
NixDaemon bool // pass DEVCELL_NIX_DAEMON=true into the container
NoPorts bool // skip all -p port mappings (user ports and GUI)
TrustFlake bool // pass DEVCELL_FLAKE_TRUST=1 into the container
Image string // image ID or tag to run; defaults to UserImageTag
ExtraEnv map[string]string // additional env vars injected by the command handler
InheritEnv []string // env var names to inherit from host (passed as -e KEY with no value)
Getenv func(string) string // env lookup; defaults to os.Getenv when nil
GitConfig func(string) string // host `git config` lookup (cell.HostGitConfig); nil skips that tier
ThinImage bool // when true, mount devcell-nix-store volume for /nix
BootDir string // host-side boot dir for the Go-generated entrypoint script; empty disables the bind-mount
TTY bool // allocate a pseudo-TTY (-it); set from isatty check on stdin
Detach bool // run container in detached mode (-d); set by `cell start`
Lifecycle string // "persistent" (cell start) or "oneshot" (cell claude); empty defaults to "oneshot"
NoSecrets bool // skip `op run --` prefix and all secrets injection
ProxyEnabled bool // when true, use internal network and inject proxy env vars
KVMAutoDetected bool // daemon host has /dev/kvm; set by the boot-checklist probe
Policy cfg.Policy // isolation policy; nil defaults to OpenPolicy
}
RunSpec holds everything needed to build the docker run argv.
type VMDiskInfo ¶
VMDiskInfo holds Docker VM filesystem info from `docker run alpine df`.
func CollectVMDisk ¶
func CollectVMDisk(ctx context.Context) (VMDiskInfo, error)
CollectVMDisk probes the Docker VM filesystem size.
Source Files
¶
- boot_panel.go
- build.go
- build_label.go
- cleanup.go
- cleanup_docker.go
- closure_alive.go
- container_log_watcher.go
- df.go
- df_collect.go
- df_nix.go
- diagnostics.go
- docker_alive.go
- docker_debug.go
- engine.go
- exec.go
- init.go
- kvm_probe.go
- nix_cache_hydrate.go
- nix_health.go
- nix_health_phase.go
- proxy_sidecar.go
- prune.go
- run.go
- runner.go
- squid.go
- stale_cell.go
- thin_build.go
- thin_context.go
- thin_volume.go
- validate_proxy.go
- volume_hydrated.go
- volume_shell.go