Skip to main content

Migration Plan: Agent CRD to Standard Kubernetes Workloads

Status: ✅ Completed Created: 2026-01-23 Completed: 2026-01-28 Target: Rossoctl UI v2.x

Executive Summary

This document outlines the phased migration of the Rossoctl UI from managing agents via the custom Agent CRD (processed by rossoctl-operator) to directly creating standard Kubernetes workloads (Deployments, Services, and eventually StatefulSets and Jobs).

Goals:

  • Remove dependency on rossoctl-operator for agent deployment
  • Use standard Kubernetes primitives for better portability
  • Maintain backward compatibility during transition
  • Enable future support for StatefulSets and Jobs

Table of Contents

  1. Current State Analysis
  2. Target State
  3. Label Standards
  4. Migration Phases
  5. API Changes
  6. RBAC Requirements
  7. Testing Strategy
  8. Rollback Plan

1. Current State Analysis

Current Architecture

┌─────────────┐ POST /agents ┌─────────────────┐
│ Rossoctl UI │ ──────────────────▶ │ Backend (FastAPI)│
└─────────────┘ └────────┬────────┘

│ Creates Agent CRD

┌─────────────────┐
│ Kubernetes API │
└────────┬────────┘

│ Watches Agent CRD

┌─────────────────┐
│rossoctl-operator │
└────────┬────────┘

│ Creates

┌───────────────┴───────────────┐
│ │
┌──────▼──────┐ ┌───────▼───────┐
│ Deployment │ │ Service │
└─────────────┘ └───────────────┘

Current Agent CRD Structure

File: rossoctl/backend/app/routers/agents.py (lines 1006-1136)

apiVersion: agent.rossoctl.dev/v1alpha1
kind: Agent
metadata:
name: <agent-name>
namespace: <namespace>
labels:
app.kubernetes.io/created-by: rossoctl-ui
app.kubernetes.io/name: rossoctl-operator
rossoctl.io/type: agent
rossoctl.io/protocol: <protocol>
rossoctl.io/framework: <framework>
spec:
description: "Agent description"
replicas: 1
servicePorts:
- name: http
port: 8080
targetPort: 8000
protocol: TCP
imageSource:
image: <image-url>
podTemplateSpec:
spec:
containers:
- name: agent
image: <image-url>
env: [...]
ports: [...]
resources: {...}
volumeMounts: [...]
volumes: [...]

Key Backend Files

FilePurposeLines of Interest
rossoctl/backend/app/routers/agents.pyAgent API endpoints1006-1136 (manifest), 262-299 (list)
rossoctl/backend/app/services/kubernetes.pyK8s API wrapper82-103 (list resources)
rossoctl/backend/app/core/constants.pyCRD/label constantsAll

Key Frontend Files

FilePurpose
rossoctl/ui-v2/src/pages/AgentCatalogPage.tsxAgent listing
rossoctl/ui-v2/src/pages/AgentDetailPage.tsxAgent details
rossoctl/ui-v2/src/pages/ImportAgentPage.tsxAgent creation
rossoctl/ui-v2/src/services/api.tsAPI client
rossoctl/ui-v2/src/types/index.tsTypeScript types

2. Target State

Target Architecture

┌─────────────┐ POST /agents ┌─────────────────┐
│ Rossoctl UI │ ──────────────────▶ │ Backend (FastAPI)│
└─────────────┘ └────────┬────────┘

│ Creates directly

┌─────────────────┐
│ Kubernetes API │
└────────┬────────┘

┌───────────────┼───────────────┐
│ │ │
┌──────▼──────┐ ┌─────▼─────┐ ┌───────▼───────┐
│ Deployment │ │ Service │ │ HTTPRoute │
└─────────────┘ └───────────┘ └───────────────┘

Benefits

  1. No operator dependency - Agents work without rossoctl-operator running
  2. Standard K8s primitives - Better tooling support (kubectl, Lens, etc.)
  3. Simpler debugging - Direct inspection of Deployments/Services
  4. Future flexibility - Easy to add StatefulSets, Jobs, CronJobs

3. Label Standards

Required Labels (All Workloads)

All agent workloads (Deployment, StatefulSet, Job) and their managed Pods MUST have:

