Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@
identity:
description: Identity specifies optional per-workload identity overrides
properties:
allowedAudiences:
description: |-
AllowedAudiences specifies additional JWT audiences that the AuthProxy
sidecar should accept for inbound requests. This is a transitional
mechanism to support application-to-agent flows until the auth model
is finalized. See https://github.com/kagenti/kagenti-operator/issues/368
items:
type: string
type: array
spiffe:
description: SPIFFE specifies SPIFFE identity configuration overrides
properties:
Expand Down Expand Up @@ -151,6 +160,52 @@
- permissive
- strict
type: string
skills:
description: |-
Skills declares OCI skill images to mount into the agent pod as
Kubernetes ImageVolumes. Each skill is mounted read-only at
/agent/skills/<name>/. Requires the skillImageVolumes feature gate
and Kubernetes 1.31+ with the ImageVolume feature gate enabled.
items:
description: SkillImageRef identifies an OCI skill image to mount
into the agent pod.
properties:
image:
description: Image is the OCI image reference for the skill.
minLength: 1
type: string
mountPath:
description: |-
MountPath is the absolute path where the skill image is mounted in
the container. Different agent frameworks expect skills in different
locations (e.g. /agent/skills/my-skill, /app/.claude/skills/my-skill).
minLength: 1
pattern: ^/.*
type: string
name:
description: |-
Name is a unique identifier for this skill mount, used as the volume
name suffix (skill-<name>).
maxLength: 58
minLength: 1
pattern: ^[a-z0-9]([a-z0-9\-]*[a-z0-9])?$
type: string
pullPolicy:
description: |-
PullPolicy for pulling the OCI skill image. Defaults to Always for
:latest tags and IfNotPresent otherwise (standard Kubernetes behavior).
enum:
- Always
- Never
- IfNotPresent
type: string
required:
- image
- mountPath
- name
type: object
maxItems: 20
type: array
targetRef:
description: TargetRef identifies the workload backing this agent
runtime (duck typing).
Expand Down Expand Up @@ -433,7 +488,7 @@
lastTransitionTime:
description: |-
lastTransitionTime is the last time the condition transitioned from one status to another.
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.

Check warning on line 491 in charts/kagenti-operator/crds/agent.kagenti.dev_agentruntimes.yaml

View workflow job for this annotation

GitHub Actions / YAML Lint

491:151 [line-length] line too long (162 > 150 characters)
format: date-time
type: string
message:
Expand All @@ -445,7 +500,7 @@
observedGeneration:
description: |-
observedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date

Check warning on line 503 in charts/kagenti-operator/crds/agent.kagenti.dev_agentruntimes.yaml

View workflow job for this annotation

GitHub Actions / YAML Lint

503:151 [line-length] line too long (162 > 150 characters)
with respect to the current state of the instance.
format: int64
minimum: 0
Expand Down
4 changes: 4 additions & 0 deletions charts/kagenti-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ featureGates:
# Default false — cached mode is faster and sufficient when namespace ConfigMaps
# rarely change. Cache is cleared on webhook pod restart.
perWorkloadConfigResolution: false
# skillImageVolumes controls whether AgentRuntime can mount OCI skill images
# as Kubernetes ImageVolumes into agent pods. Requires Kubernetes 1.31+ with
# the ImageVolume feature gate enabled. Default false.
skillImageVolumes: false

# Platform defaults for AuthBridge sidecar injection.
# These are the lowest-priority layer — overridden by feature gates,
Expand Down
43 changes: 43 additions & 0 deletions kagenti-operator/api/v1alpha1/agentruntime_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ type AgentRuntimeSpec struct {
// +optional
// +kubebuilder:validation:Enum=disabled;permissive;strict
MTLSMode string `json:"mtlsMode,omitempty"`

// Skills declares OCI skill images to mount into the agent pod as
// Kubernetes ImageVolumes. Each skill is mounted read-only at
// /agent/skills/<name>/. Requires the skillImageVolumes feature gate
// and Kubernetes 1.31+ with the ImageVolume feature gate enabled.
// +optional
// +kubebuilder:validation:MaxItems=20
Skills []SkillImageRef `json:"skills,omitempty"`
}

// IdentitySpec configures workload identity for an AgentRuntime.
Expand Down Expand Up @@ -209,6 +217,41 @@ type CardStatus struct {
AttestedAgentSpiffeID string `json:"attestedAgentSpiffeID,omitempty"`
}

// +kubebuilder:validation:Enum=Always;Never;IfNotPresent
type SkillPullPolicy string

const (
SkillPullAlways SkillPullPolicy = "Always"
SkillPullNever SkillPullPolicy = "Never"
SkillPullIfNotPresent SkillPullPolicy = "IfNotPresent"
)

