v1alpha1

package
v0.0.9 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package v1alpha1 contains API Schema definitions for the agents v1alpha1 API group. +kubebuilder:object:generate=true +groupName=agents.navix.sh

Index

Constants

View Source
const (
	// ManagedAgentConditionBrainReady is true when the Deployment is available
	// and the gateway answers its health probe.
	ManagedAgentConditionBrainReady = "BrainReady"
	// ManagedAgentConditionBackendsAvailable is true when at least one harness
	// passed preflight.
	ManagedAgentConditionBackendsAvailable = "BackendsAvailable"
	// ManagedAgentConditionHandsReady is true when the referenced or derived
	// SandboxEnv exists and can serve.
	ManagedAgentConditionHandsReady = "HandsReady"
	// ManagedAgentConditionSandboxReachable is true when the configured sandbox
	// credential and endpoint answer.
	ManagedAgentConditionSandboxReachable = "SandboxReachable"
)

ManagedAgent condition types.

View Source
const (
	SandboxPoolLabelKey  = "agentbox.navix.sh/sandbox-pool"
	SandboxPhaseLabelKey = "agentbox.navix.sh/sandbox-phase"
	SandboxIDLabelKey    = "agentbox.navix.sh/sandbox-id"
	ManagedByLabelKey    = "agentbox.navix.sh/managed-by"

	// TemplateHashLabelKey carries the fnv32 revision hash of a Pool's
	// materialised idle-Pod identity (IdleImage + pod-spec body + NetworkPolicy
	// + template metadata; see ComputeRevisionHash). Stamped by the Env
	// renderer onto both SandboxPool.metadata.labels and
	// SandboxPool.spec.template.metadata.labels, from where it flows to every
	// Pod. The SandboxPool reconciler compares a Pod's value against the Pool
	// template's to decide which idle Pods are stale and must be rolled.
	TemplateHashLabelKey = "agentbox.navix.sh/template-hash"

	// SandboxPhase values for the agentbox sandbox lifecycle.
	SandboxPhaseIdle     = "idle"
	SandboxPhaseRunning  = "running"
	SandboxPhaseStarting = "starting" // Idle → (image pull) → Running
	SandboxPhaseStopping = "stopping" // Running → (image reset) → Idle
	SandboxPhaseFailed   = "failed"

	ManagedBySandboxAPIServer = "sandbox-api-server"

	SandboxIDAnnotationKey        = "agentbox.navix.sh/sandbox-id"
	SandboxClaimedAtAnnotationKey = "agentbox.navix.sh/claimed-at"
	SandboxStartedAtAnnotationKey = "agentbox.navix.sh/started-at"
	// SandboxIdleTimeoutAnnotationKey stores the idle timeout duration in seconds (e.g. "600").
	// Written at claim time if TTL > 0. Read by IdleTimeoutReconciler.
	SandboxIdleTimeoutAnnotationKey = "agentbox.navix.sh/idle-timeout"
	// SandboxStartupTimeoutAnnotationKey stores the startup timeout duration in seconds (e.g. "120").
	// Written at claim time when a startup timeout is resolved (from request or pool default).
	// Read by IdleTimeoutReconciler.cleanupTimedOutStartingPods to determine per-pod timeout.
	// Takes priority over the pool-level StartupTimeout when both are set.
	SandboxStartupTimeoutAnnotationKey = "agentbox.navix.sh/startup-timeout"
	// SandboxLastActiveAnnotationKey stores the RFC3339 time of the last HTTP request
	// proxied through ExtProc. Written asynchronously by ActivityTracker.
	SandboxLastActiveAnnotationKey            = "agentbox.navix.sh/last-active"
	SandboxMetadataAnnotationKey              = "agentbox.navix.sh/sandbox-metadata"
	SandboxManagedLabelKeysAnnotationKey      = "agentbox.navix.sh/managed-label-keys"
	SandboxManagedAnnotationKeysAnnotationKey = "agentbox.navix.sh/managed-annotation-keys"

	// SandboxStopReasonAnnotationKey records why the sandbox was stopped.
	// Values: "Completed" | "Released" | "Failed" | "Canceled". Written by ReleaseSandboxPod.
	// Read by syncInplaceUpdatePhases on Stopping→Idle to perform deferred KV write.
	SandboxStopReasonAnnotationKey = "agentbox.navix.sh/stop-reason"

	// SandboxTerminatedAtAnnotationKey records the RFC3339 termination timestamp.
	SandboxTerminatedAtAnnotationKey = "agentbox.navix.sh/terminated-at"

	// SandboxFailureReasonAnnotationKey records the machine-readable failure cause.
	// e.g. "IdleTimeout", "OOMKilled", "Evicted"
	SandboxFailureReasonAnnotationKey = "agentbox.navix.sh/failure-reason"

	// SandboxFailureMessageAnnotationKey records the human-readable failure description.
	SandboxFailureMessageAnnotationKey = "agentbox.navix.sh/failure-message"

	// SandboxExitCodeAnnotationKey records the container exit code (decimal string).
	SandboxExitCodeAnnotationKey = "agentbox.navix.sh/exit-code"

	// SandboxRunningImagesAnnotationKey stores a JSON map[string]string of container
	// name → image captured at release time (before the idle image reset).
	SandboxRunningImagesAnnotationKey = "agentbox.navix.sh/running-images"

	// SandboxContainerIDAnnotationKey stores the runtime container ID (e.g.
	// "containerd://abc123…") captured at release time, before the in-place
	// update resets the pod to idle and clears StableContainerStatuses.
	SandboxContainerIDAnnotationKey = "agentbox.navix.sh/container-id"

	// SandboxEgressPolicyAnnotationKey carries the JSON-encoded effective egress
	// policy (pkg/egressproxy.Policy) resolved for a claimed sandbox: the merge
	// of the per-sandbox override and the Pool's Env-default networkPolicy. The
	// SandboxReady hook reads it and pushes it into the filter sidecar via exec.
	// Registered as a managed annotation key so it is stripped on release,
	// giving free reset-on-recycle.
	SandboxEgressPolicyAnnotationKey = "agentbox.navix.sh/egress-policy"

	// SandboxEgressInjectAnnotationKey carries the JSON-encoded credential
	// injection block (v1alpha1.SecretInjection) resolved for a claimed sandbox,
	// with per-claim placeholders filled in.
	//
	// It holds rule shapes, credential names, Secret references and decoys —
	// never a credential value. The SandboxReady hook resolves the referenced
	// Secrets and delivers the plaintext straight to the sidecar over exec, so
	// no credential is ever written to etcd or returned by the API. Registered
	// as a managed annotation key so release strips it.
	SandboxEgressInjectAnnotationKey = "agentbox.navix.sh/egress-inject"

	// SI Scheduler labels and annotations
	LabelTeam = "scheduling.navix.sh/team"
	LabelUser = "scheduling.navix.sh/user"

	// AnnotationReservationReplicaQuota stores the per-replica reservation quota
	// as a JSON map[string]string of instancetype-name → whole-instance count,
	// e.g. {"sci.c23-2":"2"}. It is the bridge between the API server (which
	// derives sizing from EnvClusterMember.{InstanceType,Multiplier}) and the
	// closed-source SI Scheduler reservation plugin, which reads it to size the
	// reservation. When an InstanceType is used, the API server stamps the real
	// multiplier here so the reservation quota is charged per whole instance even
	// when the Pod's actual resource request is rounded down below the instance.
	//
	// The value MUST stay identical to the reservation plugin's own constant
	// (agentbox pkg/scitix/reservation/sischeduler.AnnotationReplicaQuota).
	AnnotationReservationReplicaQuota = "scheduling.navix.sh/reservation-replica-quota"

	// LabelEnv is stamped onto every member SandboxPool by the SandboxEnv
	// reconciler at materialisation time, with the owning Env's
	// metadata.name as value. Used by the Pool autoscaler to reverse-lookup
	// the owning Env (for reading scaling-group constraints) and to list
	// sibling Pools sharing the same Env without walking ownerReferences.
	LabelEnv = "agentbox.navix.sh/env"

	// LabelScalingGroup is stamped onto every member SandboxPool by the
	// SandboxEnv reconciler at materialisation time, carrying the member's
	// EnvClusterMember.Config.ScalingGroup. Members sharing a value belong to
	// the same Env autoscaling group. Surfaced on the gen.SandboxPool wire
	// shape so the dashboard can group Pools without re-reading the Env spec.
	// Absent when the member is excluded from autoscaling (empty ScalingGroup).
	LabelScalingGroup = "agentbox.navix.sh/scaling-group"

	// SandboxTemplateDocsAnnotationKey stores Markdown documentation for the template.
	// Read by the dashboard to display a documentation sheet.
	SandboxTemplateDocsAnnotationKey = "agentbox.navix.sh/docs"

	// SandboxTemplatePoolDocsAnnotationKey is the legacy annotation for pool-specific usage docs.
	//
	// Deprecated: ignored by the server; use SandboxTemplateDocsAnnotationKey instead.
	SandboxTemplatePoolDocsAnnotationKey = "agentbox.navix.sh/pool-docs"

	// SandboxPoolTemplateNameAnnotationKey records the source SandboxTemplate name.
	SandboxPoolTemplateNameAnnotationKey = "agentbox.navix.sh/template-name"
	// SandboxPoolTemplateVersionAnnotationKey records the source SandboxTemplate version at creation time.
	SandboxPoolTemplateVersionAnnotationKey = "agentbox.navix.sh/template-version"
	// SandboxPoolOverridesAnnotationKey stores a JSON-encoded PoolTemplateOverrides
	// object so SyncTemplate can re-apply all pool-level overrides on top of newer
	// template revisions. A single blob avoids per-field annotation proliferation as
	// the override surface grows (image, resourceMultiplier, imagePullSecret, PVCs, …).
	SandboxPoolOverridesAnnotationKey = "agentbox.navix.sh/overrides"

	// SandboxProtectionFinalizer is added to every Pool-managed Pod at creation time,
	// and reconcile backfills it onto pre-existing Pods after upgrade.
	// It guarantees the controller sees a DeletionTimestamp window before the pod is GC'd,
	// allowing sandbox history records to be written even when a pod is deleted externally
	// (e.g. kubectl delete pod, kubelet eviction). Without this finalizer an external pod
	// deletion may race past the controller's reconcile loop, permanently losing the
	// sandbox history record and stop metrics.
	// The finalizer stays attached for the pod lifetime and is removed only when
	// the pod is actually being deleted:
	//   - syncDeletingPods after writing the terminal record for a terminating pod
	//   - syncFailedPods before explicitly deleting an evicted/failed pod
	//   - Controller scale-down, pool-deletion, and startup-timeout cleanup paths before Delete
	SandboxProtectionFinalizer = "agentbox.navix.sh/sandbox-protection"

	// SandboxPostStartHooksAnnotationKey stores JSON-encoded []PostStartHookAction.
	// Written at claim time when post-start hooks are requested (e.g. envd /init for env vars).
	// Consumed by the controller after Starting→Running; deleted on Stopping→Idle.
	SandboxPostStartHooksAnnotationKey = "agentbox.navix.sh/post-start-hooks"

	// SandboxScaleDownProtectedAnnotationKey is set on Idle Pods that have been
	// selected as scale-down candidates. The value is the RFC3339 timestamp when
	// the protection window started. Cleared if the Pod is claimed before deletion.
	SandboxScaleDownProtectedAnnotationKey = "agentbox.navix.sh/scale-down-protected"

	// LastSandboxCreateTimeAnnotationKey is the throttled persistent mirror
	// of the in-process LastCreateTracker: the most recent wall-clock time
	// the apiserver served a Sandbox.Create request for this Pool. Written
	// by a periodic flush (≈ every 5 s, only when the in-memory value
	// advanced past the last-flushed value) so high-QPS Create traffic
	// does not produce a per-request annotation patch.
	//
	// The Pool autoscaler reads this annotation as a fallback when the
	// in-process tracker is empty (e.g. shortly after a process restart);
	// the in-memory value always takes precedence when both exist.
	//
	// The value is RFC3339 UTC. Absence is treated as "never observed".
	LastSandboxCreateTimeAnnotationKey = "agentbox.navix.sh/last-sandbox-create-time"

	// LabelSyncSource marks the origin of a resource.
	// "global" means the resource was created/synced via ws-proxy (global key manager).
	// Resources without this label (locally-created or legacy) are treated as non-global.
	// Intentionally mirrors the constant in pkg/utils/apikey so that the api/v1alpha1 package
	// can be used as the canonical source for all agentbox label/annotation keys.
	LabelSyncSource = "agentbox.io/sync-source"
	// LabelSyncSourceGlobal is the value for LabelSyncSource that indicates a globally-managed resource.
	LabelSyncSourceGlobal = "global"

	// ImagePullSecretNamePrefix is prepended to a parent resource's name to
	// derive the deterministic dockerconfigjson Secret created alongside
	// it. Used by both the legacy SandboxPool Create flow (Secret owned by
	// the Pool) and the SandboxEnv flow (Secret owned by the Env and
	// referenced by every member Pool). The full name is
	// "ips-{ownerName}".
	ImagePullSecretNamePrefix = "ips-"
)
View Source
const (
	// SandboxEnvConditionReady indicates all members are Active.
	SandboxEnvConditionReady = "Ready"
	// SandboxEnvConditionTemplateConsistent indicates every member Pool
	// references the Env's Template by name and has finished rolling onto its
	// current revision hash.
	SandboxEnvConditionTemplateConsistent = "TemplateConsistent"
	// SandboxEnvConditionAutoscalingActive indicates the autoscaler is
	// configured, enabled, and has not stalled due to misconfiguration.
	SandboxEnvConditionAutoscalingActive = "AutoscalingActive"
	// SandboxEnvConditionCredentialsResolvable indicates every declared
	// injected credential resolves to a non-empty value right now. False means
	// a sandbox claim would fail closed, so the Env carries the diagnosis
	// instead of leaving it to be inferred from Pods that never start. Absent
	// on Envs that declare no credentials.
	SandboxEnvConditionCredentialsResolvable = "CredentialsResolvable"
)

Condition type constants for SandboxEnv.

View Source
const (
	// SandboxPoolConditionAvailable indicates whether the pool has idle pods ready to accept sandbox requests.
	SandboxPoolConditionAvailable = "Available"
	// SandboxPoolConditionScaling indicates whether the pool is currently scaling up or down.
	SandboxPoolConditionScaling = "Scaling"
	// SandboxPoolConditionDegraded indicates whether the pool has unhealthy or failed pods.
	SandboxPoolConditionDegraded = "Degraded"
)

Condition type constants for SandboxPool.

View Source
const (
	// Available condition reasons
	SandboxPoolReasonIdlePodsAvailable   = "IdlePodsAvailable"   // healthy idle pods are available
	SandboxPoolReasonNoIdlePodsAvailable = "NoIdlePodsAvailable" // no idle pods can accept requests

	// Scaling condition reasons
	SandboxPoolReasonScalingUp     = "ScalingUp"     // pool is scaling up
	SandboxPoolReasonScalingDown   = "ScalingDown"   // pool is scaling down
	SandboxPoolReasonReplicasReady = "ReplicasReady" // all replicas are up-to-date

	// Degraded condition reasons
	SandboxPoolReasonAllPodsHealthy     = "AllPodsHealthy"         // no unhealthy or failed pods
	SandboxPoolReasonUnhealthyIdlePods  = "UnhealthyIdlePods"      // idle pods are NotReady
	SandboxPoolReasonFailedPodsPresent  = "FailedPodsPresent"      // failed pods exist
	SandboxPoolReasonUnhealthyAndFailed = "UnhealthyAndFailedPods" // both unhealthy idle and failed pods
)

Condition reason constants for SandboxPool.

View Source
const EgressProxyContainerName = "egress-proxy"

EgressProxyContainerName is the egress filter sidecar the operator injects into sandbox Pods whose Pool declares a SandboxNetworkPolicy. Normally it is a native sidecar and lives in Pod.Spec.InitContainers with an Always restart policy; on API servers that prune that field the operator can be told to inject it as an ordinary container instead, so both lists have to be searched for it.

View Source
const EnvSecretInjectionNamePrefix = "eis-"

EnvSecretInjectionNamePrefix is prepended to an Env's name to form the Secret that holds its injected credentials — one Secret per Env, one key per credential (keyed by the credential's Name), not one Secret per credential.

View Source
const MinPlaceholderLen = 16

MinPlaceholderLen is the shortest accepted decoy. Short decoys risk colliding with ordinary header content, which would substitute a real credential into a request that never asked for one.

View Source
const PlaceholderPrefix = "agbx_ph_"

PlaceholderPrefix marks a generated decoy value. Fixed placeholders supplied by the user need not carry it.

View Source
const SandboxEnvOwnerKind = "SandboxEnv"

SandboxEnvOwnerKind is the OwnerReference.Kind value for SandboxEnv. Exposed so other packages can write owner refs without string literals.

Variables

View Source
var (
	// GroupVersion is group version used to register these objects.
	GroupVersion = schema.GroupVersion{Group: "agents.navix.sh", Version: "v1alpha1"}

	// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}

	// AddToScheme adds the types in this group-version to the given scheme.
	AddToScheme = SchemeBuilder.AddToScheme
)
View Source
var DefaultMaxUnavailable = intstr.FromString("20%")

DefaultMaxUnavailable is the rollout unavailability budget applied when neither the member nor the Env overrides specify one.

Functions

func ComputeRevisionHash added in v0.0.7

func ComputeRevisionHash(spec *SandboxPoolSpec) string

ComputeRevisionHash returns a stable fnv32a hash of the identity a freshly materialised *idle* Pod would take under this Pool spec. Two Pools that would produce byte-identical idle Pods hash equally; any change that alters the idle Pod (idle image, sidecars/volumes/affinity in the pod-spec body, egress network policy, or the scheduler-facing template metadata) flips the hash and drives a rollout. Field *deletion* changes the serialised structure and is therefore captured too.

