Documentation
¶
Overview ¶
Package v1alpha1 contains API Schema definitions for the agents v1alpha1 API group. +kubebuilder:object:generate=true +groupName=agents.navix.sh
Index ¶
- Constants
- Variables
- func BoolAnnotation(obj metav1.Object, key string) bool
- func ComputeRevisionHash(spec *SandboxPoolSpec) string
- func EnvImagePullSecretName(envName string) string
- func HasEnvOwner(obj metav1.Object) bool
- func PodHasEgressProxy(pod *corev1.Pod) bool
- func ReadOnlyDefeatingFeatures(spec *corev1.PodSpec) []string
- func ResolveAutoUpdate(env *SandboxEnv, member EnvClusterMember) bool
- func ResolveMaxUnavailable(env *SandboxEnv, member EnvClusterMember) intstr.IntOrString
- func ValidateReadOnlyEnforceable(vols []EnvVolumeMount, spec *corev1.PodSpec, allowed bool) error
- func ValidateSecretInjection(np *SandboxNetworkPolicy, si *SecretInjection) error
- func ValidateVolumeMounts(vols []EnvVolumeMount, tmplSpec *corev1.PodSpec) error
- type BackendStatus
- type ClaudeCodeRuntime
- type ClientToolSpec
- type ConfigMapKeySelector
- type EgressRules
- type EmbeddedSandboxTemplate
- type EnvAutoscalingGroup
- type EnvAutoscalingSpec
- type EnvClusterMember
- type EnvClusterMemberConfig
- type EnvClusterSpec
- type EnvClusterStatus
- type EnvObservedMember
- type EnvOverridesSpec
- type EnvScalingGroupStatus
- type EnvUpdateStrategy
- type EnvVolumeMount
- type GatewaySpec
- type HandsAutoSpec
- type HandsBinding
- type HandsE2B
- type HandsEnvRef
- type HandsExternal
- type HandsInstanceType
- type HeaderInjection
- type HeaderInjectionMode
- type InjectedCredential
- type InjectionRule
- type LangfuseSpec
- type MCPServerSpec
- type ManagedAgent
- type ManagedAgentBrain
- type ManagedAgentClassifier
- type ManagedAgentHands
- type ManagedAgentImage
- type ManagedAgentIngress
- type ManagedAgentList
- type ManagedAgentModel
- type ManagedAgentObservability
- type ManagedAgentOwner
- type ManagedAgentPrompt
- type ManagedAgentRuntime
- type ManagedAgentScenario
- type ManagedAgentSession
- type ManagedAgentSpec
- type ManagedAgentStatus
- type MemberMetadata
- type ObservedMemberState
- type OpenCodeRuntime
- type PodCreationImagePolicy
- type PoolAutoScalingStatus
- type PoolScaleDownPolicy
- type PoolScaleUpAttemptResult
- type PoolScaleUpMode
- type PoolScaleUpPolicy
- type ResolvedHands
- type SandboxEnv
- type SandboxEnvDefaults
- type SandboxEnvList
- type SandboxEnvMode
- type SandboxEnvSpec
- type SandboxEnvStatus
- type SandboxEnvTemplateRef
- type SandboxNetworkPolicy
- type SandboxPool
- type SandboxPoolList
- type SandboxPoolPhase
- type SandboxPoolSpec
- type SandboxPoolStatus
- type SandboxReservationSpec
- type SandboxRuntimeSpec
- type SandboxStatusDetail
- type SandboxStopReason
- type SandboxTemplate
- type SandboxTemplateList
- type SandboxTemplateSpec
- type SandboxTemplateStatus
- type SecretInjection
- type SecretKeyRef
- type SecretKeySelector
- type SessionPersistence
- type TemplateVisibility
- type TemplateVisibilityRule
- type ToolApproval
- type ToolPolicySpec
Constants ¶
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.
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 + Gateway // + 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 egress policy // (pkg/egressproxy.Policy) resolved for a claimed sandbox from its create // request. The SandboxReady hook reads it and pushes it into the proxy // 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. // // It holds rule shapes, credential names and Secret references — 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" // SandboxArmedAnnotationKey marks a claimed sandbox as fully armed: its // runtimes answered their readiness probes, the post-start hooks ran (env // vars and, when injection is configured, the CA are in place), and the // egress policy and credentials were pushed into the filter sidecar. The // value is the sandbox ID, so a recycled Pod carrying a stale mark can never // be mistaken for an armed one. // // It is the single readiness judgement for a sandbox: the create path waits // for it before returning, and the data-plane router refuses to route to a // sandbox that does not carry it. Registered as a managed annotation key so // release strips it. SandboxArmedAnnotationKey = "agentbox.navix.sh/sandbox-armed" // SandboxArmErrorAnnotationKey records why arming failed, in place of // SandboxArmedAnnotationKey (the two are mutually exclusive). The create path // surfaces the reason to the caller instead of handing back a sandbox that // looks usable but has no env vars, no CA or no credentials. SandboxArmErrorAnnotationKey = "agentbox.navix.sh/sandbox-arm-error" // 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" // RegistryRewriteAnnotationKey opts a SandboxTemplate into having its own // images (idleImage, containers, initContainers) rewritten to the registry // of whichever cluster the Pool is rendered for. // // Written by: the Template author (a human). // Read by: poolrender.RenderSandboxPool. // Format: a boolean literal parsable by strconv.ParseBool ("true", "1"). // Absent: no rewriting of Template-owned images — the pre-existing // behaviour, where a Template authored against one region's registry keeps // that registry in every cluster it is broadcast to. // Unparseable: treated as false, logged at V(2), never an error. // // Opt-in rather than always-on because the rewrite is a bare host swap: // only the Template author knows whether the same repository path exists in // every region's mirror. RegistryRewriteAnnotationKey = "agentbox.navix.sh/registry-rewrite" // AllowUnenforceableReadOnlyVolumesAnnotationKey opts a SandboxTemplate out // of the check that refuses read-only Env volume mounts on a pod spec that // can defeat them (privileged, SYS_ADMIN, Bidirectional propagation, // hostPath, unmasked procMount). // // Written by: a cluster administrator. SandboxTemplate writes are // admin-scoped, which is the point: the person who chose `privileged: true` // is the person who may accept its consequence, not the user mounting the // dataset. // Read by: v1alpha1.ValidateReadOnlyEnforceable via its callers. // Format: a boolean literal parsable by strconv.ParseBool. // Absent: read-only mounts are refused on such pod specs. // Unparseable: treated as false (the safe direction). AllowUnenforceableReadOnlyVolumesAnnotationKey = "agentbox.navix.sh/allow-unenforceable-readonly-volumes" // 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-" )
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" )
Condition type constants for SandboxEnv.
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" // SandboxPoolConditionAdmitted indicates whether the backing scheduler / quota // system accepts the pool's desired replica count. It is orthogonal to Scaling: // Scaling says the pool wants to grow, Admitted says whether it is allowed to. // A pool can be Scaling=True and Admitted=False for a long time when the quota // backing it is exhausted. SandboxPoolConditionAdmitted = "Admitted" )
Condition type constants for SandboxPool.
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 // Admitted condition reasons SandboxPoolReasonAdmissionGranted = "AdmissionGranted" // the desired replica count was fully admitted SandboxPoolReasonQuotaExhausted = "ResourceQuotaExhausted" // quota/capacity limits how many replicas may be created SandboxPoolReasonAdmissionRejected = "AdmissionRejected" // the pool spec itself was rejected; retrying will not help SandboxPoolReasonAdmissionError = "AdmissionError" // admission could not be evaluated (backend unreachable, etc.) )
Condition reason constants for SandboxPool.
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.
const ReservedVolumeNamePrefix = "abx-vol-"
ReservedVolumeNamePrefix namespaces every volume the Pool renderer injects for an Env-declared PVC mount.
A Template that declares a volume with this prefix is rejected on write. That rejection is what makes the naming guarantee hold: an injected volume can never collide with a Template-declared one, or with one a plugin invents later, without anybody maintaining a list of reserved names.
const SandboxEnvOwnerKind = "SandboxEnv"
SandboxEnvOwnerKind is the OwnerReference.Kind value for SandboxEnv. Exposed so other packages can write owner refs without string literals.
Variables ¶
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 )
DefaultMaxUnavailable is the rollout unavailability budget applied when neither the member nor the Env overrides specify one.
Functions ¶
func BoolAnnotation ¶ added in v0.0.10
BoolAnnotation reads a boolean opt-in annotation off an object.
It is deliberately fail-open in the "false" direction: a missing object, a missing key, or a value strconv.ParseBool rejects all yield false, and none of them is an error. Opt-in annotations in this repo gate behaviour that is safe to skip, so a typo must degrade to the pre-existing behaviour rather than fail a request.
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
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 HasEnvOwner ¶ added in v0.0.5
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
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 ReadOnlyDefeatingFeatures ¶ added in v0.0.10
ReadOnlyDefeatingFeatures reports pod-spec features that let a container reach the host mount namespace and remount a read-only bind mount read-write.
Read-only on a PVC is enforced by the container runtime, not by the CSI driver: the driver mounts the backing filesystem read-write on the host and kubelet asks the runtime for a read-only bind. Anything that can act in the host mount namespace therefore bypasses it.
Returns a human-readable list, empty when the spec cannot defeat read-only.
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 ValidateReadOnlyEnforceable ¶ added in v0.0.10
func ValidateReadOnlyEnforceable(vols []EnvVolumeMount, spec *corev1.PodSpec, allowed bool) error
ValidateReadOnlyEnforceable refuses a read-only volume declaration that the pod spec cannot actually honour.
Scoped deliberately to read-only entries: an entry the user marked writable never claimed a guarantee, so a privileged Docker-in-Docker template mounting a scratch dataset read-write is unaffected. That narrowing is what keeps the rule from breaking legitimate privileged templates.
allowed comes from the Template's admin-only opt-out annotation. Template writes are admin-scoped on purpose: whoever chose `privileged: true` is the one who may accept its consequence, not the user mounting the dataset.
func ValidateSecretInjection ¶ added in v0.0.8
func ValidateSecretInjection(np *SandboxNetworkPolicy, si *SecretInjection) error
ValidateSecretInjection checks the credential-injection block resolved for a claim against the egress policy resolved for the same claim, for the mistakes that would otherwise fail silently or leak a credential.
Both arguments come from one create request, so the two can genuinely contradict each other: filtering that excludes a host the rules name leaves the rule configured and dead. Either may be nil.
func ValidateVolumeMounts ¶ added in v0.0.10
func ValidateVolumeMounts(vols []EnvVolumeMount, tmplSpec *corev1.PodSpec) error
ValidateVolumeMounts checks Env-declared PVC mounts for anything that would produce a broken or dangerous Pod.
tmplSpec is the rendered Template's pod spec and may be nil; when supplied, mounts are additionally checked against what the Template already declares, which is what keeps a user from shadowing /mnt/agentbox or a DinD template's /var/lib/docker without either path being named here.
It is called when a SandboxEnv is written, so the author sees the error, and again from the renderer, so a hand-edited CR cannot slip through.
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
func (in *ConfigMapKeySelector) DeepCopy() *ConfigMapKeySelector
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 ¶
func (in *EmbeddedSandboxTemplate) DeepCopy() *EmbeddedSandboxTemplate
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 and override changes DO auto-propagate into Spec by default: refreshAutoUpdateMembers re-renders the member on every reconcile, compares revision hashes, and rewrites Spec when they differ. The pod-spec body is replaced wholesale (so field deletions take effect) while the pod-template ObjectMeta is merged, and neither Metadata nor PreCreatePool is re-run — so plugin identity survives and no side-effect is replayed. Set updateStrategy.autoUpdate=false to hold a frozen snapshot instead (see ResolveAutoUpdate, which defaults to true).
- 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 migration escape hatch for legacy Pools without
// an InstanceType label, and the source of truth that keeps resource sizing
// stable across a Template upgrade: the auto-update re-render reads it from
// Config, which plugins never mutate. 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
func (in *EnvClusterMemberConfig) DeepCopy() *EnvClusterMemberConfig
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"`
// Gateway turns on the egress gateway for every member Pool of this Env: the
// operator injects a transparent proxy sidecar into each sandbox Pod, which
// is what makes per-sandbox egress filtering and credential injection
// possible. It carries no rules of its own — those arrive on the create
// call. Nil, or enabled=false, means no sidecar, and a create request that
// asks for filtering or injection is then refused rather than silently
// unenforced.
// +optional
Gateway *GatewaySpec `json:"gateway,omitempty"`
// UpdateStrategy is the Env-wide default rollout policy: when a member's
// effective idle-Pod identity changes (Template edit, image / gateway
// 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"`
// Volumes mounts already-existing PersistentVolumeClaims from this Env's
// namespace into the sandbox container. The claim must exist and be Bound;
// this is checked when the Env is written, not at render time (silently
// dropping a declared mount would make a data path vanish without a word).
// The operator never creates or deletes a PVC.
//
// Mounts are fixed at Pod creation — Kubernetes forbids mutating
// spec.volumes on a live Pod — so editing this list flips the revision hash
// and rolls idle Pods; sandboxes already claimed keep their old mounts until
// they are returned. In-place image upgrades never touch volumes.
//
// Read-only is enforced on the VOLUME SOURCE rather than the mount, which
// makes it un-overridable by a container asking for read-write. It is still
// only a container bind-mount flag, so a pod spec with host mount-namespace
// reach (privileged, SYS_ADMIN, Bidirectional propagation, hostPath) can
// remount it read-write; such combinations are rejected on write unless the
// Template carries the admin-only opt-out annotation. See
// ValidateReadOnlyEnforceable.
// +optional
// +kubebuilder:validation:MaxItems=8
Volumes []EnvVolumeMount `json:"volumes,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
func (in *EnvScalingGroupStatus) DeepCopy() *EnvScalingGroupStatus
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"`
// 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 EnvVolumeMount ¶ added in v0.0.10
type EnvVolumeMount struct {
// ClaimName is an existing, Bound PersistentVolumeClaim in this Env's
// namespace. Cross-namespace mounts are impossible in Kubernetes, which is
// exactly the authorisation boundary this feature relies on: the sandbox Pod
// runs in the Env's namespace, so a caller can only ever reach claims their
// own identity resolved to.
// +required
ClaimName string `json:"claimName"`
// MountPath is the absolute path inside the sandbox container.
// +required
MountPath string `json:"mountPath"`
// SubPath mounts a subtree of the volume instead of its root. Relative, no
// ".." segments. Recommended whenever the backing PersistentVolume is
// exposed at its filesystem root.
//
// Note kubelet creates a missing subPath directory, and the backing
// filesystem is mounted read-write on the host regardless of ReadOnly, so a
// mistyped SubPath yields a silently-empty mount rather than an error.
// +optional
SubPath string `json:"subPath,omitempty"`
// ReadOnly defaults to true. Read it only through IsReadOnly() — a nil
// pointer must never be treated as read-write.
// +optional
// +kubebuilder:default=true
ReadOnly *bool `json:"readOnly,omitempty"`
}
EnvVolumeMount mounts one existing PersistentVolumeClaim, or one subtree of it, into the sandbox container.
It is deliberately not corev1.VolumeMount: the Kubernetes volume name is derived rather than user-supplied (see sandboxrender.VolumeNameFor), and ReadOnly here lands on the volume source instead of the mount.
func (*EnvVolumeMount) DeepCopy ¶ added in v0.0.10
func (in *EnvVolumeMount) DeepCopy() *EnvVolumeMount
DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvVolumeMount.
func (*EnvVolumeMount) DeepCopyInto ¶ added in v0.0.10
func (in *EnvVolumeMount) DeepCopyInto(out *EnvVolumeMount)
DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (EnvVolumeMount) IsReadOnly ¶ added in v0.0.10
func (v EnvVolumeMount) IsReadOnly() bool
IsReadOnly is the only sanctioned way to read EnvVolumeMount.ReadOnly.
nil means read-only: an omitted field must never widen access to a user's dataset. The CRD default (+kubebuilder:default=true) covers objects written through the API server, but it does not fire for objects constructed in Go (the API service builds the spec before validation runs) nor for Envs stored by an older CRD revision — so the nil case has to be safe on its own.
Never dereference ReadOnly directly.
type GatewaySpec ¶ added in v0.0.10
type GatewaySpec struct {
// Enabled injects the egress gateway sidecar into every sandbox Pod of this
// environment. Without it, a create request carrying network rules is
// refused rather than silently unenforced.
// +optional
Enabled bool `json:"enabled,omitempty"`
}
GatewaySpec is the whole of a SandboxEnv's network configuration: whether its sandboxes get the egress gateway.
It is a single switch on purpose. Enabling the gateway adds a sidecar and an iptables redirect to the Pod, which is a Pod-spec change and therefore rolls the pool — that is the one decision that genuinely belongs to the environment. Everything else (what may be reached, what gets injected into which request) is a property of one sandbox, arrives on the create call, and is expressed in standard E2B terms: network.allowOut / denyOut, network.rules with Secret.fill(), and envVars for whatever placeholder the caller wants its tools to see.
The Env used to be able to declare egress rules and injection rules of its own. That bought nothing: a create request's network config replaced the Env's outright, so the Env's rules were a default rather than a floor, and Env-level injection applied the same credentials to every tenant sharing the environment. What it cost was a second configuration surface, a merge semantics between the two (union for injection, replace for filtering), and a dialect users had to learn on top of the E2B SDK.
func (*GatewaySpec) DeepCopy ¶ added in v0.0.10
func (in *GatewaySpec) DeepCopy() *GatewaySpec
DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewaySpec.
func (*GatewaySpec) DeepCopyInto ¶ added in v0.0.10
func (in *GatewaySpec) DeepCopyInto(out *GatewaySpec)
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
DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HandsE2B.
func (*HandsE2B) DeepCopyInto ¶ added in v0.0.8
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,
// written as ${e2b.secrets.NAME}. For an Authorization header, that is a
// Bearer prefix followed by the reference to 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 header value template,
// written as ${e2b.secrets.NAME}. This is the same syntax the E2B SDK's
// Secret.fill() produces, so a rule authored against the SDK and a rule
// authored here are byte-identical.
Name string `json:"name"`
// ValueFrom points at the Secret key holding the credential — for a vault
// reference, the caller's own vault Secret. It must live in the sandbox's
// namespace.
//
// A credential a tool has to *see* (because it validates the key's shape, or
// signs with it locally) is not this feature's business: set an ordinary
// environment variable on the create call to whatever decoy or real value
// the tool should read, and let the header rule replace what goes on the
// wire.
ValueFrom SecretKeyRef `json:"valueFrom"`
}
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"`
// 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
func (in *ManagedAgentClassifier) DeepCopy() *ManagedAgentClassifier
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 {
// Repository is the image to run. Optional: left empty, the agent gets the
// deployment's default Brain image, so an agent can be created from a prompt
// alone. A deployment that publishes no default rejects an agent without one,
// rather than guessing a reference that would surface later as a pull failure.
// +optional
Repository string `json:"repository,omitempty"`
// +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
func (in *ManagedAgentObservability) DeepCopy() *ManagedAgentObservability
DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedAgentObservability.
func (*ManagedAgentObservability) DeepCopyInto ¶ added in v0.0.8
func (in *ManagedAgentObservability) DeepCopyInto(out *ManagedAgentObservability)
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
func (in *ManagedAgentScenario) DeepCopy() *ManagedAgentScenario
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.
//
// Optional: omitted, the agent runs the deployment's default Brain image, which
// is what lets an agent be created from a prompt alone. Set it to pin a specific
// build, or when the deployment publishes no default.
// +optional
Image ManagedAgentImage `json:"image,omitempty"`
// 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. At most one branch may be set.
//
// Declaring none is how an agent takes the deployment's default sandbox
// supply, which is what lets one be created from a prompt alone. The default
// is resolved on every reconcile rather than copied in at creation, so the
// deployment can re-point it — a sandbox image tag that rolls with its own
// build would otherwise leave every agent pinned to whatever was current the
// day it was created. A deployment that publishes no default answers an agent
// without a branch with HandsReady=False.
// +optional
Hands ManagedAgentHands `json:"hands,omitzero"`
// 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,
// because the session-to-sandbox map lives in the daemon's memory: a second
// replica that has not served a thread would build it a second sandbox, and the
// thread's files would appear and disappear depending on which replica answered.
//
// This is a property of the daemon, not of the platform. Re-attaching to a
// running sandbox by id works, so lifting the constraint is a matter of moving
// that map somewhere both replicas can read.
// +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
func (in *PoolAutoScalingStatus) DeepCopy() *PoolAutoScalingStatus
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 {
// Source says where the supply came from: "agent" when the spec declares a
// branch, "platformDefault" when it declares none and the deployment's default
// answered instead. Without it the two are indistinguishable on the object,
// since the default is applied per reconcile and never written to the spec.
// +kubebuilder:validation:Enum=agent;platformDefault
// +optional
Source string `json:"source,omitempty"`
// +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
func (in *SandboxEnvTemplateRef) DeepCopy() *SandboxEnvTemplateRef
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 opens the private ranges (RFC1918, CGNAT, ULA)
// wholesale for a request that declares filtering. Default false.
//
// Usually unnecessary: naming an internal host or CIDR in Egress already
// reaches it, because a specific allowlist entry lifts the baseline for the
// destination it names. This is for "allow everything, the cluster network
// included" — a wildcard entry deliberately does not imply that.
//
// It never opens the cloud-metadata and link-local ranges. Those are denied
// unconditionally: an unauthenticated GET to 169.254.169.254 (or, on this
// cloud, 100.100.100.200) hands out instance credentials, and no sandbox
// workload has a legitimate reason to reach them.
//
// Implied when Egress is nil and DisableEgress is false: a request that
// filters nothing (rules only, say) must not be stricter than one that says
// nothing at all, where private ranges are reachable.
// +optional
AllowPrivateNetworks bool `json:"allowPrivateNetworks,omitempty"`
}
SandboxNetworkPolicy is the per-sandbox egress configuration carried on a create request. It is never stored on a SandboxEnv or SandboxPool.
Enforcement is 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. The ruleset is pushed at claim time and reset on release. Semantics are allowlist / default-deny.
func (*SandboxNetworkPolicy) DeepCopy ¶ added in v0.0.7
func (in *SandboxNetworkPolicy) DeepCopy() *SandboxNetworkPolicy
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"`
// Gateway, when enabled, injects the transparent egress proxy sidecar into
// this Pool's sandbox Pods. It is a Pod-shape decision and nothing more: the
// rules the proxy enforces, and the credentials it injects, are per-sandbox
// and arrive at claim time. For Env-owned Pools this is projected from the
// Env's overrides.gateway.
// +optional
Gateway *GatewaySpec `json:"gateway,omitempty"`
// 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"`
// 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 ¶
func (in *SandboxReservationSpec) DeepCopy() *SandboxReservationSpec
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 ¶
func (in *SandboxTemplateStatus) DeepCopy() *SandboxTemplateStatus
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: the sidecar terminates TLS for the listed hosts and sets the configured headers, so the sandbox can use a credential without ever being able to read it.
It is assembled at claim time from one create request's network.rules and the caller's own vault. It is never stored on a SandboxEnv or SandboxPool — a credential shared by an environment would be a credential shared by every tenant of it.
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.
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
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 ¶
func (in *TemplateVisibilityRule) DeepCopy() *TemplateVisibilityRule
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.