LabelValuePurpose
rossoctl.io/typeagentIdentifies resource as a Rossoctl agent
app.kubernetes.io/name<agent-name>Standard K8s app name label
rossoctl.io/protocola2aProtocol type (a2a, mcp, etc.)
LabelValuePurpose
app.kubernetes.io/managed-byrossoctl-uiResource manager
app.kubernetes.io/componentagentComponent type
rossoctl.io/framework<framework>Framework (LangGraph, CrewAI, etc.)
rossoctl.io/workload-typedeploymentWorkload type (deployment/statefulset/job)

Label Selector for Agents

To list all agents in a namespace:

rossoctl.io/type=agent

To list all A2A agents:

rossoctl.io/type=agent,rossoctl.io/protocol=a2a

4. Migration Phases

Phase 1: Backend Infrastructure

Goal: Add backend support for creating/managing Deployments and Services directly.

1.1 Add Kubernetes Core API Methods

File: rossoctl/backend/app/services/kubernetes.py

Add new methods for core Kubernetes resources:

# Deployments
def create_deployment(namespace: str, body: dict) -> dict
def get_deployment(namespace: str, name: str) -> dict
def list_deployments(namespace: str, label_selector: str = None) -> list
def delete_deployment(namespace: str, name: str) -> None
def patch_deployment(namespace: str, name: str, body: dict) -> dict

# Services
def create_service(namespace: str, body: dict) -> dict
def get_service(namespace: str, name: str) -> dict
def delete_service(namespace: str, name: str) -> None

# Future: StatefulSets (placeholder)
def create_statefulset(namespace: str, body: dict) -> dict
def get_statefulset(namespace: str, name: str) -> dict
def list_statefulsets(namespace: str, label_selector: str = None) -> list
def delete_statefulset(namespace: str, name: str) -> None

# Future: Jobs (placeholder)
def create_job(namespace: str, body: dict) -> dict
def get_job(namespace: str, name: str) -> dict
def list_jobs(namespace: str, label_selector: str = None) -> list
def delete_job(namespace: str, name: str) -> None

1.2 Update Constants

File: rossoctl/backend/app/core/constants.py

# Workload types
WORKLOAD_TYPE_DEPLOYMENT = "deployment"
WORKLOAD_TYPE_STATEFULSET = "statefulset" # Future
WORKLOAD_TYPE_JOB = "job" # Future

# Label keys
LABEL_ROSSOCTL_TYPE = "rossoctl.io/type"
LABEL_ROSSOCTL_PROTOCOL = "rossoctl.io/protocol"
LABEL_ROSSOCTL_FRAMEWORK = "rossoctl.io/framework"
LABEL_ROSSOCTL_WORKLOAD_TYPE = "rossoctl.io/workload-type"
LABEL_APP_NAME = "app.kubernetes.io/name"
LABEL_MANAGED_BY = "app.kubernetes.io/managed-by"

# Label values
VALUE_TYPE_AGENT = "agent"
VALUE_MANAGED_BY_UI = "rossoctl-ui"

1.3 Add Manifest Builders

File: rossoctl/backend/app/routers/agents.py (new functions)

def _build_deployment_manifest(request: CreateAgentRequest, image: str) -> dict:
"""Build Kubernetes Deployment manifest for an agent."""

def _build_service_manifest(request: CreateAgentRequest) -> dict:
"""Build Kubernetes Service manifest for an agent."""

# Future placeholders
def _build_statefulset_manifest(request: CreateAgentRequest, image: str) -> dict:
"""Build Kubernetes StatefulSet manifest for an agent. (Future)"""
raise NotImplementedError("StatefulSet support coming in future release")

def _build_job_manifest(request: CreateAgentRequest, image: str) -> dict:
"""Build Kubernetes Job manifest for an agent. (Future)"""
raise NotImplementedError("Job support coming in future release")

Phase 2: Deployment Support

Goal: Implement full Deployment + Service creation workflow.

2.1 Deployment Manifest Structure

apiVersion: apps/v1
kind: Deployment
metadata:
name: <agent-name>
namespace: <namespace>
labels:
rossoctl.io/type: agent
rossoctl.io/protocol: a2a
rossoctl.io/framework: <framework>
rossoctl.io/workload-type: deployment
app.kubernetes.io/name: <agent-name>
app.kubernetes.io/managed-by: rossoctl-ui
annotations:
rossoctl.io/description: "<description>"
rossoctl.io/shipwright-build: "<build-name>" # if built from source
spec:
replicas: 1
selector:
matchLabels:
rossoctl.io/type: agent
app.kubernetes.io/name: <agent-name>
template:
metadata:
labels:
rossoctl.io/type: agent
rossoctl.io/protocol: a2a
rossoctl.io/framework: <framework>
app.kubernetes.io/name: <agent-name>
spec:
containers:
- name: agent
image: <image>
imagePullPolicy: Always
env:
- name: PORT
value: "8000"
- name: HOST
value: "0.0.0.0"
# ... other env vars
ports:
- containerPort: 8000
name: http
protocol: TCP
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 1Gi
volumeMounts:
- name: cache
mountPath: /app/.cache
- name: shared-data
mountPath: /shared
volumes:
- name: cache
emptyDir: {}
- name: shared-data
emptyDir: {}