// SkillImageRef identifies an OCI skill image to mount into the agent pod.
type SkillImageRef struct {
// Name is a unique identifier for this skill mount, used as the volume
// name suffix (skill-<name>).
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=58
// +kubebuilder:validation:Pattern=`^[a-z0-9]([a-z0-9\-]*[a-z0-9])?$`
Name string `json:"name"`

// Image is the OCI image reference for the skill.
// +kubebuilder:validation:MinLength=1
Image string `json:"image"`

// MountPath is the absolute path where the skill image is mounted in
// the container. Different agent frameworks expect skills in different
// locations (e.g. /agent/skills/my-skill, /app/.claude/skills/my-skill).
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^/.*`
MountPath string `json:"mountPath"`

// PullPolicy for pulling the OCI skill image. Defaults to Always for
// :latest tags and IfNotPresent otherwise (standard Kubernetes behavior).
// +optional
PullPolicy SkillPullPolicy `json:"pullPolicy,omitempty"`
}

// AgentRuntimeStatus defines the observed state of AgentRuntime.
type AgentRuntimeStatus struct {
// Phase is the high-level state of the AgentRuntime
Expand Down
20 changes: 20 additions & 0 deletions kagenti-operator/api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions kagenti-operator/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ func main() {
Recorder: mgr.GetEventRecorderFor("agentruntime-controller"),
EnableCardDiscovery: enableCardDiscovery,
SpireTrustDomain: spireTrustDomain,
GetFeatureGates: featureGateLoader.Get,
}
if enableCardDiscovery {
artReconciler.AgentFetcher = agentFetcher
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,52 @@ spec:
- permissive
- strict
type: string
skills:
description: |-
Skills declares OCI skill images to mount into the agent pod as
Kubernetes ImageVolumes. Each skill is mounted read-only at
/agent/skills/<name>/. Requires the skillImageVolumes feature gate
and Kubernetes 1.31+ with the ImageVolume feature gate enabled.
items:
description: SkillImageRef identifies an OCI skill image to mount
into the agent pod.
properties:
image:
description: Image is the OCI image reference for the skill.
minLength: 1
type: string
mountPath:
description: |-
MountPath is the absolute path where the skill image is mounted in
the container. Different agent frameworks expect skills in different
locations (e.g. /agent/skills/my-skill, /app/.claude/skills/my-skill).
minLength: 1
pattern: ^/.*
type: string
name:
description: |-
Name is a unique identifier for this skill mount, used as the volume
name suffix (skill-<name>).
maxLength: 58
minLength: 1
pattern: ^[a-z0-9]([a-z0-9\-]*[a-z0-9])?$
type: string
pullPolicy:
description: |-
PullPolicy for pulling the OCI skill image. Defaults to Always for
:latest tags and IfNotPresent otherwise (standard Kubernetes behavior).
enum:
- Always
- Never
- IfNotPresent
type: string
required:
- image
- mountPath
- name
type: object
maxItems: 20
type: array
targetRef:
description: TargetRef identifies the workload backing this agent
runtime (duck typing).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Full AgentRuntime: enroll a Deployment as an agent with per-workload overrides.
# Overrides the SPIFFE trust domain and configures OTEL trace collection.
# Overrides the SPIFFE trust domain, configures OTEL trace collection, and
# mounts OCI skill images (requires skillImageVolumes feature gate + K8s 1.31+).
apiVersion: agent.kagenti.dev/v1alpha1
kind: AgentRuntime
metadata:
Expand All @@ -21,3 +22,7 @@ spec:
protocol: grpc
sampling:
rate: 0.1
skills:
- name: weather-forecast
image: ghcr.io/redhat-et/skillimage/weather-forecast:v1.0.0
mountPath: /agent/skills/weather-forecast
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# AgentRuntime with OCI skill images: mounts skill OCI images as ImageVolumes.
# Requires: skillImageVolumes feature gate enabled, Kubernetes 1.31+.
apiVersion: agent.kagenti.dev/v1alpha1
kind: AgentRuntime
metadata:
name: resume-agent-runtime
namespace: default
labels:
app.kubernetes.io/name: resume-agent
spec:
type: agent
targetRef:
apiVersion: apps/v1
kind: Deployment
name: resume-agent
skills:
- name: resume-reviewer
image: ghcr.io/redhat-et/skillimage/resume-reviewer:v1.0.0
mountPath: /agent/skills/resume-reviewer
- name: blog-writer
image: ghcr.io/redhat-et/skillimage/blog-writer:latest
mountPath: /agent/skills/blog-writer
pullPolicy: Always
Loading
Loading