engine
engine
Section titled “engine”import "github.com/thesimonho/warden/engine"Package engine wraps the Docker Engine API for discovering and managing Claude Code project containers.
- Constants
- Variables
- func ContainerWorkspaceDir(projectName string) string
- func DetectStaleMounts(original, current []api.Mount) []string
- func DisconnectKeyToByte(key string) byte
- func IsStaleMountsError(err error) bool
- func IsValidWorktreeID(id string) bool
- func ProjectCostFromContainerStatuses(statuses map[string]*agent.Status, workspacePrefix string) float64
- func ProjectID(hostPath string) (string, error)
- func ProjectIDFromURL(cloneURL string) (string, error)
- func ResolveProjectID(hostPath, cloneURL string) (string, error)
- func ValidProjectID(id string) bool
- func WorkspaceVolumeName(containerName string) string
- type AgentCostResult
- type AgentStatus
- type Client
- type ContainerHealth
- type EngineClient
- func NewClient(socketPath string, registry *agent.Registry) (*EngineClient, error)
- func (ec *EngineClient) APIClient() client.APIClient
- func (ec *EngineClient) ApplyNetworkIsolation(ctx context.Context, containerID, mode string, domains []string) error
- func (ec *EngineClient) CleanupEventDir(containerName string)
- func (ec *EngineClient) CleanupOrphanedWorktrees(ctx context.Context, containerID string) ([]string, error)
- func (ec *EngineClient) ConnectTerminal(ctx context.Context, containerID, worktreeID string, skipPermissions bool) (string, error)
- func (ec *EngineClient) ContainerIP(ctx context.Context, containerID string) (string, error)
- func (ec *EngineClient) ContainerStartupHealth(ctx context.Context, containerName string) (*ContainerHealth, error)
- func (ec *EngineClient) CopyFileToContainer(ctx context.Context, containerID, destDir, filename string, content io.Reader, _ int64) error
- func (ec *EngineClient) CreateContainer(ctx context.Context, req api.CreateContainerRequest) (string, error)
- func (ec *EngineClient) CreateWorktree(ctx context.Context, containerID, name string, skipPermissions bool) (string, error)
- func (ec *EngineClient) DeleteContainer(ctx context.Context, id string) error
- func (ec *EngineClient) DisconnectTerminal(ctx context.Context, containerID, worktreeID string) error
- func (ec *EngineClient) GetWorktreeDiff(ctx context.Context, containerID, worktreeID string) (*api.DiffResponse, error)
- func (ec *EngineClient) InspectContainer(ctx context.Context, id string) (*api.ContainerConfig, error)
- func (ec *EngineClient) IsEstimatedCost(ctx context.Context, containerID string) bool
- func (ec *EngineClient) KillWorktreeProcess(ctx context.Context, containerID, worktreeID string) error
- func (ec *EngineClient) ListProjects(ctx context.Context, names []string) ([]Project, error)
- func (ec *EngineClient) ListWorktrees(ctx context.Context, containerID string, skipEnrich bool) ([]Worktree, error)
- func (ec *EngineClient) Ping(ctx context.Context) error
- func (ec *EngineClient) PreWarmCLICache(ctx context.Context) error
- func (ec *EngineClient) ReadAgentCostAndBillingType(ctx context.Context, containerID, workspacePrefix string) (*AgentCostResult, error)
- func (ec *EngineClient) ReadAgentStatus(ctx context.Context, containerID string) (map[string]*agent.Status, error)
- func (ec *EngineClient) RecreateContainer(ctx context.Context, id string, req api.CreateContainerRequest) (string, error)
- func (ec *EngineClient) ReloadAllowedDomains(ctx context.Context, containerID string, domains []string) error
- func (ec *EngineClient) RemoveVolume(ctx context.Context, name string) error
- func (ec *EngineClient) RemoveWorktree(ctx context.Context, containerID, worktreeID string) error
- func (ec *EngineClient) RenameContainer(ctx context.Context, id string, newName string) error
- func (ec *EngineClient) ResetWorktree(ctx context.Context, containerID, worktreeID string) error
- func (ec *EngineClient) RestartProject(ctx context.Context, id string, originalMounts []api.Mount, networkMode string, allowedDomains []string) error
- func (ec *EngineClient) SendWorktreeInput(ctx context.Context, containerID, worktreeID, text string, pressEnter bool) error
- func (ec *EngineClient) SetEventBaseDir(dir string)
- func (ec *EngineClient) SetSeccompProfile(profileJSON string)
- func (ec *EngineClient) StopProject(ctx context.Context, id string) error
- func (ec *EngineClient) ValidateInfrastructure(ctx context.Context, containerID string) (bool, []string, error)
- func (ec *EngineClient) WaitForInstalls(ctx context.Context, containerID string) error
- func (ec *EngineClient) WatchContainerEvents(ctx context.Context, onStart func(containerID, containerName string))
- type InspectedMounts
- type NotificationType
- type Project
- type SessionCost
- type StaleMountsError
- type Worktree
- type WorktreeState
Constants
Section titled “Constants”ContainerHomeDir is the home directory for ContainerUser inside containers.
const ContainerHomeDir = constants.ContainerHomeDirContainerUser is the non-root user inside project containers.
const ContainerUser = constants.ContainerUserDefaultDisconnectKey is the default key to disconnect from a terminal.
const DefaultDisconnectKey = "ctrl+\\"Variables
Section titled “Variables”ErrNameTaken is returned when a container with the requested name already exists.
var ErrNameTaken = fmt.Errorf("container name already in use")TmuxSessionName returns the tmux session name for a worktree.
var TmuxSessionName = constants.TmuxSessionNamefunc ContainerWorkspaceDir
Section titled “func ContainerWorkspaceDir”func ContainerWorkspaceDir(projectName string) stringContainerWorkspaceDir computes the container-side workspace path for a project. New containers mount at /home/warden/<name> to give each project a unique path in the agent’s config file (which keys cost data by workspace path).
func DetectStaleMounts
Section titled “func DetectStaleMounts”func DetectStaleMounts(original, current []api.Mount) []stringDetectStaleMounts re-resolves the original (pre-resolution) mount specs and compares the result with the container’s current resolved mounts. Returns a list of container paths where the current mount differs from what a fresh resolution would produce.
This detects ANY divergence — deleted targets, changed symlink targets, new symlinks, or removed symlinks — not just missing files.
func DisconnectKeyToByte
Section titled “func DisconnectKeyToByte”func DisconnectKeyToByte(key string) byteDisconnectKeyToByte converts a “ctrl+<char>” string to its control character byte. Returns 0 if the format is invalid. Supports:
- ctrl+a through ctrl+z (0x01–0x1a)
- ctrl+[ (0x1b, ESC) — not recommended
- ctrl+\ (0x1c, default)
- ctrl+] (0x1d)
- ctrl+^ (0x1e)
- ctrl+_ (0x1f)
func IsStaleMountsError
Section titled “func IsStaleMountsError”func IsStaleMountsError(err error) boolIsStaleMountsError reports whether err is a StaleMountsError.
func IsValidWorktreeID
Section titled “func IsValidWorktreeID”func IsValidWorktreeID(id string) boolIsValidWorktreeID validates worktree IDs (alphanumeric start, then alphanumeric/hyphens/underscores/dots).
func ProjectCostFromContainerStatuses
Section titled “func ProjectCostFromContainerStatuses”func ProjectCostFromContainerStatuses(statuses map[string]*agent.Status, workspacePrefix string) float64ProjectCostFromContainerStatuses sums cost only for entries whose path starts with the given workspace prefix. This filters out host project entries that appear in the bind-mounted .claude.json but don’t belong to this container.
func ProjectID
Section titled “func ProjectID”func ProjectID(hostPath string) (string, error)ProjectID computes a deterministic project identifier from a host directory path. The ID is the first 12 hex characters of the SHA-256 hash of the cleaned, absolute path. Trailing slashes are stripped before hashing.
The caller is responsible for resolving symlinks (via filepath.EvalSymlinks) before calling this function — symlink resolution requires filesystem access which is inappropriate at this level.
func ProjectIDFromURL
Section titled “func ProjectIDFromURL”func ProjectIDFromURL(cloneURL string) (string, error)ProjectIDFromURL computes a deterministic project identifier from a git clone URL. The URL is normalized (lowercase host, stripped trailing .git and slash) before hashing so that equivalent URLs produce the same ID.
func ResolveProjectID
Section titled “func ResolveProjectID”func ResolveProjectID(hostPath, cloneURL string) (string, error)ResolveProjectID computes the deterministic project ID from either a clone URL (remote project) or an absolute host path (local project).
func ValidProjectID
Section titled “func ValidProjectID”func ValidProjectID(id string) boolValidProjectID reports whether id is a valid project identifier (exactly 12 lowercase hex characters).
func WorkspaceVolumeName
Section titled “func WorkspaceVolumeName”func WorkspaceVolumeName(containerName string) stringWorkspaceVolumeName returns the Docker volume name for a remote project’s persistent workspace.
type AgentCostResult
Section titled “type AgentCostResult”AgentCostResult holds cost and billing type from a single config read.
type AgentCostResult struct { TotalCost float64 IsEstimated bool // Sessions holds per-session cost breakdown, keyed by session ID. // Used for session-keyed DB persistence. Sessions []SessionCost}type AgentStatus
Section titled “type AgentStatus”AgentStatus represents whether the agent CLI is actively running inside a container.
type AgentStatus stringconst ( // AgentStatusIdle means no agent process is running. AgentStatusIdle AgentStatus = "idle" // AgentStatusWorking means an agent process is currently active. AgentStatusWorking AgentStatus = "working" // AgentStatusUnknown means the status could not be determined. AgentStatusUnknown AgentStatus = "unknown")type Client
Section titled “type Client”Client defines the interface for interacting with Docker containers. All methods accept a context for cancellation and timeout control.
type Client interface { // ListProjects returns projects for the given container names, enriched with // live Docker state. Names not found in Docker are returned with HasContainer: false. ListProjects(ctx context.Context, names []string) ([]Project, error)
// StopProject gracefully stops the container with the given ID. StopProject(ctx context.Context, id string) error
// RestartProject restarts the container with the given ID and re-applies // network isolation if needed. originalMounts are the pre-symlink-resolution // mount specs from the DB, used to detect stale bind mounts before restarting. // networkMode and allowedDomains are read from the DB so that network // isolation can be re-applied after the container restarts. RestartProject(ctx context.Context, id string, originalMounts []api.Mount, networkMode string, allowedDomains []string) error
// CreateContainer creates and starts a new project container. CreateContainer(ctx context.Context, req api.CreateContainerRequest) (string, error)
// DeleteContainer stops and removes a container. DeleteContainer(ctx context.Context, id string) error
// CleanupEventDir removes the bind-mounted event directory for a container. CleanupEventDir(containerName string)
// InspectContainer returns the editable configuration of a container. InspectContainer(ctx context.Context, id string) (*api.ContainerConfig, error)
// ContainerIP returns the bridge network IP address of a running container. ContainerIP(ctx context.Context, containerID string) (string, error)
// RenameContainer changes the name of an existing container without recreation. RenameContainer(ctx context.Context, id string, newName string) error
// ReloadAllowedDomains re-runs the network isolation script inside a // running container to update the allowed domain list without recreation. // Uses privileged docker exec since the container lacks NET_ADMIN. ReloadAllowedDomains(ctx context.Context, containerID string, domains []string) error
// WaitForInstalls polls for the install-complete marker written by the // container entrypoint after agent CLI and runtime installs finish. WaitForInstalls(ctx context.Context, containerID string) error
// ApplyNetworkIsolation runs the network isolation script via privileged // docker exec. Used after container start/restart to set up iptables // without granting NET_ADMIN to the container. ApplyNetworkIsolation(ctx context.Context, containerID, mode string, domains []string) error
// RecreateContainer replaces a stopped container with a new one using updated config. // Returns the new container ID. RecreateContainer(ctx context.Context, id string, req api.CreateContainerRequest) (string, error)
// ListWorktrees returns all worktrees for the given container with their terminal state. // When skipEnrich is true, the expensive batch docker exec for terminal state is skipped // (the caller is expected to overlay state from the event bus store instead). ListWorktrees(ctx context.Context, containerID string, skipEnrich bool) ([]Worktree, error)
// CreateWorktree creates a new git worktree inside the container and connects a terminal. // When skipPermissions is true, Claude Code runs with --dangerously-skip-permissions. // Returns the worktree ID on success. CreateWorktree(ctx context.Context, containerID, name string, skipPermissions bool) (string, error)
// ConnectTerminal starts a terminal for a worktree inside the container. // When skipPermissions is true, Claude Code runs with --dangerously-skip-permissions. // Returns the worktree ID on success. ConnectTerminal(ctx context.Context, containerID, worktreeID string, skipPermissions bool) (string, error)
// DisconnectTerminal pushes a disconnect event and cleans up tracking state. // The tmux session (and Claude/bash) continues running in the background. DisconnectTerminal(ctx context.Context, containerID, worktreeID string) error
// KillWorktreeProcess kills the tmux session for a worktree, destroying // the process entirely. The git worktree directory on disk is preserved. KillWorktreeProcess(ctx context.Context, containerID, worktreeID string) error
// SendWorktreeInput sends text to a worktree's tmux pane. Uses literal mode // to prevent key-name interpretation. If pressEnter is true, sends Enter after the text. SendWorktreeInput(ctx context.Context, containerID, worktreeID, text string, pressEnter bool) error
// ResetWorktree clears all history for a worktree without removing it. // Kills the process, clears JSONL session files, and removes terminal // tracking state. ResetWorktree(ctx context.Context, containerID, worktreeID string) error
// RemoveWorktree fully removes a worktree: kills any running processes, // runs `git worktree remove`, and cleans up tracking state. Cannot remove // the "main" worktree. RemoveWorktree(ctx context.Context, containerID, worktreeID string) error
// CleanupOrphanedWorktrees removes worktree directories from .claude/worktrees/ // that are not tracked by git. Returns the list of removed worktree IDs. CleanupOrphanedWorktrees(ctx context.Context, containerID string) ([]string, error)
// ValidateInfrastructure checks whether a container has the required Warden // terminal infrastructure installed (tmux, gosu, create-terminal.sh, etc). // Returns true if all binaries are present, along with the list of missing items. ValidateInfrastructure(ctx context.Context, containerID string) (bool, []string, error)
// GetWorktreeDiff returns uncommitted changes (tracked + untracked) for a // worktree inside the container as a unified diff with per-file statistics. GetWorktreeDiff(ctx context.Context, containerID, worktreeID string) (*api.DiffResponse, error)
// ReadAgentStatus reads the agent config file from a running container // and returns per-project status data keyed by working directory path. // Used as a fallback cost source when the event bus has no data. ReadAgentStatus(ctx context.Context, containerID string) (map[string]*agent.Status, error)
// IsEstimatedCost returns true when a container's cost is estimated // (subscription user) rather than actual API spend (API key user). IsEstimatedCost(ctx context.Context, containerID string) bool
// ReadAgentCostAndBillingType reads the agent config once and returns // both cost (filtered by workspace prefix) and billing type. ReadAgentCostAndBillingType(ctx context.Context, containerID, workspacePrefix string) (*AgentCostResult, error)
// ContainerStartupHealth inspects a container's state to determine if it // is crash-looping. When the container is restarting, reads the last lines // of container logs to capture the error. Used by the liveness checker to // enrich stale-heartbeat audit events with diagnostic details. ContainerStartupHealth(ctx context.Context, containerName string) (*ContainerHealth, error)
// CopyFileToContainer writes a single file into a running container. // Uses exec+stdin (sh -c 'cat > file') instead of the Docker tar archive API. // Used by the clipboard upload feature to stage images for the xclip shim. CopyFileToContainer(ctx context.Context, containerID, destDir, filename string, content io.Reader, size int64) error
// RemoveVolume removes a Docker named volume. Used to clean up workspace // volumes for remote projects when their container is deleted. Errors are // logged but not fatal — the volume may not exist (temporary projects). RemoveVolume(ctx context.Context, name string) error}type ContainerHealth
Section titled “type ContainerHealth”ContainerHealth describes a container’s startup health state. Used by the liveness checker to diagnose crash-looping containers.
type ContainerHealth struct { // Restarting is true when the container is in a Docker restart loop. Restarting bool // RestartCount is the number of times Docker has restarted the container. RestartCount int // ExitCode is the last exit code from the container's entrypoint. ExitCode int // OOMKilled is true if the container was killed due to memory limits. OOMKilled bool // LogTail contains the last lines of container logs (only populated when unhealthy). LogTail string}type EngineClient
Section titled “type EngineClient”EngineClient wraps the Docker Engine SDK client for container operations.
type EngineClient struct { // contains filtered or unexported fields}func NewClient
Section titled “func NewClient”func NewClient(socketPath string, registry *agent.Registry) (*EngineClient, error)NewClient creates an EngineClient using the given socket path. The registry maps agent type names to StatusProvider implementations. When socketPath is empty, falls back to client.FromEnv (default Docker behavior).
The socketPath can be an absolute Unix path (/var/run/docker.sock), a Windows named pipe (//./pipe/docker_engine), or a URI with scheme (unix://, npipe://, tcp://).
func (*EngineClient) APIClient
Section titled “func (*EngineClient) APIClient”func (ec *EngineClient) APIClient() client.APIClientAPIClient returns the underlying Docker API client. Used by the terminal proxy to create exec sessions with TTY mode.
func (*EngineClient) ApplyNetworkIsolation
Section titled “func (*EngineClient) ApplyNetworkIsolation”func (ec *EngineClient) ApplyNetworkIsolation(ctx context.Context, containerID, mode string, domains []string) errorApplyNetworkIsolation runs the network isolation script via privileged docker exec. Used after container start/restart to set up iptables without granting NET_ADMIN to the container’s capability set. This makes network isolation tamper-proof — even root inside the container cannot modify iptables rules.
func (*EngineClient) CleanupEventDir
Section titled “func (*EngineClient) CleanupEventDir”func (ec *EngineClient) CleanupEventDir(containerName string)CleanupEventDir removes the event directory for a container. Called after a container is deleted to prevent orphaned directories.
func (*EngineClient) CleanupOrphanedWorktrees
Section titled “func (*EngineClient) CleanupOrphanedWorktrees”func (ec *EngineClient) CleanupOrphanedWorktrees(ctx context.Context, containerID string) ([]string, error)CleanupOrphanedWorktrees tidies up worktree-related state in the container:
- Prunes git worktree metadata for directories that no longer exist on disk.
- Removes .claude/worktrees/ directories not tracked by git (leftovers from kill-worktree.sh running before Claude could call `git worktree remove`).
- Removes .warden/terminals/<id>/ directories whose tmux sessions are dead OR whose worktree directories no longer exist on disk (orphaned by Claude running `git worktree remove` inside the container). Kills orphaned tmux sessions before removing their tracking directories.
Returns the deduplicated list of removed worktree IDs from steps 2 and 3.
func (*EngineClient) ConnectTerminal
Section titled “func (*EngineClient) ConnectTerminal”func (ec *EngineClient) ConnectTerminal(ctx context.Context, containerID, worktreeID string, skipPermissions bool) (string, error)ConnectTerminal starts a terminal for a worktree inside the container. If a tmux session is still alive (background state), the WebSocket proxy will attach to it. Otherwise runs create-terminal.sh which starts a tmux session and launches the agent. When skipPermissions is true, Claude Code runs with —dangerously-skip-permissions.
func (*EngineClient) ContainerIP
Section titled “func (*EngineClient) ContainerIP”func (ec *EngineClient) ContainerIP(ctx context.Context, containerID string) (string, error)ContainerIP returns the bridge network IP address of a running container. Returns an error if the container has no bridge network or the IP is empty (e.g. container is stopped).
func (*EngineClient) ContainerStartupHealth
Section titled “func (*EngineClient) ContainerStartupHealth”func (ec *EngineClient) ContainerStartupHealth(ctx context.Context, containerName string) (*ContainerHealth, error)ContainerStartupHealth inspects a container to determine if it is crash-looping and, if so, captures the last log lines for diagnostics.
func (*EngineClient) CopyFileToContainer
Section titled “func (*EngineClient) CopyFileToContainer”func (ec *EngineClient) CopyFileToContainer(ctx context.Context, containerID, destDir, filename string, content io.Reader, _ int64) errorCopyFileToContainer writes a single file into a running container via exec. Creates intermediate directories if needed. Runs as the container user so file ownership is correct for the agent process.
func (*EngineClient) CreateContainer
Section titled “func (*EngineClient) CreateContainer”func (ec *EngineClient) CreateContainer(ctx context.Context, req api.CreateContainerRequest) (string, error)CreateContainer creates and starts a new project container with the given configuration. Returns the container ID (truncated to 12 chars).
func (*EngineClient) CreateWorktree
Section titled “func (*EngineClient) CreateWorktree”func (ec *EngineClient) CreateWorktree(ctx context.Context, containerID, name string, skipPermissions bool) (string, error)CreateWorktree creates a new worktree terminal inside the container. Claude Code’s —worktree flag handles git worktree creation and isolation, so the worktree won’t exist in git yet — we skip the orphan check. When skipPermissions is true, Claude Code runs with —dangerously-skip-permissions.
func (*EngineClient) DeleteContainer
Section titled “func (*EngineClient) DeleteContainer”func (ec *EngineClient) DeleteContainer(ctx context.Context, id string) errorDeleteContainer stops and removes a container, clearing its git repo cache entry.
func (*EngineClient) DisconnectTerminal
Section titled “func (*EngineClient) DisconnectTerminal”func (ec *EngineClient) DisconnectTerminal(ctx context.Context, containerID, worktreeID string) errorDisconnectTerminal pushes a disconnect event and cleans up tracking state. The tmux session (and Claude/bash running inside it) continues in the background.
func (*EngineClient) GetWorktreeDiff
Section titled “func (*EngineClient) GetWorktreeDiff”func (ec *EngineClient) GetWorktreeDiff(ctx context.Context, containerID, worktreeID string) (*api.DiffResponse, error)GetWorktreeDiff returns the uncommitted changes (tracked + untracked) for a worktree inside the container. Uses a temporary index copy so the real index is never modified.
func (*EngineClient) InspectContainer
Section titled “func (*EngineClient) InspectContainer”func (ec *EngineClient) InspectContainer(ctx context.Context, id string) (*api.ContainerConfig, error)InspectContainer returns the editable configuration of an existing container by parsing its inspect data (binds, env vars, labels).
func (*EngineClient) IsEstimatedCost
Section titled “func (*EngineClient) IsEstimatedCost”func (ec *EngineClient) IsEstimatedCost(ctx context.Context, containerID string) boolIsEstimatedCost checks whether a container is using estimated cost (subscription user) vs actual API cost. Reads oauthAccount.billingType from .claude.json — “stripe_subscription” means estimated cost. Falls back to true (estimated) if the billing type can’t be determined.
func (*EngineClient) KillWorktreeProcess
Section titled “func (*EngineClient) KillWorktreeProcess”func (ec *EngineClient) KillWorktreeProcess(ctx context.Context, containerID, worktreeID string) errorKillWorktreeProcess kills the tmux session for a worktree, destroying the process entirely. The git worktree directory on disk is preserved. Use DisconnectTerminal to only disconnect the viewer and keep the session alive.
func (*EngineClient) ListProjects
Section titled “func (*EngineClient) ListProjects”func (ec *EngineClient) ListProjects(ctx context.Context, names []string) ([]Project, error)ListProjects fetches Docker state for the given container names. Names not found in Docker are returned with HasContainer: false. The returned order matches the input name order.
func (*EngineClient) ListWorktrees
Section titled “func (*EngineClient) ListWorktrees”func (ec *EngineClient) ListWorktrees(ctx context.Context, containerID string, skipEnrich bool) ([]Worktree, error)ListWorktrees returns all worktrees for the given container with their terminal state. For git repos, discovers worktrees via `git worktree list —porcelain`. For non-git repos, returns a single implicit worktree at /project. When skipEnrich is true, the expensive batch docker exec for terminal state is skipped.
func (*EngineClient) Ping
Section titled “func (*EngineClient) Ping”func (ec *EngineClient) Ping(ctx context.Context) errorPing checks whether the Docker daemon is reachable.
func (*EngineClient) PreWarmCLICache
Section titled “func (*EngineClient) PreWarmCLICache”func (ec *EngineClient) PreWarmCLICache(ctx context.Context) errorPreWarmCLICache downloads pinned agent CLIs into the warden-cache volume using throwaway containers. Both agent types run in parallel. Subsequent container creates get a cache hit and skip the download.
func (*EngineClient) ReadAgentCostAndBillingType
Section titled “func (*EngineClient) ReadAgentCostAndBillingType”func (ec *EngineClient) ReadAgentCostAndBillingType(ctx context.Context, containerID, workspacePrefix string) (*AgentCostResult, error)ReadAgentCostAndBillingType reads the agent config file once and extracts both cost (filtered by workspace prefix) and billing type. Returns per-session cost breakdown for session-keyed DB persistence.
func (*EngineClient) ReadAgentStatus
Section titled “func (*EngineClient) ReadAgentStatus”func (ec *EngineClient) ReadAgentStatus(ctx context.Context, containerID string) (map[string]*agent.Status, error)ReadAgentStatus reads the agent config file from a running container and extracts per-project status data. Returns a map keyed by the working directory path inside the container.
This is the Go-side equivalent of the jq extraction in warden-event.sh, but more reliable: it uses proper JSON parsing, doesn’t depend on WARDEN_EVENT_DIR being set, and runs from the host via docker exec.
func (*EngineClient) RecreateContainer
Section titled “func (*EngineClient) RecreateContainer”func (ec *EngineClient) RecreateContainer(ctx context.Context, id string, req api.CreateContainerRequest) (string, error)RecreateContainer replaces a stopped container with a new one using updated config. The old container is renamed to a temporary name before creating the replacement, so it can be restored if the create fails (atomic swap).
func (*EngineClient) ReloadAllowedDomains
Section titled “func (*EngineClient) ReloadAllowedDomains”func (ec *EngineClient) ReloadAllowedDomains(ctx context.Context, containerID string, domains []string) errorReloadAllowedDomains re-runs the network isolation script inside a running container to update the allowed domain list without recreation. Delegates to ApplyNetworkIsolation with restricted mode hardcoded (the only mode that uses domain hot-reload).
func (*EngineClient) RemoveVolume
Section titled “func (*EngineClient) RemoveVolume”func (ec *EngineClient) RemoveVolume(ctx context.Context, name string) errorRemoveVolume removes a Docker named volume. Used to clean up workspace volumes for remote projects when their container is deleted.
func (*EngineClient) RemoveWorktree
Section titled “func (*EngineClient) RemoveWorktree”func (ec *EngineClient) RemoveWorktree(ctx context.Context, containerID, worktreeID string) errorRemoveWorktree fully removes a worktree: kills any running tmux session, runs `git worktree remove —force`, and cleans up the .warden/terminals/ tracking directory. Cannot remove the “main” worktree.
Tolerates missing git worktrees (e.g. when Claude already ran `git worktree remove` inside the container). In that case, git metadata is pruned and the terminal tracking directory is still cleaned up.
func (*EngineClient) RenameContainer
Section titled “func (*EngineClient) RenameContainer”func (ec *EngineClient) RenameContainer(ctx context.Context, id string, newName string) errorRenameContainer changes the name of an existing container without recreation.
func (*EngineClient) ResetWorktree
Section titled “func (*EngineClient) ResetWorktree”func (ec *EngineClient) ResetWorktree(ctx context.Context, containerID, worktreeID string) errorResetWorktree clears all history for a worktree without removing it from disk. It kills any running tmux session, removes the terminal tracking directory (exit_code, inner-cmd.sh), and deletes agent JSONL session files so that the FileTailer won’t replay old events on restart.
func (*EngineClient) RestartProject
Section titled “func (*EngineClient) RestartProject”func (ec *EngineClient) RestartProject(ctx context.Context, id string, originalMounts []api.Mount, networkMode string, allowedDomains []string) errorRestartProject restarts a container and re-applies network isolation. Before restarting, it validates that all bind mount source paths still exist on the host. If any are stale, the restart is blocked with a StaleMountsError so the caller can warn the user.
After the restart completes, network isolation is re-applied via privileged docker exec if the project uses restricted or none mode. Iptables rules don’t persist across container restarts, so they must be re-established every time.
originalMounts are the pre-symlink-resolution mount specs from the DB. When nil, mount validation is skipped (container predates the migration).
func (*EngineClient) SendWorktreeInput
Section titled “func (*EngineClient) SendWorktreeInput”func (ec *EngineClient) SendWorktreeInput(ctx context.Context, containerID, worktreeID, text string, pressEnter bool) errorSendWorktreeInput sends text to a worktree’s tmux pane. Uses `tmux send-keys -l` (literal mode) to prevent tmux key-name interpretation. If pressEnter is true, sends a separate Enter keystroke after the text.
func (*EngineClient) SetEventBaseDir
Section titled “func (*EngineClient) SetEventBaseDir”func (ec *EngineClient) SetEventBaseDir(dir string)SetEventBaseDir configures the host-side base directory for event files. Each container gets a subdirectory at <baseDir>/<containerName>/events/ that is bind-mounted into the container at /var/warden/events/.
func (*EngineClient) SetSeccompProfile
Section titled “func (*EngineClient) SetSeccompProfile”func (ec *EngineClient) SetSeccompProfile(profileJSON string)SetSeccompProfile configures the inline seccomp profile JSON for new containers. Docker’s API applies it via SecurityOpt.
func (*EngineClient) StopProject
Section titled “func (*EngineClient) StopProject”func (ec *EngineClient) StopProject(ctx context.Context, id string) errorStopProject gracefully stops a container with a 30-second timeout.
func (*EngineClient) ValidateInfrastructure
Section titled “func (*EngineClient) ValidateInfrastructure”func (ec *EngineClient) ValidateInfrastructure(ctx context.Context, containerID string) (bool, []string, error)ValidateInfrastructure checks whether a container has the required Warden terminal infrastructure installed. Uses POSIX `test -x` to check each binary so it works in minimal containers without `which`.
func (*EngineClient) WaitForInstalls
Section titled “func (*EngineClient) WaitForInstalls”func (ec *EngineClient) WaitForInstalls(ctx context.Context, containerID string) errorWaitForInstalls polls the container for the install-complete marker written by entrypoint.sh. This ensures network isolation is not applied while downloads are in progress. Returns nil once the marker exists, or an error on timeout/context cancellation.
func (*EngineClient) WatchContainerEvents
Section titled “func (*EngineClient) WatchContainerEvents”func (ec *EngineClient) WatchContainerEvents(ctx context.Context, onStart func(containerID, containerName string))WatchContainerEvents subscribes to Docker container start events and calls onStart for each Warden-managed container that starts. This catches auto-restarts by the Docker daemon (restart policy: unless-stopped) so the Go server can re-apply network isolation.
The watcher reconnects automatically on errors with exponential backoff. It runs until the context is cancelled.
type InspectedMounts
Section titled “type InspectedMounts”InspectedMounts holds the parsed mount information from a Docker container inspect response. Consolidates the two-phase pattern (parse HostConfig.Binds, then scan info.Mounts for structured entries) into a single pass.
type InspectedMounts struct { // ProjectPath is the host path mounted at the workspace directory, // or empty for remote projects (which use Docker volumes). ProjectPath string // Mounts are the non-workspace, non-warden-internal bind mounts. Mounts []api.Mount}type NotificationType
Section titled “type NotificationType”NotificationType is re-exported from event/ for backward compatibility.
type NotificationType = event.NotificationTypetype Project
Section titled “type Project”Project represents a project tracked by Warden, optionally backed by a Docker container. ProjectID is the stable identity (deterministic hash of host path or clone URL). ID is the Docker container ID (empty when HasContainer is false).
type Project struct { // ProjectID is the deterministic project identifier (sha256 of host path or clone URL, 12 hex chars). ProjectID string `json:"projectId"` // ID is the Docker container ID (empty when no container exists). ID string `json:"id"` // Name is the user-chosen display label / Docker container name. Name string `json:"name"` // HostPath is the absolute host directory mounted into the container (local projects only). HostPath string `json:"hostPath,omitempty"` // CloneURL is the git repository URL to clone (remote projects only). CloneURL string `json:"cloneURL,omitempty"` // Temporary is true when a remote project's workspace is ephemeral. Temporary bool `json:"temporary,omitempty"` // HasContainer is true when a Docker container is associated with this project. HasContainer bool `json:"hasContainer"` Type string `json:"type"` Image string `json:"image"` OS string `json:"os"` CreatedAt int64 `json:"createdAt"` SSHPort string `json:"sshPort"` State string `json:"state"` Status string `json:"status"` AgentStatus AgentStatus `json:"agentStatus"` // NeedsInput is true when any worktree requires user attention. NeedsInput bool `json:"needsInput,omitempty"` // NotificationType indicates why Claude needs attention (e.g. permission_prompt, idle_prompt). NotificationType NotificationType `json:"notificationType,omitempty"` // ActiveWorktreeCount is the number of worktrees with connected terminals. ActiveWorktreeCount int `json:"activeWorktreeCount"` // TotalCost is the aggregate cost across all worktrees in USD (from agent status provider). TotalCost float64 `json:"totalCost"` // IsEstimatedCost is true when the cost is an estimate (e.g. subscription users). // When false, the cost reflects actual API spend. IsEstimatedCost bool `json:"isEstimatedCost,omitempty"` // CostBudget is the per-project cost limit in USD (0 = use global default). CostBudget float64 `json:"costBudget"` // IsGitRepo indicates whether the container's /project is a git repository. IsGitRepo bool `json:"isGitRepo"` // AgentType identifies the CLI agent running in this project (e.g. "claude-code", "codex"). AgentType constants.AgentType `json:"agentType"` // SkipPermissions indicates whether terminals should skip permission prompts. SkipPermissions bool `json:"skipPermissions"` // MountedDir is the host directory mounted into the container. MountedDir string `json:"mountedDir,omitempty"` // WorkspaceDir is the container-side workspace directory (mount destination). WorkspaceDir string `json:"workspaceDir,omitempty"` // NetworkMode controls the container's network isolation level. NetworkMode api.NetworkMode `json:"networkMode"` // AllowedDomains lists domains accessible when NetworkMode is "restricted". AllowedDomains []string `json:"allowedDomains,omitempty"` // AgentVersion is the pinned CLI version installed in this container. AgentVersion string `json:"agentVersion,omitempty"` // ForwardedPorts lists container ports exposed via the reverse proxy. ForwardedPorts []int `json:"forwardedPorts,omitempty"`}type SessionCost
Section titled “type SessionCost”SessionCost holds cost data for a single agent session.
type SessionCost struct { SessionID string Cost float64}type StaleMountsError
Section titled “type StaleMountsError”StaleMountsError is returned by RestartProject when the container’s bind mounts no longer match what a fresh symlink resolution would produce. This typically happens when a dotfile manager changes symlink targets after the container was created.
Starting a container with stale mounts causes Claude Code to see unreadable or outdated config files. If Claude Code cannot read its settings, it performs a fresh write that overwrites the host’s settings through the read-write parent directory mount — destroying user hooks, permissions, and preferences.
The container must be recreated to pick up the current symlink targets.
type StaleMountsError struct { // StalePaths lists the container-side mount paths whose host-side // sources have diverged from a fresh resolution. StalePaths []string}func (*StaleMountsError) Error
Section titled “func (*StaleMountsError) Error”func (e *StaleMountsError) Error() stringError implements the error interface.
type Worktree
Section titled “type Worktree”Worktree represents a git worktree (or implicit project root) with its terminal state.
type Worktree struct { // ID is the worktree identifier — directory name for git worktrees, "main" for project root. ID string `json:"id"` // ProjectID is the container ID this worktree belongs to. ProjectID string `json:"projectId"` // Path is the filesystem path inside the container. Path string `json:"path"` // Branch is the git branch checked out in this worktree. Branch string `json:"branch,omitempty"` // State is the terminal connection state (connected, shell, background, stopped). State WorktreeState `json:"state"` // ExitCode is the agent's exit code when in shell state. // Nil means the agent is still running (or no exit code captured). ExitCode *int `json:"exitCode,omitempty"` // NeedsInput is true when Claude is blocked waiting for user attention. NeedsInput bool `json:"needsInput,omitempty"` // NotificationType indicates why Claude needs attention. NotificationType NotificationType `json:"notificationType,omitempty"`}type WorktreeState
Section titled “type WorktreeState”WorktreeState represents the terminal connection state of a worktree.
type WorktreeState stringconst ( // WorktreeStateConnected means a terminal is running with Claude active. WorktreeStateConnected WorktreeState = "connected" // WorktreeStateShell means the agent exited but the bash shell is still alive. WorktreeStateShell WorktreeState = "shell" // WorktreeStateBackground means the tmux session is alive but no viewer is // connected (e.g. browser closed). Claude Code may still be working. WorktreeStateBackground WorktreeState = "background" // WorktreeStateStopped means no terminal process is running. WorktreeStateStopped WorktreeState = "stopped")Generated by gomarkdoc