Deliberately excluded from the hash (changing them must NOT roll idle Pods):

  • Replicas / DefaultStartupTimeout / DefaultIdleTimeout: scale and per- request timeouts, not pod identity.
  • The main container image under the IdleImage policy: an idle Pod runs spec.idleImage (createPod overrides containers[0].image), and the running image is resolved from the live Pool template at claim time — so changing the running image reaches sandboxes on the next claim without a rebuild. It is normalised to IdleImage before hashing so it does not contribute.
  • The hash label itself (self-reference).

func EnvImagePullSecretName added in v0.0.5

func EnvImagePullSecretName(envName string) string

EnvImagePullSecretName returns the deterministic Secret name for the dockerconfigjson Secret that backs an Env's overrides.imagePullSecret. One Secret per Env; the Env Reconciler stamps a LocalObjectReference for this name into every member Pool's spec.template.spec.imagePullSecrets.

func EnvSecretInjectionName added in v0.0.9

func EnvSecretInjectionName(envName string) string

EnvSecretInjectionName returns the Secret backing an Env's declared credentials. Callers may also point a credential at a Secret of their own; this is only the one the platform materialises from values typed into the API, mirroring how imagePullSecret works.

func HasEnvOwner added in v0.0.5

func HasEnvOwner(obj metav1.Object) bool

HasEnvOwner reports whether obj carries an OwnerReference to a SandboxEnv in this API group. Controlling-vs-non-controlling is intentionally ignored; Phase 1 adoption stamps a non-controlling reference and we may still want to treat hand-edited controlling references the same way.

The check uses APIVersion's group prefix (not exact equality) so future minor API revisions (e.g. v1beta1) automatically qualify.

func PodHasEgressProxy added in v0.0.8

func PodHasEgressProxy(pod *corev1.Pod) bool

PodHasEgressProxy reports whether pod carries the egress filter sidecar.

A Pod materialised before its Pool gained a SandboxNetworkPolicy does not have it — and since the same injection also installs the iptables redirect, such a Pod has *no* egress enforcement whatsoever. Handing one to a claim that expects enforcement would be fail-open (the policy annotation would be stamped, the API would report success, and traffic would leave unfiltered), so the scheduler refuses those Pods and waits for a rolled one instead.

func ResolveAutoUpdate added in v0.0.7

func ResolveAutoUpdate(env *SandboxEnv, member EnvClusterMember) bool

ResolveAutoUpdate returns whether the given member auto-rolls when its revision changes. Resolution order: member.Config.UpdateStrategy → env.Spec.Overrides.UpdateStrategy → default true. A cross-field default like this cannot be expressed with kubebuilder markers, so it lives in code alongside EffectiveScaleUpPriority.

func ResolveMaxUnavailable added in v0.0.7

func ResolveMaxUnavailable(env *SandboxEnv, member EnvClusterMember) intstr.IntOrString

ResolveMaxUnavailable returns the rollout unavailability budget for the given member. Resolution order: member.Config.UpdateStrategy → env.Spec.Overrides.UpdateStrategy → DefaultMaxUnavailable ("20%").

func ValidateSecretInjection added in v0.0.8

func ValidateSecretInjection(np *SandboxNetworkPolicy) error

ValidateSecretInjection checks a SandboxNetworkPolicy's injection block for the mistakes that would otherwise fail silently or leak a credential. It is called both when a SandboxEnv is written (so the author sees the error) and at claim time (so a hand-edited CRD cannot slip through).

np may be nil or carry no injection block, in which case there is nothing to check.

Types

type BackendStatus added in v0.0.8

type BackendStatus struct {
	// +required
	ID string `json:"id"`
	// +optional
	Available bool `json:"available,omitempty"`
	// +optional
	Reason string `json:"reason,omitempty"`
}

BackendStatus is one harness's availability.

func (*BackendStatus) DeepCopy added in v0.0.8

func (in *BackendStatus) DeepCopy() *BackendStatus

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendStatus.

func (*BackendStatus) DeepCopyInto added in v0.0.8

