Documentation
¶
Overview ¶
Package kit stages a docker-agent kit on the host before launching a sandbox.
A kit is a self-contained directory that bundles every host resource an agent will need at runtime — local skills, AGENTS.md/CLAUDE.md prompt files, sub-agent YAMLs — laid out under a fixed schema:
<kit>/skills/<skill-name>/ # local skills, recursively <kit>/prompt_files/<name> # collected add_prompt_files inputs <kit>/manifest.json # debug + cache key
The host stages the kit, redacts secrets via portcullis.Redact in every text file, and bind-mounts the kit read-only inside the sandbox. At runtime, the in-sandbox resolvers (skills.Load, promptfiles.Paths) consult skills.KitDirEnv to read from the kit instead of the user's $HOME — which doesn't exist inside the sandbox.
The kit solves four constraints inherent to the docker sandbox CLI:
- the user's $HOME inside the sandbox is unrelated to the host's;
- sandbox mounts target directories, not individual files;
- host files may contain secrets that must not leak;
- other host-only state (e.g. .agents/skills under a parent dir) is unreachable from the sandbox.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Entry ¶
type Entry struct {
// Source is the original host path. Omitted from the on-disk
// manifest so the sandbox cannot learn the host layout.
Source string `json:"-"`
// Target is the path relative to the kit root. Empty when the
// file isn't staged into the kit because it's already reachable
// inside the sandbox via the live workspace mount.
Target string `json:"target,omitempty"`
}
Entry records one staged file or directory.
type Manifest ¶
type Manifest struct {
AgentRef string `json:"agent_ref"`
BuiltAt time.Time `json:"built_at"`
Skills []Entry `json:"skills,omitempty"`
PromptFiles []Entry `json:"prompt_files,omitempty"`
Redactions []Redaction `json:"redactions,omitempty"`
}
Manifest is the kit's table of contents.
type Options ¶
type Options struct {
// AgentRef is the user-facing reference to the agent (a YAML path,
// an OCI ref, a URL or a builtin name). Used for cache keying and
// for loading the team config so the kit knows which prompt files
// and skills to ship.
AgentRef string
// EnvProvider is forwarded to [config.Resolve] so URL-sourced
// agents can pick up GITHUB_TOKEN. May be nil.
EnvProvider environment.Provider
// HostCwd is the host's working directory. Prompt-file lookups
// walk up from it the same way the in-sandbox runtime would.
HostCwd string
// HostHome overrides the host's $HOME for prompt-file lookups.
// Empty means "use os.UserHomeDir".
HostHome string
// Workspace is the absolute host path that the sandbox mounts as
// the agent's live working directory. Files under it are not
// staged into the kit because the sandbox sees them through the
// live mount; staging them would duplicate content and ship a
// stale, redacted copy alongside the live one.
Workspace string
// CacheDir is the parent directory under which the kit will be
// staged. Empty means "use [paths.GetCacheDir]/sandbox-kits".
CacheDir string
}
Options describes a kit build.
type Redaction ¶
type Redaction struct {
// Source is the host path of the original file. Omitted from the
// on-disk manifest for the same reason as [Entry.Source].
Source string `json:"-"`
// Target is the path relative to the kit root.
Target string `json:"target"`
}
Redaction records that portcullis added at least one portcullis.Marker to the staged copy of a file.
type Result ¶
type Result struct {
// HostDir is the absolute host path of the staged kit. Mount it
// read-only into the sandbox (the sandbox CLI exposes extras at
// the same path as on the host) and forward
// `-e DOCKER_AGENT_KIT_DIR=<HostDir>` so the in-sandbox resolvers
// find it.
HostDir string
// Manifest describes what was staged. It contains absolute host
// source paths and is meant for caller-side inspection only — the
// on-disk copy under <HostDir>/manifest.json is sanitised so the
// sandbox cannot learn the host filesystem layout.
Manifest Manifest
// NeedsToolInstall reports whether the agent has at least one
// MCP / LSP toolset that the in-sandbox runtime might auto-install
// (the toolset has a Command set and Version isn't "false"/"off").
// Callers use this to decide whether to allowlist the package
// hosts the auto-installer reaches — we keep that gated so we
// don't open holes in the sandbox proxy when no agent could
// possibly need them.
NeedsToolInstall bool
// ToolInstallHosts is the sorted, deduplicated set of hostnames
// the in-sandbox auto-installer needs to reach in order to install
// every auto-installable toolset declared by the agent. It is
// populated only when NeedsToolInstall is true.
//
// Each toolset's package is looked up against the aqua registry
// and contributes only the hosts its install path actually uses
// (Go module proxy + toolchain bootstrap for go_install packages,
// GitHub release hosts for github_release packages, plus the
// shared registry-lookup hosts in both cases). When a lookup
// fails, [toolinstall.FallbackHosts] is folded in instead so the
// install can still succeed at the cost of opening every install
// host — callers that want to fail closed should inspect
// ToolInstallHostsResolutionErr.
ToolInstallHosts []string
// ToolInstallHostsResolutionErr lists the per-toolset registry
// lookup errors encountered while computing ToolInstallHosts.
// When non-empty, ToolInstallHosts conservatively contains the
// fallback union of every install host so the run can still
// proceed; callers can choose stricter behaviour (refuse the run,
// surface the error to the user) by checking this slice.
ToolInstallHostsResolutionErr []ToolHostError
}
Result is what Build returns.
func Build ¶
Build stages the kit and returns its location.
Each Build creates a temporary directory under CacheDir, populates it, then atomically replaces the final per-agent directory. Concurrent Builds for the same agent therefore never see a half-populated kit; the last one to finish wins. The kit directory itself is reused across runs (deterministic path keyed by AgentRef) so the sandbox VM can be reused as long as nothing else in the workspace mount set changed.
func (*Result) PrintSummary ¶
PrintSummary writes a human-readable description of what was staged to w. The output groups files by skill (one block per skill, listing every file inside), then lists prompt files. Files whose host content was scrubbed are tagged "(redacted)". A trailing summary line counts skills, prompt files, and redactions.
PrintSummary is silent when the kit shipped nothing — the caller is expected to print its own "no kit needed" hint in that case.
type ToolHostError ¶ added in v1.63.0
type ToolHostError struct {
// Command is the toolset's Command field — the same string the
// in-sandbox runtime would auto-install.
Command string
// Version is the toolset's Version field. Empty means "latest /
// resolve by command".
Version string
// Err is the underlying registry / lookup error.
Err error
}
ToolHostError records a single toolset whose package could not be resolved against the aqua registry while computing the sandbox allowlist. Callers can use it to surface a precise diagnostic to the user ("could not resolve gopls; falling back to the union of every install host") instead of silently degrading the network policy.
func (ToolHostError) Error ¶ added in v1.63.0
func (e ToolHostError) Error() string
func (ToolHostError) Unwrap ¶ added in v1.63.0
func (e ToolHostError) Unwrap() error