2.2 Service Manifest Structure

apiVersion: v1
kind: Service
metadata:
name: <agent-name>
namespace: <namespace>
labels:
rossoctl.io/type: agent
rossoctl.io/protocol: a2a
app.kubernetes.io/name: <agent-name>
app.kubernetes.io/managed-by: rossoctl-ui
spec:
type: ClusterIP
selector:
rossoctl.io/type: agent
app.kubernetes.io/name: <agent-name>
ports:
- name: http
port: 8080
targetPort: 8000
protocol: TCP

2.3 Update Agent Creation Endpoint

File: rossoctl/backend/app/routers/agents.py

Modify create_agent() endpoint to:

  1. Accept new parameter workload_type (default: deployment)
  2. Create Deployment instead of Agent CRD
  3. Create Service for the Deployment
  4. Create HTTPRoute (unchanged)
@router.post("/agents")
async def create_agent(request: CreateAgentRequest):
# Validate workload type
if request.workload_type not in [WORKLOAD_TYPE_DEPLOYMENT]:
raise HTTPException(400, f"Unsupported workload type: {request.workload_type}")

# Build and create Deployment
deployment_manifest = _build_deployment_manifest(request, image)
k8s.create_deployment(request.namespace, deployment_manifest)

# Build and create Service
service_manifest = _build_service_manifest(request)
k8s.create_service(request.namespace, service_manifest)

# Create HTTPRoute if requested (unchanged)
if request.create_route:
# ... existing HTTPRoute logic

2.4 Update Agent List Endpoint

File: rossoctl/backend/app/routers/agents.py

Modify list_agents() to query Deployments instead of Agent CRD:

@router.get("/agents")
async def list_agents(namespace: str):
label_selector = f"{LABEL_ROSSOCTL_TYPE}={VALUE_TYPE_AGENT}"

deployments = k8s.list_deployments(namespace, label_selector)
# Future: Also list StatefulSets and Jobs with same selector

agents = []
for deploy in deployments:
agents.append({
"name": deploy["metadata"]["name"],
"namespace": deploy["metadata"]["namespace"],
"status": _get_deployment_status(deploy),
"labels": deploy["metadata"].get("labels", {}),
"workloadType": "deployment",
# ... other fields
})

return agents

2.5 Update Agent Get Endpoint

Return Deployment details with associated Service info:

@router.get("/agents/{namespace}/{name}")
async def get_agent(namespace: str, name: str):
deployment = k8s.get_deployment(namespace, name)
service = k8s.get_service(namespace, name)

return {
"metadata": deployment["metadata"],
"spec": deployment["spec"],
"status": _get_deployment_status(deployment),
"service": service,
"workloadType": "deployment",
}

2.6 Update Agent Delete Endpoint

Delete Deployment, Service, and associated resources:

@router.delete("/agents/{namespace}/{name}")
async def delete_agent(namespace: str, name: str):
deleted = []

# Delete Deployment
try:
k8s.delete_deployment(namespace, name)
deleted.append(f"Deployment/{name}")
except NotFoundError:
pass

# Delete Service
try:
k8s.delete_service(namespace, name)
deleted.append(f"Service/{name}")
except NotFoundError:
pass

# Delete HTTPRoute (unchanged)
# Delete Shipwright Build/BuildRun (unchanged)

return {"deleted": deleted}

2.7 Update Shipwright Build Finalization

Modify finalize_shipwright_build() to create Deployment instead of Agent CRD:

@router.post("/agents/{namespace}/{name}/finalize-shipwright-build")
async def finalize_shipwright_build(namespace: str, name: str, request: FinalizeRequest):
# ... get build info, validate success ...

# Create Deployment instead of Agent CRD
deployment_manifest = _build_deployment_manifest(config, output_image)
k8s.create_deployment(namespace, deployment_manifest)