func (in *BackendStatus) DeepCopyInto(out *BackendStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ClaudeCodeRuntime added in v0.0.8

type ClaudeCodeRuntime struct {
	// BaseURL is an Anthropic-format endpoint. Empty means api.anthropic.com.
	// +optional
	BaseURL string `json:"baseURL,omitempty"`

	// CredentialsRef supplies ANTHROPIC_AUTH_TOKEN.
	// +required
	CredentialsRef SecretKeySelector `json:"credentialsRef"`

	// Models is the ONLY source of the in-composer dropdown. The Claude Agent
	// SDK's supportedModels() is a static table compiled into the SDK and never
	// queries the endpoint, so a configured list is the only correct answer.
	// +optional
	Models []ManagedAgentModel `json:"models,omitempty"`

	// +optional
	DefaultModel string `json:"defaultModel,omitempty"`

	// SmallModel backs the harness's own side tasks (titles and the like).
	// +optional
	SmallModel string `json:"smallModel,omitempty"`

	// +kubebuilder:validation:Enum=low;medium;high;xhigh;max
	// +optional
	Effort string `json:"effort,omitempty"`

	// PluginPaths are in-image plugin directories carrying skills, sub-agents,
	// hooks and .mcp.json. They coexist with an empty settingSources, which is
	// how product assets load without reading a developer's own ~/.claude.
	// +optional
	PluginPaths []string `json:"pluginPaths,omitempty"`
}

ClaudeCodeRuntime configures the Claude Agent SDK harness.

func (*ClaudeCodeRuntime) DeepCopy added in v0.0.8

func (in *ClaudeCodeRuntime) DeepCopy() *ClaudeCodeRuntime

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClaudeCodeRuntime.

func (*ClaudeCodeRuntime) DeepCopyInto added in v0.0.8

func (in *ClaudeCodeRuntime) DeepCopyInto(out *ClaudeCodeRuntime)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ClientToolSpec added in v0.0.8

type ClientToolSpec struct {
	// +required
	Name string `json:"name"`
	// +required
	Description string `json:"description"`
	// InputSchema is JSON Schema, passed to the harness unchanged.
	// +optional
	// +kubebuilder:pruning:PreserveUnknownFields
	InputSchema *apiextensionsv1.JSON `json:"inputSchema,omitempty"`
	// TimeoutSeconds bounds how long the platform waits for the caller.
	// +optional
	TimeoutSeconds int32 `json:"timeoutSeconds,omitempty"`
}

ClientToolSpec declares a tool the caller executes.

func (*ClientToolSpec) DeepCopy added in v0.0.8

func (in *ClientToolSpec) DeepCopy() *ClientToolSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientToolSpec.

func (*ClientToolSpec) DeepCopyInto added in v0.0.8

func (in *ClientToolSpec) DeepCopyInto(out *ClientToolSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ConfigMapKeySelector added in v0.0.8

type ConfigMapKeySelector struct {
	// +required
	Name string `json:"name"`
	// +required
	Key string `json:"key"`
}

ConfigMapKeySelector points at one key of a ConfigMap.

func (*ConfigMapKeySelector) DeepCopy added in v0.0.8

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapKeySelector.

func (*ConfigMapKeySelector) DeepCopyInto added in v0.0.8

func (in *ConfigMapKeySelector) DeepCopyInto(out *ConfigMapKeySelector)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type EgressRules added in v0.0.7

type EgressRules struct {
	// AllowedDomains permits egress to matching hostnames. Supports exact
	// ("pypi.org"), wildcard-all ("*"), and suffix ("*.pythonhosted.org").
	// Matched via TLS SNI (443) / HTTP Host (80); other ports are IP-only.
	// +optional
	AllowedDomains []string `json:"allowedDomains,omitempty"`

	// AllowedCIDRs permits egress to these CIDR blocks / bare IPs (as /32).
	// +optional
	AllowedCIDRs []string `json:"allowedCIDRs,omitempty"`

	// DeniedCIDRs blocks egress to these CIDR blocks / bare IPs. Domains are not
	// supported for deny (a domain resolves to many changing IPs).
	// +optional
	DeniedCIDRs []string `json:"deniedCIDRs,omitempty"`
}

EgressRules is the allow/deny ruleset applied to sandbox outbound traffic.

func (*EgressRules) DeepCopy added in v0.0.7

func (in *EgressRules) DeepCopy() *EgressRules

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressRules.

func (*EgressRules) DeepCopyInto added in v0.0.7

func (in *EgressRules) DeepCopyInto(out *EgressRules)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type EmbeddedSandboxTemplate

type EmbeddedSandboxTemplate struct {
	// Template defines the Pod template. ALL Pods in this Pool share the same
	// resources (requests/limits). The image specified here is used as the IDLE image
	// unless IdleImage is explicitly set.
	// +kubebuilder:pruning:PreserveUnknownFields
	// +kubebuilder:validation:Schemaless
	// +optional
	Template corev1.PodTemplateSpec `json:"template,omitempty"`

	// IdleImage is the image to use when Pods are in the idle state.
	// If not specified, the image from Template.Spec.Containers[0].Image will be used.
	// +optional
	IdleImage string `json:"idleImage,omitempty"`

	// Runtimes specifies the runtimes to use for the sandbox pods. Each runtime has a type and optional configuration.
	// If not specified, a default runtime will be used.
	// +listType=map
	// +listMapKey=name
	// +optional
	Runtimes []SandboxRuntimeSpec `json:"runtimes,omitempty"`
}

func (*EmbeddedSandboxTemplate) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmbeddedSandboxTemplate.

func (*EmbeddedSandboxTemplate) DeepCopyInto

func (in *EmbeddedSandboxTemplate) DeepCopyInto(out *EmbeddedSandboxTemplate)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type EnvAutoscalingGroup added in v0.0.5

type EnvAutoscalingGroup struct {
	// Name matches EnvClusterMember.ScalingGroup. Required. The Env
	// rejects groups whose Name does not match the ScalingGroup of at
	// least one member — empty-group policies have no effect and would
	// confuse the autoscaler's per-group iteration.
	// +required
	Name string `json:"name"`

	// Enabled toggles the autoscaler on/off for this group. When false,
	// member Pool replicas in this scaling group are managed manually.
	// +optional
	// +kubebuilder:default=false
	Enabled bool `json:"enabled,omitempty"`

	// MinReplicas is the lower bound for the aggregate (group) replica
	// count. Defaults to 0 — set explicitly so kubectl get sbe surfaces
	// the floor instead of leaving it implicit.
	// +optional
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=0
	MinReplicas *int32 `json:"minReplicas,omitempty"`

	// MaxReplicas is the upper bound for the aggregate (group) replica
	// count. When unset, the group has NO ceiling and grows until each
	// member's own MaxReplicas, the cluster's capacity, or external
	// quotas stop it. Aggressive scaleUpPolicy.mode REQUIRES this field
	// to be set (validated via CEL) because doubling each cooldown
	// without an upper bound is unsafe.
	// +optional
	// +kubebuilder:validation:Minimum=0
	MaxReplicas *int32 `json:"maxReplicas,omitempty"`

	// ScaleUpPolicy controls how scale-up decisions are evaluated. The
	// API server fills every field with its declared default when the
	// caller omits it, so the persisted CR always carries an explicit,
	// inspectable value (no hidden code defaults).
	// +optional
	// +kubebuilder:default={}
	ScaleUpPolicy PoolScaleUpPolicy `json:"scaleUpPolicy"`

	// ScaleDownPolicy controls how scale-down decisions are evaluated.
	// Same defaulting contract as ScaleUpPolicy.
	// +optional
	// +kubebuilder:default={}
	ScaleDownPolicy PoolScaleDownPolicy `json:"scaleDownPolicy"`
}

EnvAutoscalingGroup is one Env-level autoscaling unit, applied jointly to every member referencing this group.

+kubebuilder:validation:XValidation:rule="self.scaleUpPolicy.mode != 'Aggressive' || has(self.maxReplicas)",message="Aggressive scaleUpPolicy.mode requires maxReplicas to be set on the group — Aggressive doubles the replica count each cooldown and would otherwise grow without bound"

func (*EnvAutoscalingGroup) DeepCopy added in v0.0.5

func (in *EnvAutoscalingGroup) DeepCopy() *EnvAutoscalingGroup

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvAutoscalingGroup.

func (*EnvAutoscalingGroup) DeepCopyInto added in v0.0.5

func (in *EnvAutoscalingGroup) DeepCopyInto(out *EnvAutoscalingGroup)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type EnvAutoscalingSpec added in v0.0.5

type EnvAutoscalingSpec struct {
	// Groups is the list of autoscaling groups. Each group is keyed by Name
	// and toggles its own Enabled bit independently.
	// +optional
	// +listType=map
	// +listMapKey=name
	Groups []EnvAutoscalingGroup `json:"groups,omitempty"`
}

EnvAutoscalingSpec configures the Env-level autoscaler. The Enabled switch lives on each EnvAutoscalingGroup so groups can be toggled independently — a group with Enabled=false is dormant; its members' Pool replicas stay where the user (or other actors) put them.

func (*EnvAutoscalingSpec) DeepCopy added in v0.0.5

func (in *EnvAutoscalingSpec) DeepCopy() *EnvAutoscalingSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvAutoscalingSpec.

func (*EnvAutoscalingSpec) DeepCopyInto added in v0.0.5

func (in *EnvAutoscalingSpec) DeepCopyInto(out *EnvAutoscalingSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type EnvClusterMember added in v0.0.5

type EnvClusterMember struct {
	// Name is the SandboxPool's metadata.name within the Env's namespace.
	// Acts as the list map key for Members. Must equal Metadata.Name once
	// the Reconciler materialises the Pool; the Reconciler overwrites
	// Metadata.Name with Name at stamp time if they disagree.
	// +required
	Name string `json:"name"`

	// Metadata is the snapshot of the candidate Pool's mutable ObjectMeta
	// subset (Labels + Annotations) after PreCreatePool. The Reconciler
	// propagates these onto the live Pool when materialising it.
	//
	// Finalizers are intentionally NOT stored here — `SandboxPoolReconciler`
	// owns the Pool's finalizer lifecycle. Name/Namespace/UID/etc. are server
	// or Env-owned and don't belong on a per-member snapshot. Using a
	// dedicated struct (instead of metav1.ObjectMeta) avoids controller-gen
	// emitting a degenerate `type: object` schema, which K8s API server would
	// otherwise prune in admission.
	// +optional
	Metadata MemberMetadata `json:"metadata,omitempty"`

	// Spec is the snapshot of the candidate SandboxPoolSpec after
	// PreCreatePool. The Reconciler stamps the whole Spec verbatim when
	// creating the live Pool and uses equality.Semantic.DeepEqual to
	// detect drift between Spec and the live Pool on subsequent
	// reconciles, including Spec.Replicas. The Env Reconciler is the
	// sole writer of the live Pool's Replicas — both the API
	// (UpdateMember) and the Env autoscaler express their intent by
	// patching Member.Spec.Replicas here and let the Reconciler
	// propagate it.
	// +optional
	Spec SandboxPoolSpec `json:"spec,omitempty"`

	// Config carries user-declared intent: sizing (InstanceType/Multiplier
	// or InlineResources), autoscaling bookkeeping (ScalingGroup,
	// MaxReplicas), and routing priorities. Plugins do not mutate Config,
	// so it remains a faithful description of the caller's request.
	// +optional
	Config EnvClusterMemberConfig `json:"config,omitempty"`
}

EnvClusterMember describes one SandboxPool participating in this Env.

The shape is a three-bucket split:

  • Name: identity within the Env (the list map key).
  • Metadata + Spec: server-managed snapshot of the materialised SandboxPool, captured AFTER PreCreatePool admission ran at the API layer. The Env Reconciler stamps these onto the live Pool verbatim — it never re-runs plugin admission, so plugin side-effects (Reservation submit, scheduling labels, NodeAffinity, …) survive Pool recreate / Env re-apply without redoing the side-effect. **Not exposed through the REST API.** Template upgrades do NOT auto-propagate into Spec; an explicit RefreshMember API (Phase 2 TODO) is the way to align an existing member with a newer Template revision.
  • Config: user-declared intent (sizing, scaling-group bookkeeping, routing priorities). This is the only bucket exposed through the REST API. Plugins do not mutate Config — it stays equal to whatever the caller supplied at AddMember/UpdateMember time so it remains a faithful description of the request shape.

func (*EnvClusterMember) DeepCopy added in v0.0.5

func (in *EnvClusterMember) DeepCopy() *EnvClusterMember

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvClusterMember.

func (*EnvClusterMember) DeepCopyInto added in v0.0.5

func (in *EnvClusterMember) DeepCopyInto(out *EnvClusterMember)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type EnvClusterMemberConfig added in v0.0.5

type EnvClusterMemberConfig struct {
	// Labels are caller-supplied SandboxPool metadata.labels stamped onto
	// the rendered candidate Pool BEFORE PreCreatePool runs. Plugins
	// typically consume these for routing decisions (e.g. the
	// "quota.scitix.ai/url" label selects which ScitixQuota CR backs the
	// member). The plugin output — original + any plugin-added labels —
	// lands in Member.Metadata.Labels; Config.Labels stays equal to the
	// caller's input.
	// +optional
	Labels map[string]string `json:"labels,omitempty"`

	// Annotations are caller-supplied SandboxPool metadata.annotations,
	// same propagation rules as Labels.
	// +optional
	Annotations map[string]string `json:"annotations,omitempty"`

	// InstanceType references an entry in the cluster-wide InstanceType
	// catalog. Mutually informative with InlineResources: if both are set,
	// InstanceType wins and InlineResources serves as a transitional
	// record for migration.
	// +optional
	InstanceType string `json:"instanceType,omitempty"`

	// Multiplier scales InstanceType's resources. Required when
	// InstanceType is set.
	// +optional
	// +kubebuilder:validation:Minimum=0
	Multiplier int32 `json:"multiplier,omitempty"`

	// InlineResources is the Phase 1 migration escape hatch (legacy Pools
	// without an InstanceType label) AND the source of truth used by a
	// future RefreshMember API to keep resource sizing stable when the
	// underlying Template is upgraded. New Envs created via the Dashboard
	// should leave this empty and use InstanceType+Multiplier instead.
	// +optional
	InlineResources *corev1.ResourceRequirements `json:"inlineResources,omitempty"`

	// ScalingGroup names the autoscaling group this member belongs to.
	// Members in the same group must share the same effective resources
	// (= InstanceType × Multiplier or identical InlineResources). Empty
	// means the member is excluded from autoscaling.
	// +optional
	// +kubebuilder:default=default
	ScalingGroup string `json:"scalingGroup,omitempty"`

	// MinReplicas is the lower bound on this member's spec.replicas.
	// Enforced by the Env autoscaler: scale-down never shrinks this member
	// below MinReplicas. nil/0 means no per-member floor (only the group's
	// aggregate MinReplicas applies).
	// +optional
	// +kubebuilder:validation:Minimum=0
	MinReplicas *int32 `json:"minReplicas,omitempty"`

	// MaxReplicas is the upper bound on this member's spec.replicas.
	// Enforced by the Env autoscaler when distributing scale-up delta
	// across members.
	// +optional
	// +kubebuilder:validation:Minimum=0
	MaxReplicas *int32 `json:"maxReplicas,omitempty"`

	// Priority is the canonical routing/scaling preference: lower wins.
	// Also acts as the default for ScaleUpPriority / ScaleDownPriority
	// when those are unset.
	// +optional
	Priority int32 `json:"priority,omitempty"`

	// ScaleUpPriority overrides Priority for scale-up ordering within a
	// scalingGroup. Same-value tiebreak: (clusterID, name) lexicographic.
	// When nil, EffectiveScaleUpPriority falls back to Priority.
	// Reserved for Phase 2; Phase 1 ignores it.
	// +optional
	ScaleUpPriority *int32 `json:"scaleUpPriority,omitempty"`

	// ScaleDownPriority overrides Priority for scale-down ordering: lower
	// values are retained, higher values shrink first. The value direction
	// is intentionally inverted from ScaleUpPriority so that a single
	// Priority value (lower wins) means "preferred member" in both
	// directions — preferred members scale up first AND scale down last.
	// Same-value tiebreak: oldest idle Pod first, then name lexicographic.
	// When nil, EffectiveScaleDownPriority falls back to Priority.
	// +optional
	ScaleDownPriority *int32 `json:"scaleDownPriority,omitempty"`

	// UpdateStrategy overrides the Env-wide overrides.updateStrategy for this
	// member only. Unset fields inherit from the Env default, then from the
	// hard-coded default (autoUpdate=true, maxUnavailable="20%"). See
	// ResolveAutoUpdate / ResolveMaxUnavailable.
	// +optional
	UpdateStrategy *EnvUpdateStrategy `json:"updateStrategy,omitempty"`
}

EnvClusterMemberConfig captures the user-declared intent for one member. Plugins never write to this — it stays equal to the caller-supplied value across the lifetime of the member.

func (*EnvClusterMemberConfig) DeepCopy added in v0.0.5

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvClusterMemberConfig.

func (*EnvClusterMemberConfig) DeepCopyInto added in v0.0.5

func (in *EnvClusterMemberConfig) DeepCopyInto(out *EnvClusterMemberConfig)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (EnvClusterMemberConfig) EffectiveScaleDownPriority added in v0.0.5

func (c EnvClusterMemberConfig) EffectiveScaleDownPriority() int32

EffectiveScaleDownPriority returns ScaleDownPriority when set, otherwise Priority. Use this when picking which member in a scalingGroup shrinks first: HIGHER values are scaled down first (inverse of scale-up's "lower wins"), so that a shared Priority field expresses "preferred to retain" symmetrically across both directions.

func (EnvClusterMemberConfig) EffectiveScaleUpPriority added in v0.0.5

func (c EnvClusterMemberConfig) EffectiveScaleUpPriority() int32

EffectiveScaleUpPriority returns ScaleUpPriority when set, otherwise Priority. Use this when picking which member in a scalingGroup gets scale-up traffic first.

type EnvClusterSpec added in v0.0.5

type EnvClusterSpec struct {
	// ClusterID identifies the cluster that owns this segment. Each Worker
	// only mutates the segment matching its own ClusterID.
	// +required
	ClusterID string `json:"clusterID"`

	// Members is the list of SandboxPool members contributed by this cluster.
	// Phase 1 supports exactly one member per cluster.
	// +optional
	// +listType=map
	// +listMapKey=name
	Members []EnvClusterMember `json:"members,omitempty"`
}

EnvClusterSpec is the per-cluster portion of an Env spec.

func (*EnvClusterSpec) DeepCopy added in v0.0.5

func (in *EnvClusterSpec) DeepCopy() *EnvClusterSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvClusterSpec.

func (*EnvClusterSpec) DeepCopyInto added in v0.0.5

func (in *EnvClusterSpec) DeepCopyInto(out *EnvClusterSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type EnvClusterStatus added in v0.0.5

type EnvClusterStatus struct {
	// ClusterID matches the spec's ClusterID for the same segment.
	// +required
	ClusterID string `json:"clusterID"`

	// IsLocal is true on the Worker that owns this cluster's Pools. Used to
	// gate writes: only IsLocal=true segments are mutated by the local Env
	// Reconciler.
	// +optional
	IsLocal bool `json:"isLocal,omitempty"`

	// ObservedMembers reports per-member runtime state (idle/running/desired,
	// effective resources, member state).
	// +optional
	// +listType=map
	// +listMapKey=name
	ObservedMembers []EnvObservedMember `json:"observedMembers,omitempty"`

	// LastSnapshotTime records when this segment was last updated. For
	// IsLocal=true: write time by the local Reconciler. For IsLocal=false:
	// arrival time of the Hub Sync push.
	// +optional
	LastSnapshotTime *metav1.Time `json:"lastSnapshotTime,omitempty"`
}

EnvClusterStatus is the per-cluster observed state.

func (*EnvClusterStatus) DeepCopy added in v0.0.5

func (in *EnvClusterStatus) DeepCopy() *EnvClusterStatus

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvClusterStatus.

func (*EnvClusterStatus) DeepCopyInto added in v0.0.5

func (in *EnvClusterStatus) DeepCopyInto(out *EnvClusterStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type EnvObservedMember added in v0.0.5

type EnvObservedMember struct {
	// Name matches the spec member's Name and is the list map key.
	// +required
	Name string `json:"name"`

	// InstanceType / Multiplier are echoed from spec for convenience.
	// +optional
	InstanceType string `json:"instanceType,omitempty"`
	// +optional
	Multiplier int32 `json:"multiplier,omitempty"`

	// EffectiveResources is the resolved resource request/limit per Pod
	// (= InstanceType.resources × Multiplier, or InlineResources verbatim).
	// +optional
	EffectiveResources *corev1.ResourceRequirements `json:"effectiveResources,omitempty"`

	// State summarises whether the member can currently serve requests.
	// +optional
	State ObservedMemberState `json:"state,omitempty"`

	// IdleCount, RunningCount are mirrored from SandboxPool.status to surface
	// a single Env-level view to the Dashboard.
	// +optional
	IdleCount int32 `json:"idleCount,omitempty"`
	// +optional
	RunningCount int32 `json:"runningCount,omitempty"`

	// DesiredReplicas is the most recent value the Env autoscaler patched onto
	// the member Pool's spec.replicas.
	// +optional
	DesiredReplicas int32 `json:"desiredReplicas,omitempty"`

	// CurrentReplicas is the value last observed on the Pool spec.
	// +optional
	CurrentReplicas int32 `json:"currentReplicas,omitempty"`

	// PendingRequests is the throttled mirror of the in-process PoolScheduler
	// claim queue length, copied from SandboxPool.Status.PendingRequests.
	// Used by Dashboard observability and (future) cross-cluster routing.
	// +optional
	PendingRequests int32 `json:"pendingRequests,omitempty"`

	// SaturatedUntil marks this member as ineligible for routing/scaling
	// until the given time. Read-only mirror of
	// SandboxPool.Status.AutoScaling.SaturatedUntil, refreshed by the Env
	// reconciler's status aggregation; the source of truth is the per-Pool
	// autoscaler. The router (EnvScheduler) holds saturated members back
	// from the primary candidate list but still tries them as fallback
	// when no fresh member can accept the request.
	// +optional
	SaturatedUntil *metav1.Time `json:"saturatedUntil,omitempty"`

	// ScalingGroup is the autoscaling group this member belongs to on its
	// owning cluster, echoed from spec for convenience. Empty when the
	// member is not in any group. Lets a cross-cluster view (where the
	// consumer does not hold the foreign cluster's spec) still attribute
	// the member to a group and link to that cluster's group detail.
	// +optional
	ScalingGroup string `json:"scalingGroup,omitempty"`

	// AutoscalingEnabled reports whether this member's ScalingGroup has the
	// autoscaler turned on in its owning cluster. Because each cluster
	// controls its own scaling independently, a same-named group may be
	// enabled in one cluster and disabled in another; this is the per-pool,
	// per-cluster truth. It disambiguates ScaleUpHeadroom == 0 (at ceiling)
	// from autoscaling being off entirely.
	// +optional
	AutoscalingEnabled bool `json:"autoscalingEnabled,omitempty"`

	// ScaleUpHeadroom estimates how many more replicas this member can still
	// add on its owning cluster before hitting the smaller of its own
	// MaxReplicas and its group's aggregate MaxReplicas (given the group's
	// current total desired). It is meaningful only when AutoscalingEnabled
	// is true:
	//   - nil  → autoscaling off, or enabled with no finite ceiling (unbounded)
	//   - 0    → enabled but already at the ceiling (cannot grow now)
	//   - >0   → enabled with this much room left
	// The value is an estimate: the group ceiling is shared across members
	// and quota/node capacity are not folded in, so treat it as advisory
	// (like idle counts, it also lags by the federation TTL for foreign
	// members).
	// +optional
	ScaleUpHeadroom *int32 `json:"scaleUpHeadroom,omitempty"`

	// UpdateRevision is the target revision hash the member Pool is rolling
	// towards, mirrored from SandboxPool.Status.UpdateRevision.
	// +optional
	UpdateRevision string `json:"updateRevision,omitempty"`

	// TemplateVersion is the SandboxTemplate spec.version the member Pool was
	// last rendered from, read off the Pool's
	// agentbox.navix.sh/template-version provenance annotation. It is an
	// observation, not a constraint: members follow the Template's current
	// body, so this reports what they actually carry. Empty for foreign
	// (cross-cluster) members — the federation payload does not carry it.
	// +optional
	TemplateVersion string `json:"templateVersion,omitempty"`

	// UpdatedReplicas is the number of the member Pool's Pods already at
	// UpdateRevision, mirrored from SandboxPool.Status.UpdatedReplicas. A
	// rollout is in progress while UpdatedReplicas < the member's replicas.
	// +optional
	UpdatedReplicas int32 `json:"updatedReplicas,omitempty"`
}

EnvObservedMember reports per-member runtime state.

func (*EnvObservedMember) DeepCopy added in v0.0.5

func (in *EnvObservedMember) DeepCopy() *EnvObservedMember

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvObservedMember.

func (*EnvObservedMember) DeepCopyInto added in v0.0.5

func (in *EnvObservedMember) DeepCopyInto(out *EnvObservedMember)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type EnvOverridesSpec added in v0.0.5

type EnvOverridesSpec struct {
	// Image overrides the main container (containers[0]) image of the
	// rendered Template. Applied before any per-Member overrides.
	// +optional
	Image string `json:"image,omitempty"`

	// PodCreationImagePolicy overrides the Template's
	// spec.podCreationImagePolicy. Applied to every member Pool.
	// +optional
	// +kubebuilder:validation:Enum=PoolDefaultImage;IdleImage
	PodCreationImagePolicy PodCreationImagePolicy `json:"podCreationImagePolicy,omitempty"`

	// DefaultStartupTimeout overrides the Template's
	// spec.defaultStartupTimeout. Applied to Sandbox.Create requests that
	// don't carry an explicit startupTimeout.
	// +optional
	DefaultStartupTimeout *metav1.Duration `json:"defaultStartupTimeout,omitempty"`

	// DefaultIdleTimeout overrides the Template's spec.defaultIdleTimeout.
	// Applied to Sandboxes that don't carry an explicit idleTimeout.
	// +optional
	DefaultIdleTimeout *metav1.Duration `json:"defaultIdleTimeout,omitempty"`

	// NetworkPolicy, when set, enables sandbox egress filtering for every member
	// Pool of this Env. The operator injects a transparent filter sidecar into
	// each sandbox Pod; this policy is the Env-wide default, overridable per
	// sandbox at create time. Nil disables egress filtering (no sidecar).
	// +optional
	NetworkPolicy *SandboxNetworkPolicy `json:"networkPolicy,omitempty"`

	// UpdateStrategy is the Env-wide default rollout policy: when a member's
	// effective idle-Pod identity changes (Template edit, image / networkPolicy
	// override), whether and how fast its idle Pods are rebuilt. Per-member
	// EnvClusterMemberConfig.UpdateStrategy overrides this; see ResolveAutoUpdate
	// / ResolveMaxUnavailable for the resolution order.
	// +optional
	UpdateStrategy *EnvUpdateStrategy `json:"updateStrategy,omitempty"`
}

EnvOverridesSpec captures the SandboxTemplate fields this Env replaces uniformly across every member Pool. The Env represents a single class of sandbox runtime (e.g. an E2B-compatible sandbox or a SWE-ReX sandbox), so image / startup / idle / image-creation policy are expected to be shared; only per-Pool resource sizing and plugin metadata vary on the Member.

func (*EnvOverridesSpec) DeepCopy added in v0.0.5

func (in *EnvOverridesSpec) DeepCopy() *EnvOverridesSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvOverridesSpec.

func (*EnvOverridesSpec) DeepCopyInto added in v0.0.5

func (in *EnvOverridesSpec) DeepCopyInto(out *EnvOverridesSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type EnvScalingGroupStatus added in v0.0.5

type EnvScalingGroupStatus struct {
	// Name matches the autoscaling group's Name and is the list map key.
	// +required
	Name string `json:"name"`

	// TotalIdle / TotalRunning / TotalDesired aggregate across members.
	// +optional
	TotalIdle int32 `json:"totalIdle,omitempty"`
	// +optional
	TotalRunning int32 `json:"totalRunning,omitempty"`
	// +optional
	TotalDesired int32 `json:"totalDesired,omitempty"`
}

EnvScalingGroupStatus aggregates a scalingGroup's runtime state across all members. Per-Pool autoscaling bookkeeping (LastScaleUpTime, LastScaleDownTime, IdleZeroSince, etc.) lives on SandboxPool.Status.AutoScaling; this struct only carries cross-member aggregates.

func (*EnvScalingGroupStatus) DeepCopy added in v0.0.5

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvScalingGroupStatus.

func (*EnvScalingGroupStatus) DeepCopyInto added in v0.0.5

func (in *EnvScalingGroupStatus) DeepCopyInto(out *EnvScalingGroupStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type EnvUpdateStrategy added in v0.0.7

type EnvUpdateStrategy struct {
	// AutoUpdate toggles automatic rollout. When nil the value is inherited
	// (member → env → default true). Set false to freeze a member on its
	// current revision (e.g. to pin a fleet during an incident).
	// +optional
	AutoUpdate *bool `json:"autoUpdate,omitempty"`

	// MaxUnavailable bounds how many of a member Pool's desired idle Pods may be
	// unavailable at once during a rollout, as an absolute number or a
	// percentage of desired replicas (e.g. "20%"). Rounded down, floored at 1 so
	// small pools still make progress. When nil the value is inherited
	// (member → env → default "20%").
	// +optional
	// +kubebuilder:validation:XIntOrString
	MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
}

EnvUpdateStrategy controls automatic rollout of member Pools when their rendered idle-Pod identity (revision hash) changes. The only rollout mode is Recreate: stale idle Pods are deleted and re-created from the new spec; Pods that have been claimed (Running/Starting) are never disrupted — they roll on the next reconcile after they return to Idle.

func (*EnvUpdateStrategy) DeepCopy added in v0.0.7

func (in *EnvUpdateStrategy) DeepCopy() *EnvUpdateStrategy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvUpdateStrategy.

func (*EnvUpdateStrategy) DeepCopyInto added in v0.0.7

func (in *EnvUpdateStrategy) DeepCopyInto(out *EnvUpdateStrategy)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HandsAutoSpec added in v0.0.8

type HandsAutoSpec struct {
	// +required
	ClusterID string `json:"clusterID"`
	// +required
	TemplateRef string `json:"templateRef"`
	// +optional
	Image string `json:"image,omitempty"`
	// +required
	InstanceTypes []HandsInstanceType `json:"instanceTypes"`
	// +optional
	IdleTimeoutSeconds int32 `json:"idleTimeoutSeconds,omitempty"`
	// +optional
	StartupTimeoutSeconds int32 `json:"startupTimeoutSeconds,omitempty"`
}

HandsAutoSpec derives a SandboxEnv and its member pools.

func (*HandsAutoSpec) DeepCopy added in v0.0.8

func (in *HandsAutoSpec) DeepCopy() *HandsAutoSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HandsAutoSpec.

func (*HandsAutoSpec) DeepCopyInto added in v0.0.8

func (in *HandsAutoSpec) DeepCopyInto(out *HandsAutoSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HandsBinding added in v0.0.8

type HandsBinding struct {
	// Scope is the granularity a sandbox is bound at.
	// +kubebuilder:validation:Enum=thread;user
	// +kubebuilder:default=thread
	// +optional
	Scope string `json:"scope,omitempty"`

	// TimeoutSeconds is the sandbox IDLE timeout.
	// +optional
	TimeoutSeconds int32 `json:"timeoutSeconds,omitempty"`

	// ReadyTimeoutSeconds bounds how long a cold image pull may take.
	//
	// Note that readiness is not the same as usability: the sandbox API reports
	// a sandbox running before envd accepts commands, so callers must retry the
	// first command rather than trust the readiness flag alone.
	// +optional
	ReadyTimeoutSeconds int32 `json:"readyTimeoutSeconds,omitempty"`

	// AttachmentRoot is where staged attachments are flushed inside the sandbox,
	// written as root and world-readable so the agent can read but not alter
	// them.
	// +optional
	AttachmentRoot string `json:"attachmentRoot,omitempty"`

	// +optional
	MaxAttachmentBytes int64 `json:"maxAttachmentBytes,omitempty"`

	// Workspace is the FALLBACK sandbox working directory, used only when the
	// per-user directory cannot be resolved.
	// +optional
	Workspace string `json:"workspace,omitempty"`

	// SkipSeed suppresses the daemon's workspace seeding for images that already
	// carry it.
	// +optional
	SkipSeed bool `json:"skipSeed,omitempty"`

	// SeedRepo is cloned into the workspace on sandbox creation. Ignored when
	// SkipSeed is set.
	// +optional
	SeedRepo string `json:"seedRepo,omitempty"`
}

HandsBinding covers thread-to-sandbox lifecycle.

func (*HandsBinding) DeepCopy added in v0.0.8

func (in *HandsBinding) DeepCopy() *HandsBinding

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HandsBinding.

func (*HandsBinding) DeepCopyInto added in v0.0.8

func (in *HandsBinding) DeepCopyInto(out *HandsBinding)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HandsE2B added in v0.0.8

type HandsE2B struct {
	// CredentialsSecret carries E2B_API_KEY and AGBX_ENV_NAME, optionally
	// AGBX_HTTPS / E2B_DOMAIN / E2B_API_URL. It is consumed with envFrom, so
	// the Brain never has these values inlined in its pod spec.
	// +optional
	CredentialsSecret string `json:"credentialsSecret,omitempty"`
	// +optional
	APIURL string `json:"apiURL,omitempty"`
	// +optional
	Domain string `json:"domain,omitempty"`
	// +optional
	HTTPS *bool `json:"https,omitempty"`
}

HandsE2B is the sandbox API endpoint and credential.

func (*HandsE2B) DeepCopy added in v0.0.8

func (in *HandsE2B) DeepCopy() *HandsE2B

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HandsE2B.

func (*HandsE2B) DeepCopyInto added in v0.0.8

func (in *HandsE2B) DeepCopyInto(out *HandsE2B)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HandsEnvRef added in v0.0.8

type HandsEnvRef struct {
	// ClusterID scopes the env to one cluster. Empty means the local cluster.
	// +optional
	ClusterID string `json:"clusterID,omitempty"`
	// +required
	Name string `json:"name"`
	// Namespace of the SandboxEnv; empty means the agent's namespace.
	// +optional
	Namespace string `json:"namespace,omitempty"`
	// ScalingGroup pins every sandbox to one member pool unless a scenario
	// overrides it.
	// +optional
	ScalingGroup string `json:"scalingGroup,omitempty"`
	// Image overrides the sandbox main container image.
	//
	// Leaving this empty is not equivalent to "use a sensible default": a pool's
	// default image does not run envd, so sandboxes created without an override
	// come up and then answer every command with a 502. Either set it here or on
	// every scenario.
	// +optional
	Image string `json:"image,omitempty"`
}

HandsEnvRef references an existing SandboxEnv.

func (*HandsEnvRef) DeepCopy added in v0.0.8

func (in *HandsEnvRef) DeepCopy() *HandsEnvRef

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HandsEnvRef.

func (*HandsEnvRef) DeepCopyInto added in v0.0.8

func (in *HandsEnvRef) DeepCopyInto(out *HandsEnvRef)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HandsExternal added in v0.0.8

type HandsExternal struct {
	// APIURL is the E2B-compatible control endpoint.
	// +required
	APIURL string `json:"apiURL"`

	// Domain is the data-plane gateway, host plus any ingress path. Omitting the
	// path is the usual cause of "the sandbox exists but no port answers".
	// +required
	Domain string `json:"domain"`

	// +kubebuilder:default=true
	// +optional
	HTTPS *bool `json:"https,omitempty"`

	// EnvName is the name to launch from at the remote, written verbatim: a bare
	// environment ("navix"), or one scoped to a cluster ("cluster::navix").
	// +required
	EnvName string `json:"envName"`

	// Image overrides the sandbox main container image.
	//
	// A pool's default image does not run the sandbox command endpoint, so
	// leaving this empty yields sandboxes that start and then refuse every
	// command, with no error on the control plane.
	// +optional
	Image string `json:"image,omitempty"`

	// ScalingGroup pins every sandbox to one member pool at the remote.
	// +optional
	ScalingGroup string `json:"scalingGroup,omitempty"`

	// CredentialsRef supplies the remote's API key.
	// +optional
	CredentialsRef *SecretKeySelector `json:"credentialsRef,omitempty"`
}

HandsExternal describes a sandbox service owned by someone else.

This is what a deployment pointing at a different installation looks like: there is no SandboxEnv object to read, so nothing is reconciled and readiness is whatever the remote API reports at call time.

func (*HandsExternal) DeepCopy added in v0.0.8

func (in *HandsExternal) DeepCopy() *HandsExternal

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HandsExternal.

func (*HandsExternal) DeepCopyInto added in v0.0.8

func (in *HandsExternal) DeepCopyInto(out *HandsExternal)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HandsInstanceType added in v0.0.8

type HandsInstanceType struct {
	// Name is the member's identity. It is the instance-type catalog entry on
	// a cluster that has the catalog enabled, and the scaling group otherwise;
	// either way it is the name sandboxes are routed to.
	// +required
	Name string `json:"name"`

	// Resources sizes the member directly, for clusters with no instance-type
	// catalog. Setting it switches the member from a catalog lookup to an
	// inline size — on a cluster without a catalog, a member that only names
	// an instance type is rejected, and on one with a catalog these two ways
	// of sizing are mutually exclusive.
	// +optional
	Resources *corev1.ResourceRequirements `json:"resources,omitempty"`

	// +optional
	Replicas int32 `json:"replicas,omitempty"`
	// +optional
	MinReplicas *int32 `json:"minReplicas,omitempty"`
	// +optional
	MaxReplicas *int32 `json:"maxReplicas,omitempty"`
	// +optional
	Default bool `json:"default,omitempty"`
}

HandsInstanceType is one member pool of a derived SandboxEnv.

func (*HandsInstanceType) DeepCopy added in v0.0.8

func (in *HandsInstanceType) DeepCopy() *HandsInstanceType

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HandsInstanceType.

func (*HandsInstanceType) DeepCopyInto added in v0.0.8

func (in *HandsInstanceType) DeepCopyInto(out *HandsInstanceType)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HeaderInjection added in v0.0.8

type HeaderInjection struct {
	// Name is the header name, compared case-insensitively.
	Name string `json:"name"`

	// Value is a template that may reference declared credentials by name, each
	// name wrapped in a doubled pair of curly braces. For an Authorization
	// header, that is a Bearer prefix followed by the brace-wrapped name of the
	// credential holding the key.
	Value string `json:"value"`

	// Mode defaults to Override.
	// +optional
	Mode HeaderInjectionMode `json:"mode,omitempty"`
}

HeaderInjection is one header to add to matching requests.

func (*HeaderInjection) DeepCopy added in v0.0.8

func (in *HeaderInjection) DeepCopy() *HeaderInjection

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HeaderInjection.

func (*HeaderInjection) DeepCopyInto added in v0.0.8

func (in *HeaderInjection) DeepCopyInto(out *HeaderInjection)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HeaderInjectionMode added in v0.0.8

type HeaderInjectionMode string

HeaderInjectionMode selects how an injected header interacts with one the sandbox already set. +kubebuilder:validation:Enum=Override;IfAbsent

const (
	// HeaderInjectionOverride replaces whatever the sandbox sent. The default.
	HeaderInjectionOverride HeaderInjectionMode = "Override"
	// HeaderInjectionIfAbsent injects only when the sandbox sent no such header,
	// so an agent that supplies its own credential keeps it.
	HeaderInjectionIfAbsent HeaderInjectionMode = "IfAbsent"
)

type InjectedCredential added in v0.0.8

type InjectedCredential struct {
	// Name is how rules refer to this credential in a value template: the
	// credential name wrapped in a doubled pair of curly braces.
	Name string `json:"name"`

	// ValueFrom points at the Secret key holding the credential. The Secret
	// must live in the SandboxEnv's namespace.
	ValueFrom SecretKeyRef `json:"valueFrom"`

	// ExposeAs turns on placeholder mode: the sandbox gets an environment
	// variable of this name whose value is a decoy (see Placeholder), and the
	// proxy swaps the decoy for the real value on hosts that allow it. Leave
	// empty to use the credential through header injection only.
	// +optional
	ExposeAs string `json:"exposeAs,omitempty"`

	// Placeholder is the decoy value handed to the sandbox. Empty means a fresh
	// random "agbx_ph_<32 hex>" per claim.
	//
	// Set it when a client validates credential shape before sending — several
	// SDKs reject a key that lacks the expected prefix or length, so a random
	// decoy would fail inside the sandbox and never reach the proxy. A fixed
	// decoy costs nothing in secrecy (it already lives in the sandbox's
	// environment); it is merely identical across sandboxes.
	//
	// Must be at least 16 characters, and no two credentials may share a
	// placeholder or have one be a substring of another — overlapping decoys
	// would substitute into each other.
	// +optional
	Placeholder string `json:"placeholder,omitempty"`
}

InjectedCredential is one named credential.

func (*InjectedCredential) DeepCopy added in v0.0.8

func (in *InjectedCredential) DeepCopy() *InjectedCredential

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InjectedCredential.

func (*InjectedCredential) DeepCopyInto added in v0.0.8

func (in *InjectedCredential) DeepCopyInto(out *InjectedCredential)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type InjectionRule added in v0.0.8

type InjectionRule struct {
	// Host must be an exact hostname. Wildcards are rejected: anyone able to
	// control a matching subdomain would receive the credential.
	Host string `json:"host"`

	// Ports narrows which destination ports the rule covers. Defaults to
	// [80, 443]; other ports get no L7 handling at all.
	// +optional
	Ports []int32 `json:"ports,omitempty"`

	// Headers are the headers to inject.
	// +optional
	Headers []HeaderInjection `json:"headers,omitempty"`

	// Substitute lists credentials whose placeholder may be swapped for the
	// real value on this host.
	// +optional
	Substitute []string `json:"substitute,omitempty"`

	// PathPrefixes narrows the rule to matching request paths. Empty means all.
	// +optional
	PathPrefixes []string `json:"pathPrefixes,omitempty"`

	// Methods narrows the rule to these HTTP methods. Empty means all.
	// +optional
	Methods []string `json:"methods,omitempty"`
}

InjectionRule declares the injection applied to one host.

func (*InjectionRule) DeepCopy added in v0.0.8

func (in *InjectionRule) DeepCopy() *InjectionRule

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InjectionRule.

func (*InjectionRule) DeepCopyInto added in v0.0.8

func (in *InjectionRule) DeepCopyInto(out *InjectionRule)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type LangfuseSpec added in v0.0.8

type LangfuseSpec struct {
	// +optional
	Enabled *bool `json:"enabled,omitempty"`
	// +optional
	BaseURL string `json:"baseURL,omitempty"`
	// +optional
	PublicKeyRef *SecretKeySelector `json:"publicKeyRef,omitempty"`
	// +optional
	SecretKeyRef *SecretKeySelector `json:"secretKeyRef,omitempty"`
	// Environment separates deployments inside one Langfuse project. Changing it
	// on a live agent splits its history from every trace recorded before, with
	// no way to merge the two afterwards.
	// +optional
	Environment string `json:"environment,omitempty"`
}

LangfuseSpec configures trace export.

func (*LangfuseSpec) DeepCopy added in v0.0.8

func (in *LangfuseSpec) DeepCopy() *LangfuseSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LangfuseSpec.

func (*LangfuseSpec) DeepCopyInto added in v0.0.8

func (in *LangfuseSpec) DeepCopyInto(out *LangfuseSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type MCPServerSpec added in v0.0.8

type MCPServerSpec struct {
	// +required
	Name string `json:"name"`
	// +kubebuilder:validation:Enum=http;sse;stdio
	// +required
	Transport string `json:"transport"`
	// +optional
	URL string `json:"url,omitempty"`
	// Command runs a stdio server inside the Brain container.
	// +optional
	Command []string `json:"command,omitempty"`
	// HeadersFrom supplies auth headers from a Secret.
	// +optional
	HeadersFrom *SecretKeySelector `json:"headersFrom,omitempty"`
}

MCPServerSpec is one registered MCP server.

func (*MCPServerSpec) DeepCopy added in v0.0.8

func (in *MCPServerSpec) DeepCopy() *MCPServerSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MCPServerSpec.

func (*MCPServerSpec) DeepCopyInto added in v0.0.8

func (in *MCPServerSpec) DeepCopyInto(out *MCPServerSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgent added in v0.0.8

type ManagedAgent struct {
	metav1.TypeMeta `json:",inline"`

	// metadata is a standard object metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitzero"`

	// spec defines the desired state of ManagedAgent
	// +required
	Spec ManagedAgentSpec `json:"spec"`

	// status defines the observed state of ManagedAgent
	// +optional
	Status ManagedAgentStatus `json:"status,omitzero"`
}

ManagedAgent is the Schema for the managedagents API.

func (*ManagedAgent) DeepCopy added in v0.0.8

func (in *ManagedAgent) DeepCopy() *ManagedAgent

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgent.

func (*ManagedAgent) DeepCopyInto added in v0.0.8

func (in *ManagedAgent) DeepCopyInto(out *ManagedAgent)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*ManagedAgent) DeepCopyObject added in v0.0.8

func (in *ManagedAgent) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type ManagedAgentBrain added in v0.0.8

type ManagedAgentBrain struct {
	// GatewayPort is the agent gateway's port — the one contract callers use.
	// +kubebuilder:default=4099
	// +optional
	GatewayPort int32 `json:"gatewayPort,omitempty"`

	// WorkspaceFSPort serves attachment staging and the workspace file browser.
	// It is a separate process from the gateway and must be exposed for the
	// file panel and attachment upload to work at all.
	// +kubebuilder:default=8766
	// +optional
	WorkspaceFSPort int32 `json:"workspaceFSPort,omitempty"`

	// +optional
	Resources corev1.ResourceRequirements `json:"resources,omitzero"`
	// +optional
	NodeSelector map[string]string `json:"nodeSelector,omitempty"`
	// +optional
	Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
	// +optional
	Affinity *corev1.Affinity `json:"affinity,omitempty"`
	// +optional
	ServiceAccountName string `json:"serviceAccountName,omitempty"`

	// ExtraEnv is passed to the Brain verbatim, secretKeyRef included. See the
	// note on ManagedAgentSpec: this is where tenant-specific configuration
	// lives until (and unless) it earns a first-class field.
	// +optional
	ExtraEnv []corev1.EnvVar `json:"extraEnv,omitempty"`

	// +optional
	ExtraEnvFrom []corev1.EnvFromSource `json:"extraEnvFrom,omitempty"`
	// +optional
	ExtraVolumes []corev1.Volume `json:"extraVolumes,omitempty"`
	// +optional
	ExtraVolumeMounts []corev1.VolumeMount `json:"extraVolumeMounts,omitempty"`
	// ExtraPorts exposes additional in-pod processes (a vendor MCP server, for
	// instance) on the Brain Service.
	// +optional
	ExtraPorts []corev1.ContainerPort `json:"extraPorts,omitempty"`
}

ManagedAgentBrain tunes the Brain Deployment.

func (*ManagedAgentBrain) DeepCopy added in v0.0.8

func (in *ManagedAgentBrain) DeepCopy() *ManagedAgentBrain

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentBrain.

func (*ManagedAgentBrain) DeepCopyInto added in v0.0.8

func (in *ManagedAgentBrain) DeepCopyInto(out *ManagedAgentBrain)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentClassifier added in v0.0.8

type ManagedAgentClassifier struct {
	// +kubebuilder:default=true
	// +optional
	Enabled *bool `json:"enabled,omitempty"`
	// +kubebuilder:validation:Enum=anthropic-messages;openai-chat
	// +optional
	Wire string `json:"wire,omitempty"`
	// +optional
	BaseURL string `json:"baseURL,omitempty"`
	// +optional
	CredentialsRef *SecretKeySelector `json:"credentialsRef,omitempty"`
	// Model must be a non-reasoning id (see ManagedAgentModel.NonReasoning).
	// +optional
	Model string `json:"model,omitempty"`
	// +optional
	MaxTokens int32 `json:"maxTokens,omitempty"`
	// +optional
	MaxContextChars int32 `json:"maxContextChars,omitempty"`
	// TimeoutSeconds must stay below any reverse proxy read timeout in front of
	// the Brain; a classifier timeout fails safe to "same topic".
	// +optional
	TimeoutSeconds int32 `json:"timeoutSeconds,omitempty"`
}

ManagedAgentClassifier configures the topic-switch check.

func (*ManagedAgentClassifier) DeepCopy added in v0.0.8

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentClassifier.

func (*ManagedAgentClassifier) DeepCopyInto added in v0.0.8

func (in *ManagedAgentClassifier) DeepCopyInto(out *ManagedAgentClassifier)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentHands added in v0.0.8

type ManagedAgentHands struct {
	// EnvRef reuses an existing SandboxEnv. The controller only probes it; it
	// writes nothing on the worker side.
	// +optional
	EnvRef *HandsEnvRef `json:"envRef,omitempty"`

	// Auto derives a SandboxEnv named "<agent>-hands" with one member pool per
	// instance type, named "<agent>-hands-<instanceType>".
	// +optional
	Auto *HandsAutoSpec `json:"auto,omitempty"`

	// External points at an E2B-compatible sandbox service this control plane
	// does not own — another AgentBox installation, or a managed offering. The
	// platform never inspects or reconciles it; the Brain simply speaks the API.
	// +optional
	External *HandsExternal `json:"external,omitempty"`

	// Binding covers how a thread is tied to a sandbox.
	// +optional
	Binding *HandsBinding `json:"binding,omitempty"`

	// E2B is the endpoint and credential the Brain uses to reach the sandbox
	// API. When omitted, the Brain falls back to in-cluster service DNS, which
	// only works on a cluster that runs the worker chart.
	// +optional
	E2B *HandsE2B `json:"e2b,omitempty"`
}

ManagedAgentHands declares sandbox supply.

func (*ManagedAgentHands) DeepCopy added in v0.0.8

func (in *ManagedAgentHands) DeepCopy() *ManagedAgentHands

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentHands.

func (*ManagedAgentHands) DeepCopyInto added in v0.0.8

func (in *ManagedAgentHands) DeepCopyInto(out *ManagedAgentHands)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentImage added in v0.0.8

type ManagedAgentImage struct {
	// +required
	Repository string `json:"repository"`
	// +optional
	Tag string `json:"tag,omitempty"`
	// +kubebuilder:validation:Enum=Always;IfNotPresent;Never
	// +optional
	PullPolicy corev1.PullPolicy `json:"pullPolicy,omitempty"`
	// +optional
	PullSecrets []corev1.LocalObjectReference `json:"pullSecrets,omitempty"`
}

ManagedAgentImage is the Brain container image.

func (*ManagedAgentImage) DeepCopy added in v0.0.8

func (in *ManagedAgentImage) DeepCopy() *ManagedAgentImage

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentImage.

func (*ManagedAgentImage) DeepCopyInto added in v0.0.8

func (in *ManagedAgentImage) DeepCopyInto(out *ManagedAgentImage)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentIngress added in v0.0.8

type ManagedAgentIngress struct {
	// Enabled publishes the agent. While false the shared route answers 404 for
	// this agent's name, so an agent is never reachable from outside by
	// accident — being deployed is not the same as being published.
	// +kubebuilder:default=false
	// +optional
	Enabled bool `json:"enabled,omitempty"`
}

ManagedAgentIngress publishes one agent to callers outside the cluster.

There is no host or path here: publishing is a single shared route on the control-plane proxy, and the agent's name in that route is what selects it. One route means one hostname, one certificate and one authenticating hop for every agent, so a caller holds a single base URL and a single key for the whole platform.

func (*ManagedAgentIngress) DeepCopy added in v0.0.8

func (in *ManagedAgentIngress) DeepCopy() *ManagedAgentIngress

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentIngress.

func (*ManagedAgentIngress) DeepCopyInto added in v0.0.8

func (in *ManagedAgentIngress) DeepCopyInto(out *ManagedAgentIngress)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentList added in v0.0.8

type ManagedAgentList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitzero"`
	Items           []ManagedAgent `json:"items"`
}

ManagedAgentList contains a list of ManagedAgent.

func (*ManagedAgentList) DeepCopy added in v0.0.8

func (in *ManagedAgentList) DeepCopy() *ManagedAgentList

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentList.

func (*ManagedAgentList) DeepCopyInto added in v0.0.8

func (in *ManagedAgentList) DeepCopyInto(out *ManagedAgentList)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*ManagedAgentList) DeepCopyObject added in v0.0.8

func (in *ManagedAgentList) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type ManagedAgentModel added in v0.0.8

type ManagedAgentModel struct {
	// +required
	ID string `json:"id"`
	// +optional
	Name string `json:"name,omitempty"`
	// NonReasoning marks a model eligible to back the topic classifier. A
	// reasoning model spends its completion budget on the chain of thought and
	// returns empty content, which reads as "same topic" every time.
	// +optional
	NonReasoning bool `json:"nonReasoning,omitempty"`
}

ManagedAgentModel is one entry of a harness's model dropdown.

func (*ManagedAgentModel) DeepCopy added in v0.0.8

func (in *ManagedAgentModel) DeepCopy() *ManagedAgentModel

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentModel.

func (*ManagedAgentModel) DeepCopyInto added in v0.0.8

func (in *ManagedAgentModel) DeepCopyInto(out *ManagedAgentModel)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentObservability added in v0.0.8

type ManagedAgentObservability struct {
	// +optional
	Langfuse *LangfuseSpec `json:"langfuse,omitempty"`
}

ManagedAgentObservability is telemetry configuration.

func (*ManagedAgentObservability) DeepCopy added in v0.0.8

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentObservability.

func (*ManagedAgentObservability) DeepCopyInto added in v0.0.8

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentOwner added in v0.0.8

type ManagedAgentOwner struct {
	// +optional
	Team string `json:"team,omitempty"`
	// +optional
	User string `json:"user,omitempty"`
}

ManagedAgentOwner identifies who the agent belongs to.

Both fields come from the caller's credentials at creation time. They are recorded in the spec so the object is self-describing (and re-appliable), but the API overwrites them on create and rejects changes on update.

func (*ManagedAgentOwner) DeepCopy added in v0.0.8

func (in *ManagedAgentOwner) DeepCopy() *ManagedAgentOwner

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentOwner.

func (*ManagedAgentOwner) DeepCopyInto added in v0.0.8

func (in *ManagedAgentOwner) DeepCopyInto(out *ManagedAgentOwner)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentPrompt added in v0.0.8

type ManagedAgentPrompt struct {
	// Inline is the prompt text.
	// +optional
	Inline string `json:"inline,omitempty"`
	// From reads the prompt from a ConfigMap key. Takes precedence over Inline.
	// +optional
	From *ConfigMapKeySelector `json:"from,omitempty"`
	// Append is added after whatever the harness's own preset contributes.
	// +optional
	Append string `json:"append,omitempty"`
}

ManagedAgentPrompt is the shared base system prompt.

func (*ManagedAgentPrompt) DeepCopy added in v0.0.8

func (in *ManagedAgentPrompt) DeepCopy() *ManagedAgentPrompt

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentPrompt.

func (*ManagedAgentPrompt) DeepCopyInto added in v0.0.8

func (in *ManagedAgentPrompt) DeepCopyInto(out *ManagedAgentPrompt)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentRuntime added in v0.0.8

type ManagedAgentRuntime struct {
	// Default is the harness a conversation starts under when the caller picks
	// none. Every CONFIGURED harness is served regardless — the browser has a
	// picker — so this is a default, not a restriction.
	// +kubebuilder:validation:Enum=claude-code;opencode
	// +required
	Default string `json:"default"`

	// ClaudeCode speaks the Anthropic Messages API. Anthropic does not support
	// routing Claude Code at non-Claude models, so baseURL must serve them.
	// +optional
	ClaudeCode *ClaudeCodeRuntime `json:"claudeCode,omitempty"`

	// OpenCode speaks an OpenAI-compatible API.
	// +optional
	OpenCode *OpenCodeRuntime `json:"opencode,omitempty"`
}

ManagedAgentRuntime declares the harnesses served by this agent.

func (*ManagedAgentRuntime) DeepCopy added in v0.0.8

func (in *ManagedAgentRuntime) DeepCopy() *ManagedAgentRuntime

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentRuntime.

func (*ManagedAgentRuntime) DeepCopyInto added in v0.0.8

func (in *ManagedAgentRuntime) DeepCopyInto(out *ManagedAgentRuntime)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentScenario added in v0.0.8

type ManagedAgentScenario struct {
	// Name is the identifier callers pass on /run. DNS-1123 label.
	// +required
	Name string `json:"name"`

	// +optional
	DisplayName string `json:"displayName,omitempty"`

	// Default marks the scenario used when a caller names none. Exactly one.
	// +optional
	Default bool `json:"default,omitempty"`

	// Prompt is APPENDED to spec.prompt, never substituted.
	// +optional
	Prompt *ManagedAgentPrompt `json:"prompt,omitempty"`

	// Runtime pins this scenario to one harness. Unattended flows should pin,
	// so a user switching harness in the console does not drag background
	// analysis onto an unverified model configuration.
	// +kubebuilder:validation:Enum=claude-code;opencode
	// +optional
	Runtime string `json:"runtime,omitempty"`

	// Model overrides the harness default for this scenario.
	// +optional
	Model string `json:"model,omitempty"`

	// Allow is the tool allow-list: which registered MCP servers and
	// client-side tools this scenario may see. The sandbox toolset and
	// AskUserQuestion are not listed here — they are on by default.
	//
	// Registration (spec.tools) and visibility (this field) are separate on
	// purpose, and visibility is DENY BY DEFAULT: forgetting to configure a
	// scenario must fail towards "the tool is invisible", never towards "the
	// agent can post to a chat group". Visibility is computed server-side and
	// decides which tools are registered with the harness at all — an unlisted
	// tool is absent from the model's tool list rather than rejected at call
	// time, which would burn turns and leak the tool's existence.
	// +optional
	Allow []string `json:"allow,omitempty"`

	// Disable removes individual sandbox tools (bash, read, write, edit, grep,
	// glob, apply_patch) from this scenario.
	// +optional
	Disable []string `json:"disable,omitempty"`

	// Interactive false means the agent cannot ask the user a question: its
	// prompts degrade to plain text instead of rendering a card nobody can
	// click. Unattended flows must set this false.
	// +kubebuilder:default=true
	// +optional
	Interactive *bool `json:"interactive,omitempty"`

	// SandboxEnv is injected into the sandbox at CREATE time and is immutable
	// for that sandbox's life. That is why a thread is bound to one scenario
	// when it is created and cannot switch afterwards.
	// +optional
	SandboxEnv []corev1.EnvVar `json:"sandboxEnv,omitempty"`

	// ScalingGroup routes this scenario's sandboxes to one member pool
	// (rendered as the reserved metadata key agentbox.scitix.ai/scaling-group).
	// +optional
	ScalingGroup string `json:"scalingGroup,omitempty"`

	// Image overrides the sandbox image for this scenario while still reusing
	// the same SandboxEnv and warm pool.
	// +optional
	Image string `json:"image,omitempty"`

	// Exposed false hides the scenario from the console picker and the public
	// scenario list; callers may still name it explicitly.
	// +kubebuilder:default=true
	// +optional
	Exposed *bool `json:"exposed,omitempty"`
}

ManagedAgentScenario is one slice of an agent: same image, same base prompt, different persona and different visible tools.

func (*ManagedAgentScenario) DeepCopy added in v0.0.8

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentScenario.

func (*ManagedAgentScenario) DeepCopyInto added in v0.0.8

func (in *ManagedAgentScenario) DeepCopyInto(out *ManagedAgentScenario)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentSession added in v0.0.8

type ManagedAgentSession struct {
	// +optional
	Persistence *SessionPersistence `json:"persistence,omitempty"`
	// RetentionDays prunes threads older than this. Zero means keep forever.
	// +optional
	RetentionDays int32 `json:"retentionDays,omitempty"`
}

ManagedAgentSession covers thread persistence.

func (*ManagedAgentSession) DeepCopy added in v0.0.8

func (in *ManagedAgentSession) DeepCopy() *ManagedAgentSession

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentSession.

func (*ManagedAgentSession) DeepCopyInto added in v0.0.8

func (in *ManagedAgentSession) DeepCopyInto(out *ManagedAgentSession)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentSpec added in v0.0.8

type ManagedAgentSpec struct {
	// DisplayName is shown in the console. Defaults to metadata.name.
	// +optional
	DisplayName string `json:"displayName,omitempty"`

	// Description is free-form text for the console.
	// +optional
	Description string `json:"description,omitempty"`

	// Owner is stamped from the authenticated caller when the agent is created
	// and is not settable through the console. An agent belongs to one person,
	// not to their whole team: a teammate listing agents does not see it, and a
	// request for it is answered 404 rather than 403 — whether someone else's
	// agent exists is itself not disclosed.
	// +optional
	Owner *ManagedAgentOwner `json:"owner,omitempty"`

	// Image is the Brain image. It must ship every harness listed under
	// `runtime`, plus the sandbox daemon and the workspace-fs server.
	// +required
	Image ManagedAgentImage `json:"image"`

	// Runtime declares which harnesses this agent can serve and how each reaches
	// its model endpoint. At least one must be configured, otherwise the Brain
	// starts and reports every harness unavailable through GET /backends.
	// +required
	Runtime ManagedAgentRuntime `json:"runtime"`

	// Classifier configures the one-shot "is this a new topic?" check. It is
	// deliberately NOT part of `runtime`: reusing a harness's model would make
	// the check's cost and behaviour change whenever a user switches harness.
	// +optional
	Classifier *ManagedAgentClassifier `json:"classifier,omitempty"`

	// Prompt is the base system prompt shared by every scenario — the sandbox
	// contract (what exists in the image, what the cwd is, what gets reclaimed).
	// Scenario prompts are APPENDED to it, never substituted: a statement that
	// stops being true when the scenario changes does not belong here.
	// +optional
	Prompt *ManagedAgentPrompt `json:"prompt,omitempty"`

	// Scenarios are the agent's slices. Each bundles a prompt addendum, a tool
	// allow-list, an optional harness pin and sandbox env. Exactly one entry
	// must set `default: true`.
	// +optional
	// +listType=map
	// +listMapKey=name
	Scenarios []ManagedAgentScenario `json:"scenarios,omitempty"`

	// Tools is the registry: which MCP servers and client-side tools exist, how
	// to reach them and where their credentials live.
	//
	// Registration is not visibility. A registered tool is invisible until some
	// scenario names it in `allow`, and visibility is computed server-side into
	// the tool set the harness is given — an unlisted tool is absent from the
	// model's tool list rather than refused at call time, which would burn turns
	// and disclose that it exists.
	// +optional
	Tools *ToolPolicySpec `json:"tools,omitempty"`

	// Ingress publishes this agent outside the cluster.
	//
	// Traffic never reaches the Brain directly. The Brain authenticates nothing
	// — it takes the caller's word for which end user is asking, which is safe
	// only because it is unreachable from outside — so exposing it as-is would
	// let anyone read every tenant's threads and drive the agent's tools.
	// External callers arrive through the control-plane proxy, which checks the
	// API key and that the key's owner may use this agent before forwarding.
	// +optional
	Ingress *ManagedAgentIngress `json:"ingress,omitempty"`

	// Hands declares sandbox supply: reference an existing SandboxEnv, derive
	// one, or point at an external service. Exactly one branch must be set.
	// +required
	Hands ManagedAgentHands `json:"hands"`

	// Session covers thread persistence.
	// +optional
	Session *ManagedAgentSession `json:"session,omitempty"`

	// Observability is Langfuse today.
	// +optional
	Observability *ManagedAgentObservability `json:"observability,omitempty"`

	// Docs is operator-supplied Markdown shown as the agent's landing tab in the
	// console: how to reach this agent, what its scenarios mean, which tools they
	// expose. It travels with the object rather than being compiled into the
	// console so a deployment can write it in its own language and keep it
	// accurate for its own conventions.
	// +optional
	Docs string `json:"docs,omitempty"`

	// Brain tunes the Deployment. Replicas are always 1 with strategy Recreate:
	// the session-to-sandbox map lives in the daemon's memory and sandbox
	// handles cannot be recovered across processes (the E2B layer answers
	// `Sandbox.connect` with "not supported in AgentBox"), so a second replica
	// would silently create a second sandbox for the same thread.
	// +optional
	Brain *ManagedAgentBrain `json:"brain,omitempty"`
}

ManagedAgentSpec declares one hosted agent: a Brain (the harness-independent agent runtime, one Deployment per agent) plus the Hands it reaches for (a SandboxEnv, either referenced or derived).

The field layout deliberately splits two kinds of configuration:

  • PLATFORM INVARIANTS get first-class fields. Anything whose misconfiguration would break an isolation guarantee or fail silently — identity, tool visibility, sandbox binding, session storage — is modelled here so the controller, not the tenant, owns it.
  • TENANT-SPECIFIC configuration rides `brain.extraEnv` / `extraVolumes` / `extraPorts`. These are a deliberate escape hatch, not a dumping ground: anything that turns out to be common across agents should graduate into a first-class field. They exist because a hosted agent inevitably carries business configuration the platform has no business understanding (an upstream API base, a credentials file, a vendor MCP port).

func (*ManagedAgentSpec) DeepCopy added in v0.0.8

func (in *ManagedAgentSpec) DeepCopy() *ManagedAgentSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentSpec.

func (*ManagedAgentSpec) DeepCopyInto added in v0.0.8

func (in *ManagedAgentSpec) DeepCopyInto(out *ManagedAgentSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ManagedAgentStatus added in v0.0.8

type ManagedAgentStatus struct {
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`

	// Phase is a coarse rollup: Pending, Provisioning, Ready, Degraded, Failed.
	// +optional
	Phase string `json:"phase,omitempty"`

	// Endpoint is the in-cluster URL of the agent gateway. It reaches the Brain
	// directly and is therefore unauthenticated — only ever hand it to callers
	// already inside the cluster.
	// +optional
	Endpoint string `json:"endpoint,omitempty"`

	// PublicURL is the address external callers use, set only while the agent
	// is published. Unlike Endpoint it goes through the authenticating proxy,
	// so a caller needs an API key whose owner may use this agent.
	// +optional
	PublicURL string `json:"publicURL,omitempty"`

	// Hands reports the resolved sandbox supply.
	// +optional
	Hands *ResolvedHands `json:"hands,omitempty"`

	// Backends mirrors the Brain's own view of each harness, including why one
	// is unavailable. A harness failing preflight is reported here rather than
	// taking the pod down — a bad model credential must not stop the other
	// processes in the pod from serving.
	// +optional
	Backends []BackendStatus `json:"backends,omitempty"`

	// Scenarios lists the scenario names currently served.
	// +optional
	Scenarios []string `json:"scenarios,omitempty"`

	// +optional
	// +listType=map
	// +listMapKey=type
	Conditions []metav1.Condition `json:"conditions,omitempty"`
}

ManagedAgentStatus is the observed state.

func (*ManagedAgentStatus) DeepCopy added in v0.0.8

func (in *ManagedAgentStatus) DeepCopy() *ManagedAgentStatus

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentStatus.

func (*ManagedAgentStatus) DeepCopyInto added in v0.0.8

func (in *ManagedAgentStatus) DeepCopyInto(out *ManagedAgentStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type MemberMetadata added in v0.0.5

type MemberMetadata struct {
	// Labels are the candidate Pool's metadata.labels post-PreCreatePool.
	// +optional
	Labels map[string]string `json:"labels,omitempty"`

	// Annotations are the candidate Pool's metadata.annotations post-PreCreatePool.
	// +optional
	Annotations map[string]string `json:"annotations,omitempty"`
}

MemberMetadata is the mutable subset of a candidate SandboxPool's ObjectMeta that the Env Reconciler propagates onto the live Pool. It exists as a dedicated type (not metav1.ObjectMeta) because controller-gen emits only a degenerate `type: object` schema for an embedded ObjectMeta inside a non-root CRD field, and the K8s API server then prunes every sub-field at admission time — silently dropping Labels/Annotations the AddMember flow just wrote.

Fields are deliberately limited to what survives the round-trip from RenderSandboxPool + PreCreatePool back onto the live Pool:

  • Labels/Annotations: identity (team/user) + plugin-added routing keys.
  • Finalizers are intentionally absent — SandboxPoolReconciler manages the Pool's finalizer lifecycle directly.
  • Name/Namespace/UID/ResourceVersion/etc. are server- or Env-owned and don't belong on a per-member snapshot.

func (*MemberMetadata) DeepCopy added in v0.0.5

func (in *MemberMetadata) DeepCopy() *MemberMetadata

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MemberMetadata.

func (*MemberMetadata) DeepCopyInto added in v0.0.5

func (in *MemberMetadata) DeepCopyInto(out *MemberMetadata)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ObservedMemberState added in v0.0.5

type ObservedMemberState string

ObservedMemberState summarises whether a member Pool can serve requests. +kubebuilder:validation:Enum=Active;Saturated;Missing;Inconsistent

const (
	// ObservedMemberStateActive: member Pool exists and is eligible for routing/scaling.
	ObservedMemberStateActive ObservedMemberState = "Active"
	// ObservedMemberStateSaturated: member hit its maxReplicas or returned InsufficientQuota.
	ObservedMemberStateSaturated ObservedMemberState = "Saturated"
	// ObservedMemberStateMissing: member Pool no longer exists in the cluster.
	ObservedMemberStateMissing ObservedMemberState = "Missing"
	// ObservedMemberStateInconsistent: member Pool references a different
	// SandboxTemplate than the Env's templateRef.name. Template *version* is
	// not part of this judgement — the cluster holds a single mutable
	// SandboxTemplate per name, so spec.version is a human-maintained label
	// rather than a resolvable revision. Whether a member has converged onto
	// the Template's current body is answered by the revision hash
	// (status.updateRevision vs the Pool's currentRevision), surfaced through
	// the TemplateConsistent condition's RolloutInProgress reason.
	ObservedMemberStateInconsistent ObservedMemberState = "Inconsistent"
)

type OpenCodeRuntime added in v0.0.8

type OpenCodeRuntime struct {
	// Enabled withdraws the harness from the picker AND stops the entrypoint
	// from launching its server — one value drives both, so the picker can never
	// offer a harness whose server nobody started.
	// +kubebuilder:default=true
	// +optional
	Enabled *bool `json:"enabled,omitempty"`

	// Port is the loopback port for `opencode serve`.
	// +kubebuilder:default=4096
	// +optional
	Port int32 `json:"port,omitempty"`

	// BaseURL is the OpenAI-compatible endpoint this harness may reach.
	// +optional
	BaseURL string `json:"baseURL,omitempty"`

	// CredentialsRef supplies the provider API key. The console collects the key
	// itself and the platform materialises this reference; it can also be set
	// directly to an existing Secret.
	// +optional
	CredentialsRef *SecretKeySelector `json:"credentialsRef,omitempty"`

	// Models is the exact in-composer dropdown for this harness.
	// +optional
	Models []ManagedAgentModel `json:"models,omitempty"`

	// +optional
	DefaultModel string `json:"defaultModel,omitempty"`

	// ProviderID names the single provider in the generated config. It is not
	// cosmetic: every model is addressed as "<providerID>/<model-id>", so this
	// string is part of the model identity the composer sends back. Changing it
	// on a live agent invalidates whatever model ids callers have stored.
	// +kubebuilder:default=platform
	// +optional
	ProviderID string `json:"providerID,omitempty"`

	// ProviderName is the provider's display label in the model picker.
	// +optional
	ProviderName string `json:"providerName,omitempty"`

	// Overlay is harness configuration the platform does not model: plugins,
	// telemetry switches, tool output limits. It is merged *underneath* the
	// generated keys, so an overlay cannot widen the provider allow-list,
	// repoint the endpoint, or re-enable a gated tool — the keys that decide
	// where data goes stay generated.
	//
	// This is the seam that keeps the CRD from growing a field per harness
	// knob. Use ConfigSecretRef instead only when you want no generated config
	// at all.
	// +optional
	Overlay *apiextensionsv1.JSON `json:"overlay,omitempty"`

	// ConfigSecretRef brings your own opencode.json instead of the generated
	// one. It bypasses the provider allow-list above, so a hand-managed config
	// must set `enabled_providers` itself.
	// +optional
	ConfigSecretRef *SecretKeySelector `json:"configSecretRef,omitempty"`
}

OpenCodeRuntime configures the OpenCode harness.

OpenCode is pinned to exactly one OpenAI-compatible provider. Left to itself it also loads every provider it can reach without credentials — including its vendor's own hosted free models — which would put both in the model picker and reachable by model id, i.e. this deployment's data leaving for a third party. The rendered config therefore carries a server-side allow-list naming only the provider below, so an unlisted provider is not merely hidden but unusable.

func (*OpenCodeRuntime) DeepCopy added in v0.0.8

func (in *OpenCodeRuntime) DeepCopy() *OpenCodeRuntime

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenCodeRuntime.

func (*OpenCodeRuntime) DeepCopyInto added in v0.0.8

func (in *OpenCodeRuntime) DeepCopyInto(out *OpenCodeRuntime)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type PodCreationImagePolicy

type PodCreationImagePolicy string

PodCreationImagePolicy defines which image createPod should use. +kubebuilder:validation:Enum=PoolDefaultImage;IdleImage

const (
	// PodCreationImagePolicyPoolDefaultImage preserves the template container image.
	// This matches the current createPod behavior and enables the same-image fast path.
	PodCreationImagePolicyPoolDefaultImage PodCreationImagePolicy = "PoolDefaultImage"
	// PodCreationImagePolicyIdleImage replaces the first container image with
	// spec.idleImage when a Pod is created, so Pods enter Idle faster.
	PodCreationImagePolicyIdleImage PodCreationImagePolicy = "IdleImage"
)

type PoolAutoScalingStatus added in v0.0.5

type PoolAutoScalingStatus struct {
	// LastScaleUpTime is the wall-clock time of the most recent
	// scale-up that actually increased spec.replicas (the probe
	// accepted at least one additional replica). Drives the success
	// cooldown gate (scaleUpPolicy.cooldownSeconds).
	// +optional
	LastScaleUpTime *metav1.Time `json:"lastScaleUpTime,omitempty"`

	// LastScaleDownTime is the wall-clock time of the most recent
	// successful scale-down (spec.replicas decreased) on this Pool. Drives
	// scaleDownPolicy.stabilizationSeconds.
	// +optional
	LastScaleDownTime *metav1.Time `json:"lastScaleDownTime,omitempty"`

	// IdleZeroSince is the wall-clock time at which this Pool's idle
	// replica count first dropped to zero in the current continuous-zero
	// window. Cleared the instant idle > 0 is observed. Drives the
	// proactive scaleUpPolicy.idleThresholdSeconds trigger.
	// +optional
	IdleZeroSince *metav1.Time `json:"idleZeroSince,omitempty"`

	// LastScaleUpAttemptTime records when the autoscaler last invoked
	// the admission probe for a scale-up, regardless of whether the
	// probe accepted the target. Together with LastScaleUpAttemptResult
	// and the group's SaturationCooldownSeconds it drives the saturation
	// cooldown: when the last attempt was Insufficient / JustRight /
	// Failed, the autoscaler and router treat the Pool as saturated
	// until SaturationCooldownSeconds has elapsed past this timestamp.
	// +optional
	LastScaleUpAttemptTime *metav1.Time `json:"lastScaleUpAttemptTime,omitempty"`

	// LastScaleUpAttemptResult records the outcome of the most recent
	// scale-up admission probe. Empty before the first attempt; one of
	// the PoolScaleUpAttemptResult enum values otherwise.
	// +optional
	LastScaleUpAttemptResult PoolScaleUpAttemptResult `json:"lastScaleUpAttemptResult,omitempty"`

	// ScaleUpErrorMessage is a short single-line description of the most
	// recent non-Enough scale-up result, suitable for surfacing to the
	// dashboard. Empty when LastScaleUpAttemptResult is Enough.
	// +optional
	ScaleUpErrorMessage string `json:"scaleUpErrorMessage,omitempty"`

	// ObservedGeneration is the metadata.generation observed when the
	// autoscaler last wrote this block. Clients may use it to confirm the
	// status is current with respect to the spec they care about.
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`
}

PoolAutoScalingStatus carries the autoscaler's per-Pool decision state. Every field is set/read exclusively by the SandboxPool reconciler running the autoscaling decision pipeline; the SandboxEnv reconciler must never write these fields.

func (*PoolAutoScalingStatus) DeepCopy added in v0.0.5

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolAutoScalingStatus.

func (*PoolAutoScalingStatus) DeepCopyInto added in v0.0.5

func (in *PoolAutoScalingStatus) DeepCopyInto(out *PoolAutoScalingStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type PoolScaleDownPolicy

type PoolScaleDownPolicy struct {
	// IdleTimeoutSeconds is the minimum duration (in seconds) a Pod must remain
	// in Idle state before it becomes a candidate for scale-down.
	// Defaults to 300 (5 minutes).
	// +optional
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=300
	IdleTimeoutSeconds int32 `json:"idleTimeoutSeconds,omitempty"`

	// StabilizationSeconds is the minimum number of seconds between two consecutive
	// scale-down events. Prevents thrashing when load fluctuates around the threshold.
	// Defaults to 60.
	// +optional
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=60
	StabilizationSeconds int32 `json:"stabilizationSeconds,omitempty"`

	// ProtectionWindowSeconds is the time window after a Pod is marked for
	// scale-down (via the scale-down-protected annotation) during which a new
	// Create Sandbox request can still claim it, cancelling the scale-down intent.
	// Defaults to 10.
	// +optional
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=10
	ProtectionWindowSeconds int32 `json:"protectionWindowSeconds,omitempty"`
}

PoolScaleDownPolicy controls scale-down behavior.

func (*PoolScaleDownPolicy) DeepCopy

func (in *PoolScaleDownPolicy) DeepCopy() *PoolScaleDownPolicy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolScaleDownPolicy.

func (*PoolScaleDownPolicy) DeepCopyInto

func (in *PoolScaleDownPolicy) DeepCopyInto(out *PoolScaleDownPolicy)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type PoolScaleUpAttemptResult added in v0.0.5

type PoolScaleUpAttemptResult string

PoolScaleUpAttemptResult is the outcome of the most recent scale-up attempt against a Pool, recorded on PoolAutoScalingStatus. Combined with LastScaleUpAttemptTime and the group's SaturationCooldownSeconds it lets both the autoscaler and the router decide whether the Pool is currently saturated without storing a derived end timestamp. +kubebuilder:validation:Enum=Enough;JustRight;Insufficient;Failed

const (
	// PoolScaleUpAttemptEnough — the admission probe accepted the full
	// requested target; no headroom signal from the plugin chain. The
	// next scale-up attempt is only gated by the success cooldown
	// (CooldownSeconds), not by SaturationCooldownSeconds.
	PoolScaleUpAttemptEnough PoolScaleUpAttemptResult = "Enough"

	// PoolScaleUpAttemptJustRight — the probe accepted strictly less
	// than the requested target but more than the current count
	// (partial admission). The autoscaler patched the partial value
	// and treats the Pool as saturated until SaturationCooldownSeconds
	// elapses, because the cluster is known to be at a ceiling.
	//
	// Reserved for finer-grained reporting; the current autoscaler
	// emits Insufficient for partial admissions and reserves
	// JustRight for a future refinement that distinguishes "we got
	// some" from "we got none".
	PoolScaleUpAttemptJustRight PoolScaleUpAttemptResult = "JustRight"

	// PoolScaleUpAttemptInsufficient — the probe rejected the target
	// with InsufficientResources (cluster cannot fit more pods). The
	// Pool is saturated; the autoscaler skips probing until
	// SaturationCooldownSeconds elapses.
	PoolScaleUpAttemptInsufficient PoolScaleUpAttemptResult = "Insufficient"

	// PoolScaleUpAttemptFailed — the probe returned InvalidSpec or
	// an Internal error. Like Insufficient it triggers saturation
	// cooldown, and the surfaced ScaleUpErrorMessage helps diagnose
	// the misconfiguration.
	PoolScaleUpAttemptFailed PoolScaleUpAttemptResult = "Failed"
)

type PoolScaleUpMode

type PoolScaleUpMode string

PoolScaleUpMode defines how aggressively a pool scales up. +kubebuilder:validation:Enum=Conservative;Default;Aggressive

const (
	// PoolScaleUpModeConservative adds one Pod per scale-up decision.
	PoolScaleUpModeConservative PoolScaleUpMode = "Conservative"
	// PoolScaleUpModeDefault adds max(1, ceil(currentReplicas/2)) Pods per decision.
	PoolScaleUpModeDefault PoolScaleUpMode = "Default"
	// PoolScaleUpModeAggressive doubles the replica count up to maxReplicas per decision.
	PoolScaleUpModeAggressive PoolScaleUpMode = "Aggressive"
)

type PoolScaleUpPolicy

type PoolScaleUpPolicy struct {
	// Mode controls how aggressively the pool grows on each scale-up decision.
	//   - Conservative: +1 per decision
	//   - Default:      +max(1, ceil(currentReplicas/2))
	//   - Aggressive:   scale to min(currentReplicas*2, maxReplicas)
	// Defaults to Default.
	// +optional
	// +kubebuilder:validation:Enum=Conservative;Default;Aggressive
	// +kubebuilder:default=Default
	Mode PoolScaleUpMode `json:"mode,omitempty"`

	// CooldownSeconds is the minimum number of seconds between two consecutive
	// scale-up events. Prevents scale-up storms when many requests arrive simultaneously.
	// Defaults to 30.
	// +optional
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=30
	CooldownSeconds int32 `json:"cooldownSeconds,omitempty"`

	// IdleThresholdSeconds triggers a proactive scale-up when idleReplicas == 0
	// has persisted for this many seconds. Set to 0 to disable proactive scale-up.
	// Defaults to 30.
	// +optional
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=30
	IdleThresholdSeconds int32 `json:"idleThresholdSeconds,omitempty"`

	// IdleZeroQuietWindowSeconds suppresses the proactive idleZero
	// scale-up trigger when no Sandbox.Create request has been observed
	// for this Pool within the most recent window. Concretely: if
	// `now - LastSandboxCreateTime > idleZeroQuietWindowSeconds` AND
	// `IdleThresholdSeconds` has elapsed since `idleReplicas` last hit
	// zero, the autoscaler will NOT fire a proactive scale-up. Reactive
	// scale-ups (queue length > 0 with no idle Pod) ignore this window
	// — a real waiter always wins. Set to 0 to disable the quiet-window
	// gate so proactive scale-up fires the moment IdleThresholdSeconds
	// elapses.
	// Defaults to 300 (5 minutes).
	// +optional
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=300
	IdleZeroQuietWindowSeconds int32 `json:"idleZeroQuietWindowSeconds,omitempty"`

	// SaturationCooldownSeconds is the duration the Env autoscaler keeps
	// a member marked saturated after a probe returned InsufficientResources
	// (or InvalidSpec). Subsequent reconciles skip the member's expensive
	// PreUpdatePool probe until the cooldown elapses; the router also
	// deprioritises saturated members. Defaults to 60.
	// +optional
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=60
	SaturationCooldownSeconds int32 `json:"saturationCooldownSeconds,omitempty"`
}

PoolScaleUpPolicy controls scale-up behavior.

func (*PoolScaleUpPolicy) DeepCopy

func (in *PoolScaleUpPolicy) DeepCopy() *PoolScaleUpPolicy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolScaleUpPolicy.

func (*PoolScaleUpPolicy) DeepCopyInto

func (in *PoolScaleUpPolicy) DeepCopyInto(out *PoolScaleUpPolicy)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ResolvedHands added in v0.0.8

type ResolvedHands struct {
	// +optional
	ClusterID string `json:"clusterID,omitempty"`
	// +optional
	EnvName string `json:"envName,omitempty"`
	// +optional
	Pools []string `json:"pools,omitempty"`
	// +optional
	Ready bool `json:"ready,omitempty"`
}

ResolvedHands is the sandbox supply the Brain will actually use.

func (*ResolvedHands) DeepCopy added in v0.0.8

func (in *ResolvedHands) DeepCopy() *ResolvedHands

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResolvedHands.

func (*ResolvedHands) DeepCopyInto added in v0.0.8

func (in *ResolvedHands) DeepCopyInto(out *ResolvedHands)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxEnv added in v0.0.5

type SandboxEnv struct {
	metav1.TypeMeta `json:",inline"`

	// metadata is a standard object metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitzero"`

	// spec defines the desired state of SandboxEnv
	// +required
	Spec SandboxEnvSpec `json:"spec"`

	// status defines the observed state of SandboxEnv
	// +optional
	Status SandboxEnvStatus `json:"status,omitzero"`
}

SandboxEnv is the Schema for the sandboxenvs API.

func (*SandboxEnv) DeepCopy added in v0.0.5

func (in *SandboxEnv) DeepCopy() *SandboxEnv

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxEnv.

func (*SandboxEnv) DeepCopyInto added in v0.0.5

func (in *SandboxEnv) DeepCopyInto(out *SandboxEnv)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*SandboxEnv) DeepCopyObject added in v0.0.5

func (in *SandboxEnv) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type SandboxEnvDefaults added in v0.0.5

type SandboxEnvDefaults struct {
	// InstanceType references an entry in the cluster-wide InstanceType catalog.
	// May be empty when the Env was migrated from a legacy SandboxPool that did
	// not carry an InstanceType label — in that case members use InlineResources.
	// +optional
	InstanceType string `json:"instanceType,omitempty"`

	// Multiplier scales the InstanceType's base resources. Must fall within the
	// InstanceType's declared [min, max] range; validated by the Env Controller.
	// +optional
	// +kubebuilder:validation:Minimum=1
	Multiplier int32 `json:"multiplier,omitempty"`
}

SandboxEnvDefaults captures the default instance shape for Sandbox.create requests that don't specify one.

func (*SandboxEnvDefaults) DeepCopy added in v0.0.5

func (in *SandboxEnvDefaults) DeepCopy() *SandboxEnvDefaults

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxEnvDefaults.

func (*SandboxEnvDefaults) DeepCopyInto added in v0.0.5

func (in *SandboxEnvDefaults) DeepCopyInto(out *SandboxEnvDefaults)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxEnvList added in v0.0.5

type SandboxEnvList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitzero"`
	Items           []SandboxEnv `json:"items"`
}

SandboxEnvList contains a list of SandboxEnv.

func (*SandboxEnvList) DeepCopy added in v0.0.5

func (in *SandboxEnvList) DeepCopy() *SandboxEnvList

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxEnvList.

func (*SandboxEnvList) DeepCopyInto added in v0.0.5

func (in *SandboxEnvList) DeepCopyInto(out *SandboxEnvList)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*SandboxEnvList) DeepCopyObject added in v0.0.5

func (in *SandboxEnvList) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type SandboxEnvMode added in v0.0.5

type SandboxEnvMode string

SandboxEnvMode controls how the Env satisfies sandbox-create requests. +kubebuilder:validation:Enum=WarmPool;OnDemandJob

const (
	// SandboxEnvModeWarmPool dispatches requests to one of the Env's member SandboxPools.
	// This is the only supported mode in Phase 1.
	SandboxEnvModeWarmPool SandboxEnvMode = "WarmPool"
	// SandboxEnvModeOnDemandJob creates a single-shot SandboxJob per request.
	// Reserved for Phase 3; not implemented yet.
	SandboxEnvModeOnDemandJob SandboxEnvMode = "OnDemandJob"
)

type SandboxEnvSpec added in v0.0.5

type SandboxEnvSpec struct {
	// TemplateRef binds this Env to exactly one SandboxTemplate (runtime). All
	// member Pools must reference the same Template.
	// +required
	TemplateRef SandboxEnvTemplateRef `json:"templateRef"`

	// Mode selects between WarmPool (predefined member Pools) and OnDemandJob
	// (per-request SandboxJob).
	// +required
	// +kubebuilder:default=WarmPool
	Mode SandboxEnvMode `json:"mode"`

	// Defaults supplies the InstanceType and multiplier used when a Sandbox.create
	// request does not specify them explicitly. Strongly recommended.
	// +optional
	Defaults *SandboxEnvDefaults `json:"defaults,omitempty"`

	// Clusters is the per-cluster member list. Each segment is owned exclusively
	// by the Worker whose ClusterID matches; foreign segments are read-only to
	// other Workers. Hub merges contributions from all Workers in Phase 2.
	// +optional
	// +listType=map
	// +listMapKey=clusterID
	Clusters []EnvClusterSpec `json:"clusters,omitempty"`

	// Autoscaling configures the Env-level autoscaler. When nil or
	// Autoscaling.Enabled=false, member Pool replicas are managed manually.
	// +optional
	Autoscaling *EnvAutoscalingSpec `json:"autoscaling,omitempty"`

	// Overrides carries the Env-wide overrides that uniformly replace
	// fields of the referenced SandboxTemplate for every member Pool.
	// Per-Pool variations (resource multiplier, replicas, plugin metadata
	// like quota URLs) live on each EnvClusterMember instead.
	// +optional
	Overrides *EnvOverridesSpec `json:"overrides,omitempty"`
}

SandboxEnvSpec defines the desired state of SandboxEnv.

func (*SandboxEnvSpec) DeepCopy added in v0.0.5

func (in *SandboxEnvSpec) DeepCopy() *SandboxEnvSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxEnvSpec.

func (*SandboxEnvSpec) DeepCopyInto added in v0.0.5

func (in *SandboxEnvSpec) DeepCopyInto(out *SandboxEnvSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxEnvStatus added in v0.0.5

type SandboxEnvStatus struct {
	// Conditions surfaces high-level Env health signals (Ready,
	// TemplateConsistent, AutoscalingActive, …).
	// +listType=map
	// +listMapKey=type
	// +optional
	Conditions []metav1.Condition `json:"conditions,omitempty"`

	// Clusters carries the per-cluster observed state. Worker writes only the
	// segment with IsLocal=true; other segments are populated by Hub Sync.
	// +optional
	// +listType=map
	// +listMapKey=clusterID
	Clusters []EnvClusterStatus `json:"clusters,omitempty"`

	// ScalingGroups aggregates idle/running counts per scalingGroup across all
	// members (across clusters when remote segments are populated by Sync).
	// +optional
	// +listType=map
	// +listMapKey=name
	ScalingGroups []EnvScalingGroupStatus `json:"scalingGroups,omitempty"`

	// MemberCount is the total number of member Pools, summed across every
	// cluster segment. It exists because printer columns cannot evaluate the
	// nested clusters[].members[] array. Today only the local segment is
	// observed, so it equals the local member count; once foreign segments are
	// populated it reflects the cross-cluster total.
	// +optional
	MemberCount int32 `json:"memberCount,omitempty"`

	// DesiredReplicas, RunningReplicas, IdleReplicas are env-wide rollups of
	// the per-member counts, summed across every observed member. They back
	// the printer columns (which cannot sum nested arrays) and give a single
	// at-a-glance view of capacity vs. utilisation.
	// +optional
	DesiredReplicas int32 `json:"desiredReplicas,omitempty"`
	// +optional
	RunningReplicas int32 `json:"runningReplicas,omitempty"`
	// +optional
	IdleReplicas int32 `json:"idleReplicas,omitempty"`
}

SandboxEnvStatus is the observed state of SandboxEnv.

func (*SandboxEnvStatus) DeepCopy added in v0.0.5

func (in *SandboxEnvStatus) DeepCopy() *SandboxEnvStatus

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxEnvStatus.

func (*SandboxEnvStatus) DeepCopyInto added in v0.0.5

func (in *SandboxEnvStatus) DeepCopyInto(out *SandboxEnvStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxEnvTemplateRef added in v0.0.5

type SandboxEnvTemplateRef struct {
	// Name of the SandboxTemplate (cluster-scoped).
	// +required
	Name string `json:"name"`

	// Version records the SandboxTemplate spec.version this Env was created
	// against.
	//
	// Legacy: it does not pin anything. A SandboxTemplate is a single mutable
	// cluster-scoped object — there is no version history and no way to
	// resolve an older spec.version — so every consumer resolves the Template
	// by Name alone and members always converge onto its current body. The
	// version actually in effect is reported per member in
	// status.clusters[].observedMembers[].templateVersion; read that instead
	// of this field. Retained so existing objects and manifests keep
	// round-tripping; real version pinning needs immutable per-version
	// Template objects first.
	// +optional
	Version string `json:"version,omitempty"`
}

SandboxEnvTemplateRef points at a cluster-scoped SandboxTemplate.

func (*SandboxEnvTemplateRef) DeepCopy added in v0.0.5

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxEnvTemplateRef.

func (*SandboxEnvTemplateRef) DeepCopyInto added in v0.0.5

func (in *SandboxEnvTemplateRef) DeepCopyInto(out *SandboxEnvTemplateRef)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxNetworkPolicy added in v0.0.7

type SandboxNetworkPolicy struct {
	// DisableEgress blocks all outbound traffic (DNS still resolves so lookups
	// do not hang). Takes precedence over Egress. A quick "no internet" switch.
	// +optional
	DisableEgress bool `json:"disableEgress,omitempty"`

	// Egress is the allowlist. When DisableEgress is false and Egress is nil,
	// egress is unrestricted — including private ranges, see
	// AllowPrivateNetworks.
	// +optional
	Egress *EgressRules `json:"egress,omitempty"`

	// AllowPrivateNetworks disables the default deny of private / link-local /
	// cloud-metadata ranges (RFC1918, 169.254.0.0/16, etc.) for a policy that
	// declares filtering. Default false — the anti-SSRF baseline stays on.
	// Enable only for trusted intra-cluster access.
	//
	// Implied when Egress is nil and DisableEgress is false: a policy that
	// filters nothing (SecretInjection-only, say) must not be stricter than
	// having no policy at all, where no sidecar exists and private ranges are
	// reachable. To allow every host but keep the baseline, declare
	// Egress with AllowedDomains ["*"] and AllowedCIDRs ["0.0.0.0/0"] instead.
	// +optional
	AllowPrivateNetworks bool `json:"allowPrivateNetworks,omitempty"`

	// SecretInjection brokers credentials on the way out: the sidecar terminates
	// TLS for the listed hosts and adds (or substitutes) the configured headers,
	// so the sandbox can use a credential without ever being able to read it.
	// nil disables it.
	//
	// Setting this alone (with Egress nil) is valid and means "inject, but do
	// not filter": the sidecar is still injected — which is what makes the
	// interception possible — while egress stays unrestricted, private ranges
	// included, so enabling injection never narrows what the sandbox can reach.
	//
	// Declarable only on a SandboxEnv. Sandbox-create requests carrying it are
	// rejected, because a credential travelling through a create request would
	// re-introduce exactly the exposure this feature removes.
	// +optional
	SecretInjection *SecretInjection `json:"secretInjection,omitempty"`
}

SandboxNetworkPolicy configures sandbox egress control. It is enforced by an in-Pod transparent proxy sidecar (not a Kubernetes NetworkPolicy), so it can match domains — which the cluster CNIs in use (Calico, Aliyun ENI) cannot.

A non-nil SandboxNetworkPolicy opts a SandboxEnv (and its member Pools) into egress filtering: the operator injects the filter sidecar into every sandbox Pod. The effective per-sandbox ruleset is pushed at claim time and reset on release/restart. Semantics are allowlist / default-deny.

func (*SandboxNetworkPolicy) DeepCopy added in v0.0.7

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxNetworkPolicy.

func (*SandboxNetworkPolicy) DeepCopyInto added in v0.0.7

func (in *SandboxNetworkPolicy) DeepCopyInto(out *SandboxNetworkPolicy)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxPool

type SandboxPool struct {
	metav1.TypeMeta `json:",inline"`

	// metadata is a standard object metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitzero"`

	// spec defines the desired state of SandboxPool
	// +required
	Spec SandboxPoolSpec `json:"spec"`

	// status defines the observed state of SandboxPool
	// +optional
	Status SandboxPoolStatus `json:"status,omitzero"`
}

SandboxPool is the Schema for the sandboxpools API

func (*SandboxPool) DeepCopy

func (in *SandboxPool) DeepCopy() *SandboxPool

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxPool.

func (*SandboxPool) DeepCopyInto

func (in *SandboxPool) DeepCopyInto(out *SandboxPool)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*SandboxPool) DeepCopyObject

func (in *SandboxPool) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type SandboxPoolList

type SandboxPoolList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitzero"`
	Items           []SandboxPool `json:"items"`
}

SandboxPoolList contains a list of SandboxPool

func (*SandboxPoolList) DeepCopy

func (in *SandboxPoolList) DeepCopy() *SandboxPoolList

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxPoolList.

func (*SandboxPoolList) DeepCopyInto

func (in *SandboxPoolList) DeepCopyInto(out *SandboxPoolList)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*SandboxPoolList) DeepCopyObject

func (in *SandboxPoolList) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type SandboxPoolPhase

type SandboxPoolPhase string

SandboxPoolPhase is the high-level phase of a SandboxPool. +kubebuilder:validation:Enum=Pending;Ready;ScalingUp;ScalingDown;Degraded;Terminating

const (
	// SandboxPoolPhasePending indicates the pool has no pods yet (spec.replicas == 0 and no pods exist).
	SandboxPoolPhasePending SandboxPoolPhase = "Pending"
	// SandboxPoolPhaseReady indicates the pool has reached the desired replica count and all pods are healthy.
	SandboxPoolPhaseReady SandboxPoolPhase = "Ready"
	// SandboxPoolPhaseScalingUp indicates the pool is scaling up (current < desired replicas).
	SandboxPoolPhaseScalingUp SandboxPoolPhase = "ScalingUp"
	// SandboxPoolPhaseScalingDown indicates the pool is scaling down (current > desired replicas).
	// This can persist if running pods cannot be deleted immediately.
	SandboxPoolPhaseScalingDown SandboxPoolPhase = "ScalingDown"
	// SandboxPoolPhaseDegraded indicates the pool has reached the desired replica count but
	// some idle pods are unavailable (NotReady) or some pods are in failed state.
	SandboxPoolPhaseDegraded SandboxPoolPhase = "Degraded"
	// SandboxPoolPhaseTerminating indicates the pool is being deleted.
	SandboxPoolPhaseTerminating SandboxPoolPhase = "Terminating"
)

type SandboxPoolSpec

type SandboxPoolSpec struct {

	// Replicas is the total desired number of Pods (Idle + Running + Starting + Stopping).
	// Adjusted by the SandboxEnv autoscaler (when the Pool is owned by an Env) or
	// directly by the operator for unmanaged Pools.
	// +kubebuilder:validation:Minimum=0
	Replicas int32 `json:"replicas"`

	// TemplateName references a cluster-scoped SandboxTemplate to use as the base
	// configuration. When set, the template's EmbeddedSandboxTemplate is copied at
	// creation time. Inline fields in SandboxPoolSpec override template fields.
	// +optional
	TemplateName string `json:"templateName,omitempty"`

	// DefaultStartupTimeout is the default startup timeout applied to sandbox create
	// requests in this pool when the CreateSandbox request does not specify a startupTimeout.
	// It also serves as the upper bound for the Starting phase: the controller deletes any pod
	// that has been in Starting phase longer than this value.
	//
	// When nil, the controller does not enforce an upper bound on the Starting phase
	// (pods with a per-pod agentbox.navix.sh/startup-timeout annotation are still cleaned up),
	// and create requests without an explicit startupTimeout use the internal default (2 minutes).
	// +optional
	DefaultStartupTimeout *metav1.Duration `json:"defaultStartupTimeout,omitempty"`

	// DefaultIdleTimeout is the default idle timeout applied to sandboxes created
	// in this pool when the CreateSandbox request does not specify an idleTimeout.
	// If nil, sandboxes have no idle timeout by default (they run until explicitly released).
	// +optional
	DefaultIdleTimeout *metav1.Duration `json:"defaultIdleTimeout,omitempty"`

	// PodCreationImagePolicy controls which image newly created Pods start with,
	// regardless of whether replicas are increased manually or by autoscaling.
	//   - PoolDefaultImage: preserve template container image (current behavior)
	//   - IdleImage:        override the first container image with spec.idleImage
	// +optional
	// +kubebuilder:validation:Enum=PoolDefaultImage;IdleImage
	// +kubebuilder:default=IdleImage
	PodCreationImagePolicy PodCreationImagePolicy `json:"podCreationImagePolicy,omitempty"`

	// NetworkPolicy, when set, enables sandbox egress filtering for Pods in this
	// Pool: the operator injects a transparent filter sidecar. For Env-owned
	// Pools this is projected from the Env's overrides.networkPolicy and serves
	// as the default ruleset; per-sandbox create requests may override it.
	// +optional
	NetworkPolicy *SandboxNetworkPolicy `json:"networkPolicy,omitempty"`

	// MaxUnavailable bounds how many of this Pool's desired idle Pods may be
	// unavailable at once while it rolls stale idle Pods onto a new revision
	// (see status.updateRevision). Absolute number or percentage of replicas
	// (e.g. "20%"), rounded down and floored at 1. For Env-owned Pools this is
	// projected from the Env's (member/overrides) updateStrategy; nil disables
	// rollout throttling and is treated as "20%".
	// +optional
	// +kubebuilder:validation:XIntOrString
	MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`

	EmbeddedSandboxTemplate `json:",inline"`
}

SandboxPoolSpec defines the desired state of SandboxPool

func (*SandboxPoolSpec) DeepCopy

func (in *SandboxPoolSpec) DeepCopy() *SandboxPoolSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxPoolSpec.

func (*SandboxPoolSpec) DeepCopyInto

func (in *SandboxPoolSpec) DeepCopyInto(out *SandboxPoolSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxPoolStatus

type SandboxPoolStatus struct {

	// Phase is a high-level summary of the pool's current state.
	// Possible values: Pending, Ready, ScalingUp, ScalingDown, Degraded, Terminating.
	//
	// Phase is determined by the following priority rules:
	//   - Terminating: DeletionTimestamp is set
	//   - Pending:     spec.replicas == 0 and no pods exist
	//   - ScalingUp:   current pod count < spec.replicas
	//   - ScalingDown: current pod count > spec.replicas (may persist while running pods cannot be deleted)
	//   - Degraded:    replica count is stable but unavailableIdleReplicas > 0 or failedReplicas > 0
	//   - Ready:       all replicas present and all pods are healthy
	// +optional
	Phase SandboxPoolPhase `json:"phase,omitempty"`

	// IdleReplicas is the number of Pods in idle state
	// +optional
	IdleReplicas int32 `json:"idleReplicas,omitempty"`

	// UnavailableIdleReplicas is the number of Pods in idle phase whose Kubernetes PodReady
	// condition is not True (e.g. Pending, CrashLoopBackOff, ErrImagePull).
	// These Pods are counted in IdleReplicas but cannot accept sandbox requests.
	// A non-zero value causes the pool to enter the Degraded phase.
	// +optional
	UnavailableIdleReplicas int32 `json:"unavailableIdleReplicas,omitempty"`

	// RunningReplicas is the number of Pods in running state
	// +optional
	RunningReplicas int32 `json:"runningReplicas,omitempty"`

	// StartingReplicas is the number of Pods being activated (Idle → Running)
	// +optional
	StartingReplicas int32 `json:"startingReplicas,omitempty"`

	// StoppingReplicas is the number of Pods being recycled (Running → Idle)
	// +optional
	StoppingReplicas int32 `json:"stoppingReplicas,omitempty"`

	// FailedReplicas is the number of Pods in failed state
	// +optional
	FailedReplicas int32 `json:"failedReplicas,omitempty"`

	// UpdateRevision is the target revision hash of the current Pool template
	// (spec.template.metadata.labels[agentbox.navix.sh/template-hash]). Idle
	// Pods whose own hash differs are stale and get rolled onto this revision.
	// +optional
	UpdateRevision string `json:"updateRevision,omitempty"`

	// CurrentRevision is the revision hash all Pods currently share. It equals
	// UpdateRevision once a rollout has converged, and is empty while Pods
	// straddle multiple revisions (rollout in progress).
	// +optional
	CurrentRevision string `json:"currentRevision,omitempty"`

	// UpdatedReplicas is the number of Pods already at UpdateRevision.
	// +optional
	UpdatedReplicas int32 `json:"updatedReplicas,omitempty"`

	// PendingRequests is the throttled mirror of the in-process PoolScheduler
	// claim queue depth. Patched every ~3 s when the queue length changes by
	// at least 20 % or crosses the 0/>0 boundary. Used by Dashboard for
	// real-time backlog observability; the Env autoscaler reads the live
	// in-process Snapshot instead and does not depend on this field.
	// +optional
	PendingRequests int32 `json:"pendingRequests,omitempty"`

	// Selector is the label selector string used to identify Pods managed by this Pool.
	// Deprecated: Use LabelSelector for structured access or PhaseSelectors for per-phase filtering.
	// This field is retained for kubectl scale / HPA compatibility (subresource:scale selectorpath).
	// +optional
	Selector string `json:"selector,omitempty"`

	// LabelSelector is the structured label selector matching all Pods managed by this Pool.
	// Equivalent to the Selector field but in structured metav1.LabelSelector form.
	// +optional
	LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"`

	// PhaseSelectors contains pre-computed label selector strings for filtering Pods by phase,
	// suitable for direct use with `kubectl get pods -l <selector>`.
	// Keys: "all", "idle", "running", "starting", "stopping", "failed".
	// Example: kubectl get pods -l <phaseSelectors.running>
	// +optional
	PhaseSelectors map[string]string `json:"phaseSelectors,omitempty"`

	// conditions represent the current state of the SandboxPool resource.
	// Each condition has a unique type and reflects the status of a specific aspect of the resource.
	//
	// Standard condition types:
	// - "Available":  True when healthy idle pods are available to accept new sandbox requests.
	// - "Scaling":    True when the pool is actively scaling up or down.
	// - "Degraded":   True when unavailable idle pods or failed pods are present.
	//
	// The status of each condition is one of True, False, or Unknown.
	// +listType=map
	// +listMapKey=type
	// +optional
	Conditions []metav1.Condition `json:"conditions,omitempty"`

	// AutoScaling persists the Pool autoscaler's decision-time bookkeeping
	// (last scale-up/down timestamps, idle-zero window start, saturation
	// cooldown, last probe outcome). The Pool reconciler is the only writer.
	// Nil when autoscaling is disabled on this Pool's owning Env group.
	// +optional
	AutoScaling *PoolAutoScalingStatus `json:"autoscaling,omitempty"`
}

SandboxPoolStatus defines the observed state of SandboxPool.

func (*SandboxPoolStatus) DeepCopy

func (in *SandboxPoolStatus) DeepCopy() *SandboxPoolStatus

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxPoolStatus.

func (*SandboxPoolStatus) DeepCopyInto

func (in *SandboxPoolStatus) DeepCopyInto(out *SandboxPoolStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxReservationSpec

type SandboxReservationSpec struct {
	PriorityClassName string              `json:"priorityClassName,omitempty"`
	ReplicaQuota      corev1.ResourceList `json:"replicaQuota"`
}

SandboxReservationSpec holds SI Scheduler integration settings for each sandbox pod.

func (*SandboxReservationSpec) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxReservationSpec.

func (*SandboxReservationSpec) DeepCopyInto

func (in *SandboxReservationSpec) DeepCopyInto(out *SandboxReservationSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxRuntimeSpec

type SandboxRuntimeSpec struct {
	// Name specifies the name of the runtime to use for the sandbox pods.
	// Supported values are "e2b", "swerex", "aiosanbdox", etc.
	Name string `json:"name"`

	// Port specifies the port number that the runtime should listen on for incoming connections.
	// +optional
	Port *int32 `json:"port,omitempty"`

	// Protocol for port. Must be UDP, TCP, or SCTP.
	// Defaults to "TCP".
	// +optional
	// +default="TCP"
	Protocol *corev1.Protocol `json:"protocol,omitempty"`

	// Description is a human-readable description of this runtime.
	// +optional
	Description string `json:"description,omitempty"`

	// LogDir is the path to the runtime's log file inside the container.
	// When set, the GetLogs API can retrieve runtime logs via file read.
	// Example: "/tmp/envd.log"
	// +optional
	LogDir string `json:"logDir,omitempty"`

	// ReadinessProbe defines the readiness check configuration for the runtime.
	// +optional
	ReadinessProbe *corev1.Probe `json:"readinessProbe,omitempty"`

	// Config contains runtime-specific configuration parameters.
	// The content and structure of this field depend on the runtime type.
	// +kubebuilder:pruning:PreserveUnknownFields
	// +kubebuilder:validation:Schemaless
	// +optional
	Config *runtime.RawExtension `json:"config,omitempty"`
}

func (*SandboxRuntimeSpec) DeepCopy

func (in *SandboxRuntimeSpec) DeepCopy() *SandboxRuntimeSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxRuntimeSpec.

func (*SandboxRuntimeSpec) DeepCopyInto

func (in *SandboxRuntimeSpec) DeepCopyInto(out *SandboxRuntimeSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxStatusDetail

type SandboxStatusDetail struct {
	// Reason is a machine-readable cause, e.g. "Pulling", "ImagePullBackOff",
	// "ErrImagePull", "CrashLoopBackOff", "OOMKilled", "PodFailed".
	Reason string `json:"reason"`
	// Message is a human-readable description of the current state.
	Message string `json:"message"`
	// LastUpdatedTime is the RFC3339 timestamp when this record was last written.
	LastUpdatedTime string `json:"lastUpdatedTime"`
}

SandboxStatusDetail holds structured diagnostic information written by the reconciler onto the Pod annotation "agentbox.navix.sh/sandbox-status-detail".

func (*SandboxStatusDetail) DeepCopy

func (in *SandboxStatusDetail) DeepCopy() *SandboxStatusDetail

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxStatusDetail.

func (*SandboxStatusDetail) DeepCopyInto

func (in *SandboxStatusDetail) DeepCopyInto(out *SandboxStatusDetail)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxStopReason

type SandboxStopReason string
const (
	SandboxStopReasonCompleted SandboxStopReason = "Completed" // Normal completion of the sandbox workload.
	SandboxStopReasonCanceled  SandboxStopReason = "Canceled"  // Premature stop before ever reaching Running (e.g. deleted while Starting).
	SandboxStopReasonReleased  SandboxStopReason = "Released"  // Explicit release by API call or idle timeout.
	SandboxStopReasonFailed    SandboxStopReason = "Failed"    // Stopped due to pod failure (OOMKilled, Evicted, etc.).
)

type SandboxTemplate

type SandboxTemplate struct {
	metav1.TypeMeta `json:",inline"`

	// metadata is a standard object metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitzero"`

	// spec defines the desired state of SandboxTemplate
	// +required
	Spec SandboxTemplateSpec `json:"spec"`

	// status defines the observed state of SandboxTemplate
	// +optional
	Status SandboxTemplateStatus `json:"status,omitzero"`
}

SandboxTemplate is the Schema for the sandboxtemplates API

func (*SandboxTemplate) DeepCopy

func (in *SandboxTemplate) DeepCopy() *SandboxTemplate

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxTemplate.

func (*SandboxTemplate) DeepCopyInto

func (in *SandboxTemplate) DeepCopyInto(out *SandboxTemplate)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*SandboxTemplate) DeepCopyObject

func (in *SandboxTemplate) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type SandboxTemplateList

type SandboxTemplateList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitzero"`
	Items           []SandboxTemplate `json:"items"`
}

SandboxTemplateList contains a list of SandboxTemplate

func (*SandboxTemplateList) DeepCopy

func (in *SandboxTemplateList) DeepCopy() *SandboxTemplateList

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxTemplateList.

func (*SandboxTemplateList) DeepCopyInto

func (in *SandboxTemplateList) DeepCopyInto(out *SandboxTemplateList)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*SandboxTemplateList) DeepCopyObject

func (in *SandboxTemplateList) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type SandboxTemplateSpec

type SandboxTemplateSpec struct {
	EmbeddedSandboxTemplate `json:",inline"`

	// Version is an optional semantic version string for this template (e.g. "v1.2.0").
	// +optional
	Version string `json:"version,omitempty"`

	// Description is a human-readable description of this template.
	// +optional
	Description string `json:"description,omitempty"`

	// Visibility controls which tenants can see this template.
	// When nil or Rules is empty, the template is public (visible to all).
	// +optional
	Visibility *TemplateVisibility `json:"visibility,omitempty"`
}

SandboxTemplateSpec defines the desired state of SandboxTemplate

func (*SandboxTemplateSpec) DeepCopy

func (in *SandboxTemplateSpec) DeepCopy() *SandboxTemplateSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxTemplateSpec.

func (*SandboxTemplateSpec) DeepCopyInto

func (in *SandboxTemplateSpec) DeepCopyInto(out *SandboxTemplateSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SandboxTemplateStatus

type SandboxTemplateStatus struct {

	// conditions represent the current state of the SandboxTemplate resource.
	// Each condition has a unique type and reflects the status of a specific aspect of the resource.
	//
	// Standard condition types include:
	// - "Available": the resource is fully functional
	// - "Progressing": the resource is being created or updated
	// - "Degraded": the resource failed to reach or maintain its desired state
	//
	// The status of each condition is one of True, False, or Unknown.
	// +listType=map
	// +listMapKey=type
	// +optional
	Conditions []metav1.Condition `json:"conditions,omitempty"`
}

SandboxTemplateStatus defines the observed state of SandboxTemplate.

func (*SandboxTemplateStatus) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SandboxTemplateStatus.

func (*SandboxTemplateStatus) DeepCopyInto

func (in *SandboxTemplateStatus) DeepCopyInto(out *SandboxTemplateStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SecretInjection added in v0.0.8

type SecretInjection struct {
	// Credentials are the named secrets rules may reference.
	// +optional
	Credentials []InjectedCredential `json:"credentials,omitempty"`

	// Rules declare what to inject, per host.
	// +optional
	Rules []InjectionRule `json:"rules,omitempty"`

	// CACertTTL bounds the lifetime of the per-sandbox CA minted for TLS
	// interception. Defaults to 24h.
	// +optional
	CACertTTL *metav1.Duration `json:"caCertTTL,omitempty"`
}

SecretInjection declares the outbound credential broker. It never carries a credential value: values live in Secrets and are resolved by the operator at push time, because this struct is serialised into a Pod annotation and into API responses.

func (*SecretInjection) DeepCopy added in v0.0.8

func (in *SecretInjection) DeepCopy() *SecretInjection

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretInjection.

func (*SecretInjection) DeepCopyInto added in v0.0.8

func (in *SecretInjection) DeepCopyInto(out *SecretInjection)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SecretKeyRef added in v0.0.8

type SecretKeyRef struct {
	Name string `json:"name"`
	Key  string `json:"key"`
}

SecretKeyRef selects one key of one Secret.

func (*SecretKeyRef) DeepCopy added in v0.0.8

func (in *SecretKeyRef) DeepCopy() *SecretKeyRef

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeyRef.

func (*SecretKeyRef) DeepCopyInto added in v0.0.8

func (in *SecretKeyRef) DeepCopyInto(out *SecretKeyRef)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SecretKeySelector added in v0.0.8

type SecretKeySelector struct {
	// +required
	Name string `json:"name"`
	// +required
	Key string `json:"key"`
}

SecretKeySelector points at one key of a Secret.

func (*SecretKeySelector) DeepCopy added in v0.0.8

func (in *SecretKeySelector) DeepCopy() *SecretKeySelector

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeySelector.

func (*SecretKeySelector) DeepCopyInto added in v0.0.8

func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SessionPersistence added in v0.0.8

type SessionPersistence struct {
	// Enabled false uses an emptyDir — history is lost on restart.
	// +kubebuilder:default=false
	// +optional
	Enabled *bool `json:"enabled,omitempty"`
	// ExistingClaim mounts a claim this controller does not manage.
	// +optional
	ExistingClaim string `json:"existingClaim,omitempty"`
	// +optional
	Size *resource.Quantity `json:"size,omitempty"`
	// +optional
	StorageClass string `json:"storageClass,omitempty"`
}

SessionPersistence backs the state directory.

The state directory is mounted at ONE path, at the volume root, and must not be split into per-owner subPath mounts: the runtime converts a volume it does not recognise by clearing its root, and a marker written under one subPath is invisible to the others, so every restart would look like a fresh volume.

func (*SessionPersistence) DeepCopy added in v0.0.8

func (in *SessionPersistence) DeepCopy() *SessionPersistence

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SessionPersistence.

func (*SessionPersistence) DeepCopyInto added in v0.0.8

func (in *SessionPersistence) DeepCopyInto(out *SessionPersistence)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type TemplateVisibility

type TemplateVisibility struct {
	// Rules is the list of visibility rules.
	// +optional
	Rules []TemplateVisibilityRule `json:"rules,omitempty"`
}

TemplateVisibility controls the visibility of a SandboxTemplate. Rules are evaluated with OR semantics: a caller is visible if it matches any rule. An empty Rules list means the template is public (visible to all).

func (*TemplateVisibility) DeepCopy

func (in *TemplateVisibility) DeepCopy() *TemplateVisibility

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateVisibility.

func (*TemplateVisibility) DeepCopyInto

func (in *TemplateVisibility) DeepCopyInto(out *TemplateVisibility)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type TemplateVisibilityRule

type TemplateVisibilityRule struct {
	// Team specifies the team that can see the template.
	// Empty means any team.
	// +optional
	Team string `json:"team,omitempty"`

	// Users specifies the users that can see the template.
	// Empty means any user.
	// +optional
	Users []string `json:"users,omitempty"`
}

TemplateVisibilityRule describes a single visibility rule. Team and Users are combined with AND semantics: both must match (empty = wildcard). Multiple Rules in a TemplateVisibility are combined with OR semantics.

func (*TemplateVisibilityRule) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateVisibilityRule.

func (*TemplateVisibilityRule) DeepCopyInto

func (in *TemplateVisibilityRule) DeepCopyInto(out *TemplateVisibilityRule)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ToolApproval added in v0.0.8

type ToolApproval struct {
	// Pattern matches a tool name; a trailing "*" matches a prefix.
	// +required
	Pattern string `json:"pattern"`
	// +kubebuilder:validation:Enum=allow;ask;deny
	// +required
	Action string `json:"action"`
	// Prompt is shown to whoever is asked to approve.
	// +optional
	Prompt string `json:"prompt,omitempty"`
}

ToolApproval is one rule of the approval policy.

func (*ToolApproval) DeepCopy added in v0.0.8

func (in *ToolApproval) DeepCopy() *ToolApproval

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ToolApproval.

func (*ToolApproval) DeepCopyInto added in v0.0.8

func (in *ToolApproval) DeepCopyInto(out *ToolApproval)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ToolPolicySpec added in v0.0.8

type ToolPolicySpec struct {
	// MCP servers reachable by the harness.
	// +optional
	// +listType=map
	// +listMapKey=name
	MCP []MCPServerSpec `json:"mcp,omitempty"`

	// ClientSide tools are executed by the CALLER, not by the sandbox: the
	// platform only forwards the call and waits for a result. This is how an
	// agent drives its caller's own surface — navigating a page, opening a
	// panel — which no hosted runtime could do on the caller's behalf.
	// +optional
	// +listType=map
	// +listMapKey=name
	ClientSide []ClientToolSpec `json:"clientSide,omitempty"`

	// Approval gates individual tools behind a human decision. Patterns are
	// matched in order and the first hit wins; anything unmatched is allowed.
	// +optional
	Approval []ToolApproval `json:"approval,omitempty"`
}

ToolPolicySpec registers the tools an agent's scenarios may draw from.

func (*ToolPolicySpec) DeepCopy added in v0.0.8

func (in *ToolPolicySpec) DeepCopy() *ToolPolicySpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ToolPolicySpec.

func (*ToolPolicySpec) DeepCopyInto added in v0.0.8

func (in *ToolPolicySpec) DeepCopyInto(out *ToolPolicySpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

Jump to

Keyboard shortcuts

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