service-omni-queue-deploy
Verify that a Group (Type='Queue') exists with a QueueSobject binding to the requested routable sObject, reusing whatever is already there. With --create-if-missing, create the queue via the Metadata API (Group + QueueSobject) when none is bound, and optionally align its QueueRoutingConfigId to a caller-specified QRC. The skill discovers the queue by its QueueSobject.SobjectType binding, not by name, because real orgs name queues inconsistently (CaseQueue, messagingqueue, Omni_Demo_Cases_Queue) — the functional link between a queue and the routing it supports is the binding, not the DeveloperName. It is invoked by service-omni-channel-setup-coordinate; queue membership is a separate leaf (service-omni-queue-members-assign) and the QRC it aligns to comes from service-omni-queue-routing-config-deploy.
Inputs
bash scripts/verify-and-align.sh <org-alias> [Case|Incident|MessagingSession|VoiceCall] [routing_config_dn] [queue_developer_name] [--create-if-missing]
# create + bind a Voice queue on a fresh org:
bash scripts/verify-and-align.sh myorg VoiceCall Voice_Routing_Config "" --create-if-missing
org-alias (required).
sobject_type (optional, default Case).
routing_config_dn (optional) — when passed, forces alignment to that QRC; when omitted for Case it defaults to Case_Routing_Config; when omitted for other sObjects the skill reports the existing binding without forcing.
queue_developer_name (optional 4th positional) — the explicit queue to operate on, or the name to create with --create-if-missing.
--create-if-missing (flag, or QUEUE_CREATE_IF_MISSING=1) — create the queue via the Metadata API when none is bound; label defaults to a spaced form of the DeveloperName (override via QUEUE_LABEL).
Preconditions and safety
- Target org authenticated via
sf CLI (My Domain URL), Service Cloud license, sf CLI ≥ 2.139.6.
- The target sObject is enabled on the org — verified via
EntityDefinition before any write; missing sObjects block with a feature-enablement click-path (Incident Management for Incident, Enhanced Messaging for MessagingSession).
- When
routing_config_dn is supplied, that QRC must already exist (resolved by DeveloperName); otherwise the run blocks with a pointer to service-omni-queue-routing-config-deploy.
- The three-way
safe_to_write production guard applies.
Run
verify-and-align.sh runs the full sequence and emits the report:
- Prereq — confirm the sObject via
EntityDefinition.
- Discover —
QueueSobject WHERE SobjectType = '<sobject_type>'. A hit is reused. No hit: create via the Metadata API when --create-if-missing, else block with a Setup click-path.
- Inspect — read the queue's
QueueRoutingConfigId and its full QueueSobject list.
- Align (optional) — when
routing_config_dn is supplied, resolve its Id and PATCH Group.QueueRoutingConfigId if drifted.
- Re-query — confirm convergence and emit JSON.
Behavior
Discovery over naming. Any queue whose QueueSobject routes the target sObject is the queue for that sObject, regardless of its name. A name-based check would miss a queue like messagingqueue and either block or create a duplicate.
Creation is idempotent. Metadata deploy upserts by fullName, so --create-if-missing adopts/updates an existing same-named queue rather than making a second one. Creation ships the minimal safe set (doesSendEmailToMembers=false plus the sObject binding) and never deletes existing QueueSobject rows — other sObjects may be intentionally routed through the same queue.
Forced vs discovered QRC. For Case, the coordinator wants deterministic alignment to Case_Routing_Config, so the skill forces it. For other sObjects with no coordinator-owned QRC, the skill reports whatever the queue is already bound to (source: discovered) rather than forcing a name that may not exist. QRC Ids are resolved by DeveloperName at runtime — never hardcoded.
Ambiguity. If multiple distinct queues bind the same sObject, the skill does not guess — it blocks and asks the operator to disambiguate, unless a canonical name matches or an explicit queue_developer_name pins the exact queue.
PATCH hygiene. sf api request rest prints a beta warning on stderr; the skill captures stderr separately so it cannot corrupt JSON parsing, and it preserves the queue Id on PATCH (never delete + recreate) because downstream references point to it.
Output contract
A single JSON object with status ∈ created | reused | updated | blocked, plus sobject_type, developer_name, queue_created, id, queue_routing_config_id, queue_routing_config_developer_name, queue_routing_config_source (forced | discovered), queue_sobjects, a before snapshot, manual_actions, and blocking_issue.
created — no queue was bound and --create-if-missing created one (binding its QRC when supplied).
reused — a bound queue existed and, if a QRC was passed, already matched (no PATCH).
updated — a bound queue existed but the caller-supplied QRC was drifted; PATCH ran.
blocked — sObject absent, no bound queue and no --create-if-missing, supplied QRC missing, or the re-query showed state did not converge.
queue_created is true only when this run deployed a new queue; blocking_issue names the specific precondition that failed and manual_actions carries the click-path.
Limitations
- Only
Case, Incident, MessagingSession, VoiceCall — extend by adding a dispatcher branch.
- Never deletes a queue or its
QueueSobject rows, and never modifies queue members.
- Creation ships a minimal queue shape; exotic fields (
doesIncludeBosses, email routing address) are not set.
References