ranctl Action Model
Role
bin/ranctl is the single mutable action entrypoint for operations. Skills, Symphony, Codex, and humans may request actions, but only ranctl turns intent into deterministic execution.
Lifecycle
Figure source: ../assets/infographics/ranctl-lifecycle.infographic
Core Object Model
scope: action scope such asbackend,cell_group,association, orincident.cell_group: concrete DU-high target such ascg-001.target_backend:stub_fapi_profile,local_fapi_profile, oraerial_fapi_profile.change_id: immutable identifier for a planned change.incident_id: immutable identifier for an observed incident.dry_run: request planning without mutation.ttl: action validity window.reason: human or workflow justification.idempotency_key: deduplicates repeat submissions.verify_window: time budget and checks for post-apply verification.max_blast_radius: upper bound on service impact.
Supported Commands
precheckplanapplyverifyrollbackobservecapture-artifacts
CLI Contract
bin/ranctl accepts:
--file PATHto load a JSON request from disk--json STRINGto pass a JSON request inline
Examples:
bin/ranctl plan --file examples/ranctl/precheck-switch-local.json
bin/ranctl apply --json '{"scope":"cell_group","cell_group":"cg-001","change_id":"chg-1","reason":"apply","idempotency_key":"chg-1","approval":{"approved":true,"approved_by":"operator","approved_at":"2026-03-21T07:00:00Z","ticket_ref":"CHG-1","source":"inline-example"},"verify_window":{"duration":"30s","checks":["gateway_healthy"]}}'JSON Request Shape
{
"scope": "cell_group",
"cell_group": "cg-001",
"target_backend": "local_fapi_profile",
"change_id": "chg-20260320-001",
"incident_id": null,
"dry_run": false,
"ttl": "15m",
"reason": "switch backend after lab validation",
"idempotency_key": "cg-001-switch-local-001",
"verify_window": {
"duration": "30s",
"checks": ["gateway_healthy", "cell_group_attached", "ue_ping_ok"]
},
"max_blast_radius": "single_cell_group"
}Example Response Shape
{
"status": "planned",
"command": "plan",
"change_id": "chg-20260320-001",
"summary": "backend switch prepared for cg-001",
"next": ["apply", "verify"],
"artifacts": ["plans/chg-20260320-001.json"]
}Artifact Paths
Bootstrap ranctl persists deterministic outputs under artifacts/:
artifacts/plans/<change_id>.jsonartifacts/changes/<change_id>.jsonartifacts/verify/<change_id>.jsonartifacts/captures/<incident_id-or-change_id>.jsonartifacts/rollback_plans/<change_id>.jsonartifacts/approvals/<change_id>-<command>.jsonartifacts/config_snapshots/<incident_id-or-change_id>.jsonartifacts/control_snapshots/<incident_id-or-change_id>.json
Execution Rules
precheckmust validate target existence, health, drain readiness, and config completeness.planmust produce an ordered action list plus rollback intent.applymust reject requests missingchange_id,reason, or approval state when required.verifymust use bounded checks with explicit failure criteria.rollbackmust restore the previous known-good target where possible.observeandcapture-artifactsare read-oriented and may execute without change approval.
In the current bootstrap implementation, precheck also returns:
- a
config_reportfromran_configvalidation - pass or fail status for
scope_valid,target_backend_known,verify_window_valid,config_shape_present, andcell_group_exists policydetails for controlled backend failover, including allowed targets and rollback target- optional
control_statedetails for attach freeze and drain workflow - optional
native_probedetails whenmetadata.native_probeis present - optional
runtimedetails whenmetadata.oai_runtimeis present
OAI Runtime Extension
ranctl can now orchestrate an external OpenAirInterface DU stack without moving runtime hot paths into the BEAM. This path is enabled through metadata.oai_runtime.
Example:
{
"metadata": {
"oai_runtime": {
"repo_root": "/opt/openairinterface5g",
"du_conf_path": "/opt/openairinterface5g/ci-scripts/conf_files/gnb-du.sa.band78.106prb.rfsim.conf",
"cucp_conf_path": "/opt/openairinterface5g/ci-scripts/conf_files/gnb-cucp.sa.f1.conf",
"cuup_conf_path": "/opt/openairinterface5g/ci-scripts/conf_files/gnb-cuup.sa.f1.conf",
"project_name": "ran-oai-du-cg-001",
"pull_images": true
}
}
}With this metadata:
planwrites a generated Compose asset underartifacts/runtime/<change_id>/docker-compose.ymlplanalso writes patched overlay confs underartifacts/runtime/<change_id>/conf/- source conf files remain untouched and are only used as overlay inputs
applyrunsdocker compose up -dforoai-cucp,oai-cuup, andoai-duprecheckvalidates split markers and required address patch points in the source confsverifyinspects container liveness and captures log tailsrollbackrunsdocker compose down -v --remove-orphans
Reference examples:
examples/ranctl/precheck-oai-du-docker.jsonexamples/ranctl/apply-oai-du-docker.jsonexamples/ranctl/apply-oai-du-docker-template.jsonexamples/ranctl/verify-oai-du-docker.jsonexamples/ranctl/rollback-oai-du-docker.json
Approval Model
- Non-destructive reads: no explicit approval beyond repo policy.
- Mutations with no service impact: approval gate optional but auditable.
- Service-affecting actions: explicit approval required.
- Backend switch and drain actions: explicit approval required.
Control-State Extension
metadata.control lets ranctl coordinate attach freeze and drain semantics without adding a second mutable entrypoint.
Example:
{
"metadata": {
"control": {
"attach_freeze": "activate",
"drain": "start"
}
}
}Supported verify and precheck checks:
attach_freeze_activedrain_activecell_group_draineddrain_idle
observe now includes control_state plus incident_summary so dashboards and skills can render the same operator-facing incident brief.
Native Probe Extension
metadata.native_probe lets ranctl open a bounded Port-backed backend session during precheck and verify without mutating the long-lived runtime.
Example:
{
"metadata": {
"native_probe": {
"backend_profile": "local_fapi_profile",
"session_payload": {
"fronthaul_session": "fh-precheck-001",
"host_interface": "sync0",
"strict_host_probe": true
}
}
}
}With this metadata:
precheckopens a short-lived backend session, reads backend health, and attempts activation for a hard gate checkprecheckreturnsnative_probeplus explicit checks fornative_probe_resolved,native_probe_host_ready, andnative_probe_activation_gate_clearnative_probealso returnshandshake_targetandprobe_observationsso operators can see what the backend actually inspected on the host- those observations now distinguish presence from readiness or bounded openability for bootstrap-safe host checks
verifyrepeats the same bounded probe so post-apply validation can fail on missing host or device prerequisitesobservecan lift persisted probe failures intoincident_summary.reasonsandsuggested_nextcapture-artifactswrites a deterministic probe snapshot underartifacts/probe_snapshots/<change_id-or-incident_id>.json
Reference example:
examples/ranctl/precheck-native-probe-local.json