# Create Service
service_manifest = _build_service_manifest(config)
k8s.create_service(namespace, service_manifest)

# Create HTTPRoute if requested
# ...

Phase 3: Frontend Updates

Goal: Update frontend to work with new Deployment-based agents.

3.1 Update Type Definitions

File: rossoctl/ui-v2/src/types/index.ts

// Workload types
export type WorkloadType = 'deployment' | 'statefulset' | 'job';

export interface Agent {
name: string;
namespace: string;
description?: string;
status: 'Ready' | 'Not Ready' | 'Progressing' | 'Failed';
labels: {
protocol?: string;
framework?: string;
type?: string;
};
workloadType: WorkloadType;
createdAt?: string;
}

export interface AgentDetail {
metadata: {
name: string;
namespace: string;
labels: Record<string, string>;
annotations?: Record<string, string>;
creationTimestamp: string;
uid: string;
};
spec: {
replicas?: number;
template?: {
spec: {
containers: Array<{
image: string;
env?: Array<{ name: string; value?: string }>;
}>;
};
};
};
status: DeploymentStatus;
service?: ServiceInfo;
workloadType: WorkloadType;
}

export interface DeploymentStatus {
replicas?: number;
readyReplicas?: number;
availableReplicas?: number;
conditions?: Array<{
type: string;
status: string;
reason?: string;
message?: string;
lastTransitionTime?: string;
}>;
}

export interface CreateAgentRequest {
// ... existing fields ...
workloadType?: WorkloadType; // default: 'deployment'
}

3.2 Update Agent Catalog Page

File: rossoctl/ui-v2/src/pages/AgentCatalogPage.tsx

  • Add workload type indicator (icon or badge)
  • Update status logic for Deployment conditions
  • No major UI changes needed

3.3 Update Agent Detail Page

File: rossoctl/ui-v2/src/pages/AgentDetailPage.tsx

  • Update status tab to show Deployment conditions
  • Show replica count and availability
  • Show Service information (ClusterIP, ports)
  • Update YAML tab to show Deployment YAML

3.4 Update Import Agent Page

File: rossoctl/ui-v2/src/pages/ImportAgentPage.tsx

  • Add workload type selector (disabled for now, default to Deployment)
  • Update form submission to include workloadType
// Future: Workload type selector (Phase 5)
<FormGroup label="Workload Type" fieldId="workload-type">
<FormSelect
value={workloadType}
onChange={(_, value) => setWorkloadType(value as WorkloadType)}
isDisabled={true} // Enable in Phase 5
>
<FormSelectOption value="deployment" label="Deployment (Recommended)" />
<FormSelectOption value="statefulset" label="StatefulSet" isDisabled />
<FormSelectOption value="job" label="Job" isDisabled />
</FormSelect>
<FormHelperText>
StatefulSet and Job support coming soon.
</FormHelperText>
</FormGroup>

Phase 4: Migration Tooling

Goal: Provide tools to migrate existing Agent CRD resources to Deployments.

Status: ✅ Implemented

4.1 CLI Migration Script

File: rossoctl/tools/migrate_agents.py

A command-line tool for migrating Agent CRDs to Kubernetes Deployments.

Installation

The script is included in the rossoctl package. Ensure you have the kubernetes Python package installed:

pip install kubernetes
Usage
# Basic usage - list agents that can be migrated (dry-run by default)
python -m rossoctl.tools.migrate_agents --namespace <namespace>

# Dry-run migration (shows what would happen without making changes)
python -m rossoctl.tools.migrate_agents --namespace team1 --dry-run

# Actually perform the migration
python -m rossoctl.tools.migrate_agents --namespace team1 --no-dry-run

# Migrate and delete old Agent CRDs after successful migration
python -m rossoctl.tools.migrate_agents --namespace team1 --no-dry-run --delete-old

# Migrate a specific agent only
python -m rossoctl.tools.migrate_agents --namespace team1 --agent my-agent --no-dry-run

# Output results as JSON (useful for scripting)
python -m rossoctl.tools.migrate_agents --namespace team1 --json

