// Package docker runs a one-shot Claude Code session inside a container. The // Runner interface keeps dispatch logic testable without a real Docker daemon. package docker import ( "context" "time" ) // Job fully describes a single containerised Claude session. type Job struct { // Label is a short identifier used for logging and the job directory name. Label string // Image is the container image to run. Image string // ContainerHome is the home directory inside Image (mount target root). ContainerHome string // Prompt is the full instruction handed to `claude --print`. Prompt string // CloneURL is the plain HTTPS clone URL of the repo to work in // (e.g. https://git.unkin.net/unkin/teabot.git). Auth is supplied via a // git credential store built from Token, never embedded in this URL. CloneURL string // GitHost is the host used for the credential store entry (e.g. git.unkin.net). GitHost string // GitName / GitEmail set the container's commit identity. GitName string GitEmail string // GitUser is the bot's Gitea username (credential store user). GitUser string // Token is the bot's Gitea token, used for git push and (indirectly) tea. Token string // TeaConfigPath is the host path to the personality's tea config.yml, // mounted so tea acts as this identity inside the container. TeaConfigPath string // ClaudeConfigDir is the host directory holding Claude Code credentials. ClaudeConfigDir string // AnthropicAPIKey / AnthropicBaseURL, when set, are injected as env vars // instead of relying on the mounted subscription credentials. AnthropicAPIKey string AnthropicBaseURL string // Timeout bounds the session. Timeout time.Duration } // Result captures the outcome of a job. type Result struct { ExitCode int Output string Duration time.Duration // TimedOut is true when the job was killed for exceeding Timeout. TimedOut bool } // Runner executes jobs. DockerRunner is the production implementation; tests // substitute a fake. type Runner interface { Run(ctx context.Context, job Job) (Result, error) }