Running both controller modes
harness-v1 is the previous execution path. It is kept so existing
wrapper-based installations can be retired on their own schedule, and it will be
removed in a future release. New installations never need this page.
For a new installation, follow Install Orka. It uses the
default harness-v2 mode.
This advanced guide is for clusters that also need a separate harness-v1
compatibility installation. The two installations share the Kubernetes API
server and CRDs. Each has its own Tasks, Sessions, controller state, and agent
execution resources.
The examples name the default installation orka and the compatibility
installation orka-compat. These are Helm installation names. They do not
select an Orka version or controller mode.
Controller modes
Each controller accepts exactly one required mode:
| Mode | Agent execution path |
|---|---|
harness-v1 | Legacy turn-oriented harness wrapper |
harness-v2 | ACP RuntimePools and RuntimeSessions |
There is no dual, auto, or harness-v1-drain mode. An installation never changes
mode in place.
The controller also requires a non-empty watched namespace that carries the
same mode as the orka.ai/controller-mode label. On first start the controller
labels an unlabeled namespace itself, so a Helm install with --create-namespace
needs no preparation. A namespace already labeled with the other mode fails
startup. To require an operator-applied label instead, run the controller with
--claim-namespace-mode=false.
You can still create the namespaces up front with the label in place:
export ORKA_CONTEXT='<your-kubeconfig-context>'
kubectl --context "${ORKA_CONTEXT}" create -f - <<'EOF'
apiVersion: v1
kind: Namespace
metadata:
name: orka-compat-system
labels:
orka.ai/controller-mode: harness-v1
---
apiVersion: v1
kind: Namespace
metadata:
name: orka-system
labels:
orka.ai/controller-mode: harness-v2
EOF
Each release installs a ValidatingAdmissionPolicy for its namespace. Once the label exists it can never change or be removed, and only that release's controller ServiceAccount may add it to an existing namespace. Do not relabel a namespace to move it between modes: the two harnesses own different resources in it. Recreate the installation in a new namespace instead.
Isolation checklist
The two installs share exactly two things: the Kubernetes API server, and one cluster-scoped CRD bundle. Everything else is duplicated.
The leader-election ID is hardcoded to 03b49a10.orka.ai in both installs, but each Lease lives in
its own watched namespace — so the two controllers never contend for the same lock, and never
coordinate over one Task population.
Use different values for every release-owned resource:
| Boundary | Harness v1 | Harness v2 |
|---|---|---|
| Helm installation name | orka-compat | orka |
controller.mode | harness-v1 | harness-v2 |
Namespace and controller.watchNamespace | orka-compat-system | orka-system |
| Controller API | v1-specific Service/endpoint | v2-specific Service/endpoint |
| Leader election | Lease in orka-compat-system | Lease in orka-system |
| State | v1-only SQLite/PVC/backups | v2-only SQLite/PVC/backups |
| Data plane | Wrapper Service and ledger | Dedicated ACP runtime namespace |
| Identity | v1 ServiceAccounts and Secrets | v2 ServiceAccounts and Secrets |
Set controller.acpRuntime.namespace=orka-runtimes for the default installation.
NetworkPolicies and namespace-scoped RBAC must prevent either controller from reading or writing the other watched namespace. A namespace-scoped controller cache is not an authorization boundary by itself.
The supported Helm topology co-locates each controller and its watched objects
in the release namespace. The chart rejects a different
controller.watchNamespace, which keeps all namespaced RBAC and release-owned
data-plane resources inside one boundary. Harness v2 still uses a separate
runtime namespace.
The v2 release owns cluster-scoped gateway and workspace-provider reconcilers. Do not enable those reconcilers in v1. Install common cluster-scoped admission resources once.
Manage CRDs once
CRDs are cluster-scoped, so both installations use one schema bundle capable of storing the supported v1 and v2 shapes. Designate a platform or GitOps owner, and have that owner apply the CRDs from the selected chart. From a source checkout matching the chart, the owner can run:
export ORKA_CHART='<path-to-chart.tgz>'
scripts/apply-helm-crds.sh "${ORKA_CHART}" "${ORKA_CONTEXT}"
Use --skip-crds for both Helm installations. Each still needs complete settings
for its images, Secrets, proxy, Publisher, storage, and selected mode.
The table above covers the settings that keep the installations separate.
Do not let both installations manage CRDs independently. Helm does not update crds/ during
helm upgrade.
Keep each installation's mode and watched namespace unchanged, including when recreating a deleted controller. Changing modes requires a separate installation. Orka currently supports new installations only. See Upgrading for support limits.
Route new work explicitly
Producers choose an installation by its API endpoint and watched namespace. During v2 rollout:
- leave existing v1 Tasks and Sessions on the v1 endpoint;
- install v2 in its fresh namespaces and run new v2 canaries;
- verify cross-namespace API access is forbidden;
- point selected producers at the v2 endpoint;
- create new v2 Agents, Tasks, and Sessions.
Unavailable v2 capacity fails closed. It never sends work to the v1 wrapper.
No protocol migration
Do not:
- patch a v1 Agent, AgentRuntime, or Task into v2;
- reuse a v1 controller PVC, database, wrapper ledger, or Session in v2;
- copy a transcript and claim continuation of the original Session;
- ask one controller to cancel, settle, publish, finalize, or clean up the other controller's work;
- change
controller.modeororka.ai/controller-modeon an existing installation.
You may copy non-secret configuration into a newly created object in the other installation. It has a new namespace, UID, Session lineage, attempt history, and external-effect history; it is not migrated work.
Drain and retire v1
Draining v1 is an operational procedure, not a controller mode:
- stop v1 API ingress and every internal or external v1 producer;
- revoke permissions that create v1 agent Tasks;
- record a cutoff and inventory queued, active, finalizing, and cleanup work;
- let existing work settle through v1, preserving unknown outcomes where acceptance cannot be disproved;
- repeat uncached inventory until v1 execution, Session settlement, finalizers, and wrapper-ledger cleanup reach zero;
- back up retained v1 history and state;
- remove v1 workloads and revoke their credentials;
- delete PVCs or historical data only under a separate retention decision.
The wrapper's authenticated Pod-template drain remains required before a wrapper upgrade. It protects in-memory v1 turns and is unrelated to controller mode or v2.
Rollback
Rollback changes only future routing. Stop new submissions to v2 and, if the v1 installation is still intentionally open, submit replacement work there as new v1 Tasks. Existing v2 work remains owned by v2 and must settle or be canceled through v2.
Keep the shared CRD superset while either v1 or v2 objects remain. Restore each installation only from its own coordinated Kubernetes and persistent-state backup; never restore one mode's state into the other.
The full architecture and release gates are in the isolated coexistence plan.