# Verbose output for debugging
python -m rossoctl.tools.migrate_agents --namespace team1 -v
Command-Line Options
OptionShortDefaultDescription
--namespace-ndefaultKubernetes namespace to migrate agents from
--agent-a(all)Specific agent name to migrate (migrates all if not specified)
--dry-runTrueShow what would be done without making changes
--no-dry-runActually perform the migration
--delete-oldFalseDelete Agent CRDs after successful migration
--jsonFalseOutput results as JSON
--verbose-vFalseEnable verbose logging
Migration Logic
  1. List Agent CRDs: Query all Agent CRDs in the specified namespace
  2. Check for existing Deployments: Skip agents that already have a Deployment with the same name
  3. Build Deployment manifest: Extract configuration from Agent CRD and build Deployment spec
  4. Build Service manifest: Create matching Service for the agent
  5. Create resources: Apply Deployment and Service to cluster
  6. Cleanup (optional): Delete the original Agent CRD if --delete-old is specified
Migration Annotations

Migrated Deployments include tracking annotations:

annotations:
rossoctl.io/migrated-from: "agent-crd"
rossoctl.io/migration-timestamp: "2026-01-23T10:30:00+00:00"
Example Output
============================================================
Rossoctl Agent CRD Migration - DRY-RUN
============================================================
Namespace: team1
Delete old CRDs: False
Total Agent CRDs found: 3
============================================================

🔍 weather-agent: dry-run
- Would create Deployment
- Would create Service

🔍 chat-agent: dry-run
- Would create Deployment
- Service already exists

⏭️ data-processor: skipped
- Deployment already exists

============================================================
SUMMARY
============================================================
Total: 3
Would migrate: 2
Skipped (already migrated): 1
Failed: 0
============================================================

💡 This was a dry-run. Use --no-dry-run to actually perform the migration.
JSON Output Format

When using --json, the output follows this structure:

{
"namespace": "team1",
"dry_run": true,
"delete_old": false,
"total": 3,
"migrated": 0,
"skipped": 1,
"failed": 0,
"dry_run_count": 2,
"results": [
{
"name": "weather-agent",
"namespace": "team1",
"status": "dry-run",
"deployment_created": false,
"service_created": false,
"agent_crd_deleted": false,
"messages": ["Would create Deployment", "Would create Service"],
"errors": []
}
]
}

4.2 Backend Migration Endpoints

File: rossoctl/backend/app/routers/agents.py

Three API endpoints are available for migration:

List Migratable Agents
GET /agents/migration/migratable?namespace=team1

Returns a list of Agent CRDs that can be migrated, indicating which already have Deployments.

Migrate Single Agent
POST /agents/{namespace}/{name}/migrate
Content-Type: application/json

{
"delete_old": false
}

Migrates a single Agent CRD to a Deployment.

Batch Migration
POST /agents/migration/migrate-all?namespace=team1&dry_run=true&delete_old=false

Migrates all Agent CRDs in a namespace with optional dry-run mode.

4.3 Backward Compatibility Period

File: rossoctl/backend/app/core/config.py

During the migration period, the backend supports both Agent CRDs and Deployments via the enable_legacy_agent_crd setting:

# config.py
enable_legacy_agent_crd: bool = True # Set to False after full migration

When enabled, the list_agents endpoint will:

  1. Query Deployments with rossoctl.io/type=agent label
  2. Query Agent CRDs in the namespace
  3. Skip Agent CRDs that already have a corresponding Deployment (already migrated)
  4. Return a combined list of both Deployment-based and CRD-based agents
Disabling Legacy Support

After migration is complete:

  1. Set ENABLE_LEGACY_AGENT_CRD=false environment variable
  2. Restart the backend service
  3. Only Deployment-based agents will be listed
  4. Agent CRDs can be cleaned up from the cluster

Phase 5: Future Workload Types (Placeholder)

Goal: Add support for StatefulSets and Jobs.

5.1 StatefulSet Support

Use cases:

  • Agents requiring stable network identities
  • Agents requiring persistent storage
  • Agents requiring ordered deployment/scaling

Implementation:

  • Add _build_statefulset_manifest() function
  • Add StatefulSet CRUD operations to kubernetes.py
  • Update list/get/delete endpoints to handle StatefulSets
  • Add PVC template support
  • Enable StatefulSet option in Import page

5.2 Job Support

Use cases:

  • One-time agent tasks
  • Batch processing agents
  • Scheduled agent runs (CronJob)

Implementation:

  • Add _build_job_manifest() function
  • Add Job CRUD operations to kubernetes.py
  • Different status handling (Succeeded/Failed vs Running)
  • Optional CronJob support

5.3 Workload Type Auto-Selection

Consider auto-selecting workload type based on agent requirements:

def _determine_workload_type(request: CreateAgentRequest) -> WorkloadType:
if request.persistent_storage:
return WORKLOAD_TYPE_STATEFULSET
if request.run_once:
return WORKLOAD_TYPE_JOB
return WORKLOAD_TYPE_DEPLOYMENT

5. API Changes

New/Modified Endpoints

EndpointChangePhase
POST /agentsAdd workload_type param, create Deployment+Service2
GET /agentsQuery Deployments instead of Agent CRD2
GET /agents/{ns}/{name}Return Deployment details2
DELETE /agents/{ns}/{name}Delete Deployment+Service2
POST /agents/{ns}/{name}/finalize-shipwright-buildCreate Deployment instead of Agent2
POST /agents/{ns}/{name}/migrateNew: Migrate Agent CRD to Deployment4

Request/Response Schema Changes

CreateAgentRequest:

{
"name": "my-agent",
"namespace": "team1",
"workloadType": "deployment", // NEW: default "deployment"
// ... other fields unchanged
}

Agent (list response):

{
"name": "my-agent",
"namespace": "team1",
"status": "Ready",
"workloadType": "deployment", // NEW
"labels": {...}
}

AgentDetail (get response):

{
"metadata": {...},
"spec": {...}, // Deployment spec instead of Agent spec
"status": {...}, // Deployment status
"service": {...}, // NEW: Service info
"workloadType": "deployment" // NEW
}

6. RBAC Requirements

New Permissions Required

The Rossoctl backend ServiceAccount needs additional permissions:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: rossoctl-backend
rules:
# Existing permissions for CRDs...

# NEW: Deployments
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "create", "update", "patch", "delete"]

# NEW: Services
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "create", "delete"]

# NEW: Pods (for status/logs)
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]

# Future: StatefulSets
- apiGroups: ["apps"]
resources: ["statefulsets"]
verbs: ["get", "list", "create", "update", "patch", "delete"]

# Future: Jobs
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["get", "list", "create", "delete"]

Helm Chart Updates

File: charts/rossoctl/templates/ui.yaml

Update the RBAC rules for the rossoctl-backend ServiceAccount.


7. Testing Strategy

Unit Tests

  • Test manifest builders produce valid YAML
  • Test label selectors return correct resources
  • Test status mapping logic

Integration Tests

  • Create agent via API, verify Deployment + Service created
  • Delete agent, verify cleanup
  • Build agent from source, verify finalization creates Deployment
  • Test migration endpoint

E2E Tests

File: rossoctl/tests/e2e/

  • Full workflow: Import agent → Build → Deploy → Chat → Delete
  • Migration: Create Agent CRD → Migrate → Verify Deployment

Manual Testing Checklist

  • Import agent from image (Deployment created)
  • Import agent from source (Build → Deployment)
  • Agent appears in catalog with correct status
  • Agent detail page shows Deployment info
  • Chat works with Deployment-based agent
  • Delete agent cleans up all resources
  • HTTPRoute works correctly
  • Migrate existing Agent CRD to Deployment

8. Rollback Plan

Feature Flag

Add feature flag to switch between Agent CRD and Deployment modes:

# config.py
USE_DEPLOYMENT_WORKLOADS = os.getenv("USE_DEPLOYMENT_WORKLOADS", "true").lower() == "true"

Rollback Steps

  1. Set USE_DEPLOYMENT_WORKLOADS=false
  2. Restart backend
  3. New agents will use Agent CRD
  4. Existing Deployment-based agents continue to work
  5. Run reverse migration if needed

Data Preservation

  • Deployments can be converted back to Agent CRD if needed
  • All configuration stored in Deployment spec/annotations
  • Shipwright Build resources unchanged

Implementation Timeline

PhaseDescriptionEstimated Effort
1Backend InfrastructureMedium
2Deployment SupportLarge
3Frontend UpdatesMedium
4Migration ToolingSmall
5Future Workload TypesFuture

Open Questions

  1. Should we support both Agent CRD and Deployments long-term?

    • Recommendation: Deprecate Agent CRD after migration period
  2. How to handle agents created by rossoctl-operator?

    • They have associated Deployments already
    • Migration may need to transfer ownership
  3. Should the migration be automatic or manual?

    • Recommendation: Manual with tooling support
  4. What about agents with custom operator features?

    • Some Agent CRD features may not map 1:1 to Deployment
    • Document any feature gaps

References