Enable Dev Hub & View Scratch Org Allocation Enable Dev Hub on a Salesforce org, verify whether it is already on, and see the org's scratch org allocation (Active and Daily limits, how many remain, and a pre-flight warning when close to the limit) — for the default org or a named org. The skill can also read the org's current DevHubSettings preferences , configure Dev Hub sub-preferences (packaging, org shape export, scratch org snapshots), list the active scratch orgs created from a Dev Hub, and list which orgs are authenticated when none is specified. Dev Hub is the org feature that lets yo…

\\t' read -r a u s; do printf \" %-24s %-32s %s\\n\" \"$a\" \"$u\" \"$s\"; done\n}\n\n# --- org resolution ------------------------------------------------------\nresolve_target() {\n [ -n \"$TARGET\" ] && return 0\n TARGET=\"$(sf config get target-org --json 2>/dev/null | jq -r '.result[0].value // empty')\"\n [ -n \"$TARGET\" ] && return 0\n TARGET=\"$(sf config get target-dev-hub --json 2>/dev/null | jq -r '.result[0].value // empty')\"\n [ -n \"$TARGET\" ] && return 0\n echo \"No org specified and no default target-org / target-dev-hub is set.\" >&2\n echo >&2\n if [ \"$OUTPUT\" != \"json\" ]; then\n list_orgs >&2 || true\n echo >&2\n fi\n echo \"Pass an org alias/username, or set a default:\" >&2\n echo \" sf org login web --alias \u003cmy-alias> # authenticate an org\" >&2\n echo \" sf config set target-org \u003cmy-alias> # make it the default\" >&2\n exit 2\n}\n\n# Render one dynamic value as a safe, copy-pasteable shell argument.\nshell_quote() {\n printf \"'%s'\" \"$(printf '%s' \"$1\" | sed \"s/'/'\\\\\\\\''/g\")\"\n}\n\n# --- Dev Hub detection ---------------------------------------------------\n# Sets DEVHUB_STATE (+ SCRATCH_COUNT when enabled, or error fields on failure).\n# ScratchOrgInfo is queryable ONLY on a Dev Hub, so a clean COUNT == enabled and\n# INVALID_TYPE == not enabled; any other failure is treated as an auth/conn error.\ndetect_devhub() {\n local out rc\n out=\"$(sf data query --query \"SELECT COUNT() FROM ScratchOrgInfo\" \\\n --target-org \"$TARGET\" --json 2>/dev/null)\"\n rc=$?\n if [ \"$rc\" -eq 0 ]; then\n DEVHUB_STATE=\"enabled\"\n SCRATCH_COUNT=\"$(printf '%s' \"$out\" | jq -r '.result.totalSize // empty')\"\n return 0\n fi\n local ename emsg\n ename=\"$(printf '%s' \"$out\" | jq -r '.name // empty' 2>/dev/null)\"\n emsg=\"$(printf '%s' \"$out\" | jq -r '.message // empty' 2>/dev/null | tr '\\t\\n' ' ')\"\n case \"$ename\" in\n INVALID_TYPE)\n DEVHUB_STATE=\"disabled\"; return 0 ;;\n *)\n DEVHUB_STATE=\"auth_error\"; DEVHUB_ERRNAME=\"$ename\"; DEVHUB_ERRMSG=\"$emsg\"; return 1 ;;\n esac\n}\n\n# --- org facts (edition / sandbox) ---------------------------------------\n# Best effort: populate ORG_EDITION, ORG_IS_SANDBOX. Never aborts.\norg_facts() {\n [ \"$ORG_FACTS_DONE\" -eq 1 ] && return 0\n ORG_FACTS_DONE=1\n local out\n out=\"$(sf data query --query \"SELECT OrganizationType, IsSandbox FROM Organization\" \\\n --target-org \"$TARGET\" --json 2>/dev/null)\" || return 0\n ORG_EDITION=\"$(printf '%s' \"$out\" | jq -r '.result.records[0].OrganizationType // empty' 2>/dev/null)\"\n # Use an explicit null-check rather than `// empty`: IsSandbox is a boolean, and\n # `false // empty` would drop a legitimate `false`, reporting a non-sandbox org\n # as \"unknown\" (isSandbox:null) instead of false.\n ORG_IS_SANDBOX=\"$(printf '%s' \"$out\" | jq -r '(.result.records[0].IsSandbox) as $s | if $s==null then empty else ($s|tostring) end' 2>/dev/null)\"\n return 0\n}\n\n# --- DevHubSettings preferences read -------------------------------------\n# Reads the current DevHubSettings via the Tooling API and echoes TSV rows\n# \"key\u003cTAB>true|false\" for each enable* preference. Returns non-zero on failure.\nread_devhub_settings() {\n local out\n out=\"$(sf api request rest \"/services/data/v${SETTINGS_API_VERSION}/tooling/sobjects/DevHubSettings/DevHub\" \\\n --target-org \"$TARGET\" --json 2>/dev/null)\" || return 1\n # `sf api request rest --json` returns the raw REST body; be robust to a\n # possible {result:{...}} wrapper too.\n printf '%s' \"$out\" | jq -r '\n (.Metadata // .result.Metadata // {})\n | to_entries[]? | select(.key|startswith(\"enable\"))\n | [.key, (.value|tostring)] | @tsv' 2>/dev/null\n}\n\nrender_settings() {\n local rows\n rows=\"$(read_devhub_settings)\"\n if [ -z \"$rows\" ]; then\n if [ \"$OUTPUT\" = \"json\" ]; then\n jq -n --arg org \"$TARGET\" '{org:$org, settings:{}, note:\"Could not read DevHubSettings (Dev Hub may be off, or you lack access).\"}'\n else\n echo \"Could not read DevHubSettings for '$TARGET' — Dev Hub may be off, or you may lack access.\" >&2\n fi\n return 1\n fi\n if [ \"$OUTPUT\" = \"json\" ]; then\n printf '%s\\n' \"$rows\" | jq -R -s --arg org \"$TARGET\" '\n {org:$org,\n settings:( [ split(\"\\n\")[] | select(length>0) | split(\"\\t\") | {(.[0]): (.[1]==\"true\")} ] | add // {} )}'\n return 0\n fi\n echo \"DevHub preferences for '$TARGET':\"\n printf '%s\\n' \"$rows\" | while IFS=

Enable Dev Hub & View Scratch Org Allocation Enable Dev Hub on a Salesforce org, verify whether it is already on, and see the org's scratch org allocation (Active and Daily limits, how many remain, and a pre-flight warning when close to the limit) — for the default org or a named org. The skill can also read the org's current DevHubSettings preferences , configure Dev Hub sub-preferences (packaging, org shape export, scratch org snapshots), list the active scratch orgs created from a Dev Hub, and list which orgs are authenticated when none is specified. Dev Hub is the org feature that lets yo…

\\t' read -r k v; do\n [ -n \"$k\" ] || continue\n if [ \"$v\" = \"true\" ]; then printf \" %-34s ON\\n\" \"$k\"; else printf \" %-34s OFF\\n\" \"$k\"; fi\n done\n}\n\n# Echoes TSV rows \"name\u003cTAB>remaining\u003cTAB>max\" for the two scratch org limits,\n# or nothing if the org could not be queried.\nallocation_rows() {\n local out\n out=\"$(sf org list limits --target-org \"$TARGET\" --json 2>/dev/null)\" || return 1\n printf '%s' \"$out\" | jq -r '\n .result[]?\n | select(.name==\"ActiveScratchOrgs\" or .name==\"DailyScratchOrgs\")\n | [.name, (.remaining|tostring), (.max|tostring)] | @tsv'\n}\n\n# Integer percentage used = (max-rem)*100/max, or empty when max is empty/0.\npct_used() {\n local max=\"$1\" rem=\"$2\"\n { [ -n \"$max\" ] && [ \"$max\" -gt 0 ] 2>/dev/null; } || { echo \"\"; return; }\n echo $(( (max - rem) * 100 / max ))\n}\n\n# Resolve the org instance URL for the Setup deep link (best effort).\nresolve_instance_url() {\n [ -n \"$INSTANCE_URL\" ] && return 0\n INSTANCE_URL=\"$(sf org display --target-org \"$TARGET\" --json 2>/dev/null \\\n | jq -r '.result.instanceUrl // empty')\"\n}\n\n# --- auth error reporting ------------------------------------------------\n# Guidance only: print the exact login command to run. Never logs in.\nprint_auth_error() {\n if [ \"$OUTPUT\" = \"json\" ]; then\n jq -n --arg org \"$TARGET\" --arg name \"$DEVHUB_ERRNAME\" --arg msg \"$DEVHUB_ERRMSG\" \\\n '{org:$org, devHubEnabled:null, status:\"auth_error\", error:{name:$name, message:$msg}}'\n return\n fi\n printf \" %-30s could not query org (%s)\\n\" \"$TARGET\" \"${DEVHUB_ERRNAME:-error}\"\n [ -n \"$DEVHUB_ERRMSG\" ] && printf \" %-30s (%s)\\n\" \"\" \"$DEVHUB_ERRMSG\"\n echo\n echo \" This org is not authenticated (or the session expired). Authentication is\"\n echo \" a precondition for this skill — run one of these yourself, then re-run:\"\n echo \" sf org login web --alias $(shell_quote \"$TARGET\") # prod / DE / trial\"\n echo \" sf org login web --alias \u003cmy-alias> --instance-url https://MYDOMAIN.my.salesforce.com # sandbox / My Domain\"\n echo \" List existing logins with: sf org list\"\n}\n\n# --- Setup UI fallback text ----------------------------------------------\nprint_ui_fallback() {\n resolve_instance_url\n echo \" Manual alternative (Setup UI):\"\n echo \" 1. Log in as a System Administrator.\"\n echo \" 2. Setup > Quick Find > \\\"Dev Hub\\\" > Dev Hub > turn Enable Dev Hub On.\"\n if [ -n \"$INSTANCE_URL\" ]; then\n echo \" Open it directly: sf org open --path \\\"lightning/setup/DevHub/home\\\" --target-org \\\"$TARGET\\\"\"\n fi\n}\n\n# --- allocation rendering ------------------------------------------------\nrender_allocation() {\n local rows a_max a_rem d_max d_rem a_pct d_pct\n rows=\"$(allocation_rows)\" || { echo \"Could not read org limits for '$TARGET'.\" >&2; return 1; }\n a_rem=\"$(printf '%s\\n' \"$rows\" | awk -F'\\t' '$1==\"ActiveScratchOrgs\"{print $2}')\"\n a_max=\"$(printf '%s\\n' \"$rows\" | awk -F'\\t' '$1==\"ActiveScratchOrgs\"{print $3}')\"\n d_rem=\"$(printf '%s\\n' \"$rows\" | awk -F'\\t' '$1==\"DailyScratchOrgs\"{print $2}')\"\n d_max=\"$(printf '%s\\n' \"$rows\" | awk -F'\\t' '$1==\"DailyScratchOrgs\"{print $3}')\"\n a_pct=\"$(pct_used \"$a_max\" \"$a_rem\")\"\n d_pct=\"$(pct_used \"$d_max\" \"$d_rem\")\"\n\n if [ \"$OUTPUT\" = \"json\" ]; then\n local warns=()\n if [ -n \"$a_max\" ] && [ \"$a_max\" -gt 0 ] 2>/dev/null && [ \"$a_rem\" -lt 2 ] 2>/dev/null; then\n warns+=(\"only $a_rem active scratch org(s) remaining\")\n fi\n { [ -n \"$a_pct\" ] && [ \"$a_pct\" -gt 80 ] 2>/dev/null; } && warns+=(\"Active scratch org usage at ${a_pct}%\")\n { [ -n \"$d_pct\" ] && [ \"$d_pct\" -gt 80 ] 2>/dev/null; } && warns+=(\"Daily scratch org usage at ${d_pct}%\")\n local warn_json=\"[]\"\n if [ \"${#warns[@]}\" -gt 0 ]; then\n warn_json=\"$(printf '%s\\n' \"${warns[@]}\" | jq -R . | jq -s .)\"\n fi\n jq -n --arg org \"$TARGET\" \\\n --argjson am \"${a_max:-null}\" --argjson ar \"${a_rem:-null}\" --argjson ap \"${a_pct:-null}\" \\\n --argjson dm \"${d_max:-null}\" --argjson dr \"${d_rem:-null}\" --argjson dp \"${d_pct:-null}\" \\\n --argjson warnings \"$warn_json\" '\n {org:$org,\n allocation:{\n activeScratchOrgs:{max:$am, remaining:$ar, used:(if $am!=null and $ar!=null then ($am-$ar) else null end), usedPct:$ap},\n dailyScratchOrgs:{max:$dm, remaining:$dr, used:(if $dm!=null and $dr!=null then ($dm-$dr) else null end), usedPct:$dp}\n },\n warnings:$warnings}'\n return 0\n fi\n\n echo \"Scratch org allocation for '$TARGET':\"\n if [ -z \"$a_max\" ] && [ -z \"$d_max\" ]; then\n echo \" No scratch org limits reported (org may not be a Dev Hub, or could not be queried).\"\n return 0\n fi\n printf \" %-22s %10s %10s %10s\\n\" \"Limit\" \"Used\" \"Remaining\" \"Max\"\n [ -n \"$a_max\" ] && printf \" %-22s %10s %10s %10s\\n\" \"Active scratch orgs\" \"$(( a_max - a_rem ))\" \"$a_rem\" \"$a_max\"\n [ -n \"$d_max\" ] && printf \" %-22s %10s %10s %10s\\n\" \"Daily scratch orgs\" \"$(( d_max - d_rem ))\" \"$d_rem\" \"$d_max\"\n # Pre-flight warnings.\n if [ -n \"$a_max\" ] && [ \"$a_max\" -gt 0 ] 2>/dev/null && [ \"$a_rem\" -lt 2 ] 2>/dev/null; then\n echo \" WARN: only $a_rem active scratch org(s) remaining.\"\n fi\n { [ -n \"$a_pct\" ] && [ \"$a_pct\" -gt 80 ] 2>/dev/null; } && echo \" NOTE: Active scratch org usage at ${a_pct}% ($(( a_max - a_rem ))/$a_max).\"\n { [ -n \"$d_pct\" ] && [ \"$d_pct\" -gt 80 ] 2>/dev/null; } && echo \" NOTE: Daily scratch org usage at ${d_pct}% ($(( d_max - d_rem ))/$d_max).\"\n echo\n echo \" Active = orgs alive right now; Daily = successful creations in a rolling 24h window.\"\n echo \" Allocation is set by the Dev Hub's edition (e.g. Developer/trial 3 & 6;\"\n echo \" Enterprise 40 & 80; Unlimited/Performance 100 & 200) plus any purchased add-on.\"\n}\n\n# --- active scratch org listing ------------------------------------------\nrender_list() {\n local out rc\n out=\"$(sf data query --target-org \"$TARGET\" \\\n --query \"SELECT SignupUsername, OrgName, Edition, ExpirationDate, ScratchOrg FROM ActiveScratchOrg ORDER BY ExpirationDate NULLS LAST\" \\\n --json 2>/dev/null)\"\n rc=$?\n if [ \"$rc\" -ne 0 ]; then\n if [ \"$OUTPUT\" = \"json\" ]; then echo \"[]\"; else\n echo \"Could not list scratch orgs for '$TARGET' — is Dev Hub enabled and the org authenticated?\" >&2\n fi\n return 1\n fi\n if [ \"$OUTPUT\" = \"json\" ]; then\n printf '%s' \"$out\" | jq '[.result.records[]? | {signupUsername:.SignupUsername, orgName:.OrgName, edition:.Edition, expirationDate:.ExpirationDate, scratchOrgId:.ScratchOrg}]'\n return 0\n fi\n local total\n total=\"$(printf '%s' \"$out\" | jq -r '.result.totalSize // 0')\"\n echo \"Active scratch orgs on Dev Hub '$TARGET': $total\"\n if [ \"$total\" = \"0\" ]; then\n echo \" (none active)\"\n return 0\n fi\n printf '%s' \"$out\" | jq -r '.result.records[]?\n | \" \\(.SignupUsername // \"?\") edition=\\(.Edition // \"?\") expires=\\(.ExpirationDate // \"?\") id=\\(.ScratchOrg // \"?\")\"'\n}\n\n# --- deploy (enable / configure sub-prefs) -------------------------------\nDEPLOY_TEMP_DIR=\"\"\ncleanup_deploy_temp() {\n [ -n \"$DEPLOY_TEMP_DIR\" ] && rm -rf -- \"$DEPLOY_TEMP_DIR\"\n}\n\nrender_deploy() {\n # Enabling Dev Hub cannot happen on a sandbox. When actually applying an\n # enablement, verify eligibility first and refuse before touching the org.\n if [ \"$ENABLING\" -eq 1 ] && [ \"$APPLY\" -eq 1 ]; then\n org_facts\n if [ \"$ORG_IS_SANDBOX\" = \"true\" ]; then\n if [ \"$OUTPUT\" = \"json\" ]; then\n jq -n --arg org \"$TARGET\" '{applied:false, enabling:true, success:false, message:\"Refused: Dev Hub cannot be enabled on a sandbox. Use a production, Developer Edition, or trial org.\"}'\n else\n echo \"Refused — '$TARGET' is a sandbox, and Dev Hub cannot be enabled on a sandbox.\"\n echo \" Dev Hub must be a production/business org (or a Developer Edition / trial org).\"\n echo\n print_ui_fallback\n fi\n return 1\n fi\n fi\n\n # Sub-prefs (packaging, snapshots, shape) require Dev Hub to be on. If the\n # user is configuring one without also enabling, and Dev Hub is off, warn.\n if [ \"$ENABLING\" -eq 0 ] && [ \"$DEVHUB_STATE\" = \"disabled\" ] && [ \"$OUTPUT\" != \"json\" ]; then\n echo \"Note: Dev Hub is not enabled on '$TARGET'. Sub-preferences require Dev Hub — add --enable, or run --enable first.\" >&2\n echo >&2\n fi\n\n local tmp\n tmp=\"$(mktemp -d 2>/dev/null)\" || die \"Could not create a temporary directory for the deploy.\"\n DEPLOY_TEMP_DIR=\"$tmp\"\n trap cleanup_deploy_temp EXIT\n\n mkdir -p \"$tmp/force-app/main/default/settings\"\n cat > \"$tmp/sfdx-project.json\" \u003c\u003cJSON\n{ \"packageDirectories\": [{ \"path\": \"force-app\", \"default\": true }], \"sourceApiVersion\": \"$SETTINGS_API_VERSION\" }\nJSON\n {\n echo '\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?>'\n echo '\u003cDevHubSettings xmlns=\"http://soap.sforce.com/2006/04/metadata\">'\n local kv key val\n for kv in \"${PREFS[@]}\"; do\n key=\"${kv%%=*}\"; val=\"${kv#*=}\"\n echo \" \u003c$key>$val\u003c/$key>\"\n done\n echo '\u003c/DevHubSettings>'\n } > \"$tmp/force-app/main/default/settings/DevHub.settings-meta.xml\"\n\n local dry=\"--dry-run\" action=\"Validating (dry run)\"\n if [ \"$APPLY\" -eq 1 ]; then dry=\"\"; action=\"Deploying\"; fi\n\n if [ \"$OUTPUT\" != \"json\" ]; then\n if [ \"$ENABLING\" -eq 1 ]; then\n echo \"$action Dev Hub enablement on '$TARGET':\"\n else\n echo \"$action DevHubSettings on '$TARGET':\"\n fi\n local kv2; for kv2 in \"${PREFS[@]}\"; do echo \" $kv2\"; done\n if [ \"$ENABLING\" -eq 1 ] && [ \"$APPLY\" -eq 1 ]; then\n echo\n echo \" WARNING: enabling Dev Hub is IRREVERSIBLE — it cannot be turned off.\"\n echo \" Requires ModifyAllData or ModifyMetadata (System Administrator).\"\n echo \" Not allowed in a sandbox, or in an org with a registered namespace.\"\n fi\n echo\n fi\n\n local out ok verified=\"unknown\"\n out=\"$( cd \"$tmp\" && sf project deploy start $dry --source-dir force-app \\\n --target-org \"$TARGET\" --json 2>/dev/null )\"\n ok=\"$(printf '%s' \"$out\" | jq -r '.result.success // false')\"\n\n # On a real, successful enablement, re-detect so we report verified state.\n if [ \"$APPLY\" -eq 1 ] && [ \"$ENABLING\" -eq 1 ] && [ \"$ok\" = \"true\" ]; then\n detect_devhub >/dev/null 2>&1\n verified=\"$DEVHUB_STATE\"\n fi\n\n if [ \"$OUTPUT\" = \"json\" ]; then\n printf '%s' \"$out\" | jq \\\n --arg applied \"$([ \"$APPLY\" -eq 1 ] && echo true || echo false)\" \\\n --arg enabling \"$([ \"$ENABLING\" -eq 1 ] && echo true || echo false)\" \\\n --arg verified \"$verified\" '\n {applied:($applied==\"true\"),\n enabling:($enabling==\"true\"),\n success:(.result.success // false),\n checkOnly:(.result.checkOnly // null),\n devHubVerifiedState:(if $verified==\"unknown\" then null else $verified end),\n failures:[.result.details.componentFailures[]? | {fullName, problem}],\n message:(.message // null)}'\n [ \"$ok\" = \"true\" ] && return 0 || return 1\n fi\n\n if [ \"$ok\" = \"true\" ]; then\n if [ \"$APPLY\" -eq 1 ]; then\n if [ \"$ENABLING\" -eq 1 ]; then\n echo \" Success — Dev Hub enabled (deploy succeeded).\"\n if [ \"$verified\" = \"enabled\" ]; then\n echo \" Verified: ScratchOrgInfo is now queryable.\"\n else\n echo \" Note: provisioning may take a moment; re-run 'devhub.sh \\\"$TARGET\\\"' to confirm.\"\n fi\n echo \" Set it as your default Dev Hub: sf config set target-dev-hub \\\"$TARGET\\\"\"\n else\n echo \" Success — Dev Hub preferences deployed.\"\n fi\n else\n echo \" Dry run passed — valid. Re-run with --apply to deploy.\"\n [ \"$ENABLING\" -eq 1 ] && echo \" (Enabling Dev Hub is irreversible; --apply commits it.)\"\n fi\n return 0\n fi\n\n echo \" Deployment did not succeed:\"\n printf '%s' \"$out\" | jq -r '.result.details.componentFailures[]? | \" - \\(.fullName): \\(.problem)\"' 2>/dev/null\n printf '%s' \"$out\" | jq -r '.message // empty' 2>/dev/null | sed 's/^/ /'\n # Common cause: missing perms. Offer the UI route.\n if printf '%s' \"$out\" | grep -qi \"INSUFFICIENT_ACCESS\\|ModifyAllData\\|ModifyMetadata\"; then\n echo\n echo \" This looks like a permissions issue — the deploy needs ModifyAllData or ModifyMetadata.\"\n [ \"$ENABLING\" -eq 1 ] && print_ui_fallback\n fi\n return 1\n}\n\n# --- status (default) ----------------------------------------------------\nrender_status() {\n if [ \"$OUTPUT\" = \"json\" ]; then\n local rows a_max a_rem d_max d_rem\n rows=\"$(allocation_rows 2>/dev/null || true)\"\n a_rem=\"$(printf '%s\\n' \"$rows\" | awk -F'\\t' '$1==\"ActiveScratchOrgs\"{print $2}')\"\n a_max=\"$(printf '%s\\n' \"$rows\" | awk -F'\\t' '$1==\"ActiveScratchOrgs\"{print $3}')\"\n d_rem=\"$(printf '%s\\n' \"$rows\" | awk -F'\\t' '$1==\"DailyScratchOrgs\"{print $2}')\"\n d_max=\"$(printf '%s\\n' \"$rows\" | awk -F'\\t' '$1==\"DailyScratchOrgs\"{print $3}')\"\n org_facts\n jq -n --arg org \"$TARGET\" --arg state \"$DEVHUB_STATE\" \\\n --argjson count \"${SCRATCH_COUNT:-null}\" \\\n --arg edition \"${ORG_EDITION}\" --arg sandbox \"${ORG_IS_SANDBOX}\" \\\n --argjson am \"${a_max:-null}\" --argjson ar \"${a_rem:-null}\" \\\n --argjson dm \"${d_max:-null}\" --argjson dr \"${d_rem:-null}\" '\n {org:$org,\n devHubEnabled:($state==\"enabled\"),\n status:$state,\n edition:(if $edition==\"\" then null else $edition end),\n isSandbox:(if $sandbox==\"\" then null else ($sandbox==\"true\") end),\n activeScratchOrgSignups:$count,\n allocation:{\n activeScratchOrgs:{max:$am, remaining:$ar},\n dailyScratchOrgs:{max:$dm, remaining:$dr}\n }}'\n return 0\n fi\n\n org_facts\n echo \"Dev Hub status for '$TARGET':\"\n if [ \"$DEVHUB_STATE\" = \"enabled\" ]; then\n echo \" Dev Hub: ENABLED (ScratchOrgInfo is queryable)\"\n echo \" Detection: ScratchOrgInfo is queryable only when Dev Hub is on. A successful count means ENABLED. An INVALID_TYPE error means NOT ENABLED. Scratch org limits are not used as the enablement check.\"\n [ -n \"$ORG_EDITION\" ] && echo \" Edition: $ORG_EDITION\"\n [ \"$ORG_IS_SANDBOX\" = \"true\" ] && echo \" (Sandbox org)\"\n [ -n \"$SCRATCH_COUNT\" ] && echo \" Scratch org signup records: $SCRATCH_COUNT\"\n # Best-effort current-preference summary; never let it break status.\n local prefs\n prefs=\"$(read_devhub_settings 2>/dev/null | awk -F'\\t' '$2==\"true\"{printf \"%s \", $1}')\"\n [ -n \"$prefs\" ] && echo \" Enabled preferences: $prefs\"\n echo\n render_allocation\n else\n echo \" Dev Hub: NOT ENABLED\"\n echo \" Detection: ScratchOrgInfo is queryable only when Dev Hub is on. A successful count means ENABLED. An INVALID_TYPE error means NOT ENABLED. Scratch org limits are not used, because they are reported even when Dev Hub is off.\"\n [ -n \"$ORG_EDITION\" ] && echo \" Edition: $ORG_EDITION\"\n [ \"$ORG_IS_SANDBOX\" = \"true\" ] && echo \" (Sandbox org — cannot host Dev Hub)\"\n echo\n echo \" Scratch org allocation, Dev Hub preferences, and the scratch org list are not available until Dev Hub is enabled. An empty allocation or a failed exit from those modes means Dev Hub is off, not that the org is unauthenticated.\"\n echo\n if [ \"$ORG_IS_SANDBOX\" = \"true\" ]; then\n echo \" This is a sandbox — Dev Hub cannot be enabled here. Use a production,\"\n echo \" Developer Edition, or trial org instead.\"\n echo\n else\n echo \" Enable it (deploys $DEVHUB_SWITCH=true; irreversible):\"\n echo \" devhub.sh \\\"$TARGET\\\" --enable # validate first (dry run)\"\n echo \" devhub.sh \\\"$TARGET\\\" --enable --apply # actually enable\"\n echo \" Requires ModifyAllData or ModifyMetadata (System Administrator);\"\n echo \" not allowed in a sandbox or an org with a registered namespace.\"\n echo\n fi\n print_ui_fallback\n fi\n}\n\n# --- dispatch ------------------------------------------------------------\n# --list-orgs needs no target and no auth check — handle it first.\nif [ \"$MODE\" = \"listorgs\" ]; then\n list_orgs; exit $?\nfi\n\nresolve_target\n\n# status/deploy/settings need the enablement state; allocation and list query\n# the org directly and surface their own errors.\ncase \"$MODE\" in\n status|deploy|settings)\n if ! detect_devhub && [ \"$DEVHUB_STATE\" = \"auth_error\" ]; then\n print_auth_error\n exit 1\n fi\n ;;\nesac\n\n# --show-settings requires Dev Hub to be on.\nif [ \"$MODE\" = \"settings\" ] && [ \"$DEVHUB_STATE\" != \"enabled\" ]; then\n if [ \"$OUTPUT\" = \"json\" ]; then\n jq -n --arg org \"$TARGET\" '{org:$org, settings:{}, note:\"Dev Hub is not enabled; there are no DevHubSettings to read.\"}'\n else\n echo \"Dev Hub is not enabled on '$TARGET' — there are no DevHubSettings to read.\" >&2\n echo \" Packaging (enablePackaging2), org shape export (enableShapeExportPref), and scratch org snapshots (enableScratchOrgSnapshotPref) cannot be read until Dev Hub is enabled. Do not guess ON or OFF.\" >&2\n echo \" Validate with a dry run first. Enabling is irreversible and needs a System Administrator (ModifyAllData or ModifyMetadata).\" >&2\n echo \" Enable it first with: devhub.sh \\\"$TARGET\\\" --enable --apply\" >&2\n fi\n exit 1\nfi\n\nrc=0\ncase \"$MODE\" in\n status) render_status || rc=1 ;;\n allocation) render_allocation || rc=1 ;;\n settings) render_settings || rc=1 ;;\n list) render_list || rc=1 ;;\n deploy) render_deploy || rc=1 ;;\nesac\n\n# CI gate: exit 3 if Dev Hub is not enabled (takes precedence for alerting).\nif [ \"$FAIL_IF_DISABLED\" -eq 1 ]; then\n [ -z \"$DEVHUB_STATE\" ] && detect_devhub >/dev/null 2>&1\n if [ \"$DEVHUB_STATE\" != \"enabled\" ]; then\n echo \"ALERT: Dev Hub is not enabled on '$TARGET'.\" >&2\n exit 3\n fi\nfi\n\nexit \"$rc\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":35381,"content_sha256":"8a2d8b05f902c321daed06d4a1278d1755e2c069f80b5ff1fc15ce777d4ce47d"},{"filename":"scripts/test-devhub.sh","content":"#!/usr/bin/env bash\nset -uo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"$0\")\" && pwd)\"\nSCRIPT=\"$SCRIPT_DIR/devhub.sh\"\nWORK_DIR=\"$(mktemp -d)\"\nSTUB_DIR=\"$WORK_DIR/bin\"\nLOG_FILE=\"$WORK_DIR/sf.log\"\nMARKER=\"$WORK_DIR/trap-injection\"\nmkdir -p \"$STUB_DIR\"\ntrap 'rm -rf -- \"$WORK_DIR\"' EXIT\n\ncat > \"$STUB_DIR/sf\" \u003c\u003c'EOF'\n#!/usr/bin/env bash\nprintf '%s\\n' \"$*\" >> \"$SF_STUB_LOG\"\n\ncase \"$*\" in\n \"config get target-org --json\")\n if [ \"${SF_TEST_NO_DEFAULT:-0}\" = \"1\" ]; then\n printf '%s\\n' '{\"status\":0,\"result\":[]}'\n else\n printf '%s\\n' '{\"status\":0,\"result\":[{\"value\":\"default-org\"}]}'\n fi\n ;;\n \"config get target-dev-hub --json\")\n if [ \"${SF_TEST_NO_DEFAULT:-0}\" = \"1\" ]; then\n printf '%s\\n' '{\"status\":0,\"result\":[]}'\n else\n printf '%s\\n' '{\"status\":0,\"result\":[{\"value\":\"default-devhub\"}]}'\n fi\n ;;\n \"org list --json\")\n if [ \"${SF_TEST_HANG:-0}\" = \"1\" ]; then\n sleep 60\n fi\n if [ \"${SF_TEST_NO_ORGS:-0}\" = \"1\" ]; then\n printf '%s\\n' '{\"status\":0,\"result\":{\"nonScratchOrgs\":[],\"scratchOrgs\":[]}}'\n else\n printf '%s\\n' '{\"status\":0,\"result\":{\"nonScratchOrgs\":[{\"alias\":\"my-org\",\"username\":\"[email protected]\",\"connectedStatus\":\"Connected\",\"isDefaultUsername\":true}],\"scratchOrgs\":[]}}'\n fi\n ;;\n \"data query --query SELECT COUNT() FROM ScratchOrgInfo\"*)\n if [ \"${SF_TEST_DEVHUB_ENABLED:-0}\" = \"1\" ]; then\n printf '%s\\n' '{\"status\":0,\"result\":{\"totalSize\":0}}'\n else\n printf '%s\\n' '{\"status\":1,\"name\":\"INVALID_TYPE\",\"message\":\"ScratchOrgInfo unavailable\"}'\n exit 1\n fi\n ;;\n \"data query --query SELECT OrganizationType, IsSandbox FROM Organization\"*)\n printf '%s\\n' \"{\\\"status\\\":0,\\\"result\\\":{\\\"records\\\":[{\\\"OrganizationType\\\":\\\"Developer Edition\\\",\\\"IsSandbox\\\":${SF_TEST_SANDBOX:-false}}]}}\"\n ;;\n \"api request rest /services/data/\"*\"/tooling/sobjects/DevHubSettings/DevHub\"*)\n printf '%s\\n' '{\"Id\":\"DevHub\",\"FullName\":\"DevHub\",\"Metadata\":{\"enableScratchOrgManagementPref\":true,\"enablePackaging2\":false,\"enableScratchOrgSnapshotPref\":true,\"enableShapeExportPref\":false}}'\n ;;\n \"org list limits\"*)\n if [ \"${SF_TEST_LIMITS_FAIL:-0}\" = \"1\" ]; then\n printf '%s\\n' '{\"status\":1,\"message\":\"limits unavailable\"}'\n exit 1\n fi\n printf '%s\\n' \"{\\\"status\\\":0,\\\"result\\\":[{\\\"name\\\":\\\"ActiveScratchOrgs\\\",\\\"remaining\\\":${SF_TEST_ACTIVE_REM:-3},\\\"max\\\":${SF_TEST_ACTIVE_MAX:-3}},{\\\"name\\\":\\\"DailyScratchOrgs\\\",\\\"remaining\\\":${SF_TEST_DAILY_REM:-6},\\\"max\\\":${SF_TEST_DAILY_MAX:-6}}]}\"\n ;;\n \"org display\"*)\n printf '%s\\n' '{\"status\":0,\"result\":{\"id\":\"00D000000000001\",\"username\":\"[email protected]\",\"instanceUrl\":\"https://example.my.salesforce.com\"}}'\n ;;\n \"project deploy start\"*)\n printf '%s\\n' '{\"status\":0,\"result\":{\"success\":true,\"checkOnly\":true}}'\n ;;\n *)\n printf '%s\\n' '{\"status\":1,\"message\":\"unexpected sf invocation\"}'\n exit 1\n ;;\nesac\nEOF\nchmod +x \"$STUB_DIR/sf\"\n\nexport PATH=\"$STUB_DIR:$PATH\"\nexport SF_STUB_LOG=\"$LOG_FILE\"\n\npass=0\nfail=0\n\ncheck() {\n local name=\"$1\" expected_rc=\"$2\" expected_text=\"$3\"\n shift 3\n local output rc\n : > \"$LOG_FILE\"\n output=\"$(\"$@\" 2>&1)\"\n rc=$?\n if [ \"$rc\" -eq \"$expected_rc\" ] && { [ \"$expected_text\" = \"-\" ] || printf '%s' \"$output\" | grep -Fq -- \"$expected_text\"; }; then\n pass=$((pass + 1))\n printf 'PASS: %s\\n' \"$name\"\n else\n fail=$((fail + 1))\n printf 'FAIL: %s (exit %s, expected %s)\\n%s\\n' \"$name\" \"$rc\" \"$expected_rc\" \"$output\"\n fi\n}\n\ncheck \"reject disabling the master switch\" 2 \"cannot be set to false\" \\\n \"$SCRIPT\" explicit-org --pref enableScratchOrgManagementPref=false\n\ncheck \"warn for scratch-management apply\" 0 \"IRREVERSIBLE\" \\\n env SF_TEST_DEVHUB_ENABLED=1 \"$SCRIPT\" explicit-org --scratch-management --apply\n\ncheck \"propagate status allocation failure\" 1 \"Could not read org limits\" \\\n env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_LIMITS_FAIL=1 \"$SCRIPT\" explicit-org\n\ncheck \"require explicit target for apply\" 2 \"explicit org\" \\\n \"$SCRIPT\" --enable --apply\n\n# --- new: read current DevHubSettings preferences ---\ncheck \"show-settings renders master pref ON\" 0 \"enableScratchOrgManagementPref\" \\\n env SF_TEST_DEVHUB_ENABLED=1 \"$SCRIPT\" explicit-org --show-settings\ncheck \"show-settings renders packaging OFF\" 0 \"enablePackaging2 OFF\" \\\n env SF_TEST_DEVHUB_ENABLED=1 \"$SCRIPT\" explicit-org --show-settings\n\n# --- new: pre-flight allocation thresholds ---\ncheck \"threshold WARN under 2 remaining\" 0 \"WARN\" \\\n env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_ACTIVE_REM=1 SF_TEST_ACTIVE_MAX=3 \"$SCRIPT\" explicit-org --allocation\ncheck \"threshold NOTE above 80 percent\" 0 \"usage at\" \\\n env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_ACTIVE_REM=0 SF_TEST_ACTIVE_MAX=3 \"$SCRIPT\" explicit-org --allocation\n\n# --- new: sandbox refuses enablement, before any deploy ---\n: > \"$LOG_FILE\"\nsandbox_out=\"$(env SF_TEST_DEVHUB_ENABLED=0 SF_TEST_SANDBOX=true \"$SCRIPT\" explicit-org --scratch-management --apply 2>&1)\"\nsandbox_rc=$?\nif [ \"$sandbox_rc\" -eq 1 ] && printf '%s' \"$sandbox_out\" | grep -qi \"sandbox\" && ! grep -Fq \"project deploy start\" \"$LOG_FILE\"; then\n pass=$((pass + 1)); printf 'PASS: sandbox refuses enablement without deploying\\n'\nelse\n fail=$((fail + 1)); printf 'FAIL: sandbox refuses enablement (exit %s)\\n%s\\n' \"$sandbox_rc\" \"$sandbox_out\"\nfi\n\n# --- new: org discovery when no default is set ---\ncheck \"org discovery lists authenticated orgs\" 2 \"my-org\" \\\n env SF_TEST_NO_DEFAULT=1 SF_TEST_DEVHUB_ENABLED=1 \"$SCRIPT\"\n\ncheck \"list-orgs mode lists authenticated orgs\" 0 \"my-org\" \\\n \"$SCRIPT\" --list-orgs\n\n# --- removed: login flags are now unknown options ---\ncheck \"login flag rejected\" 2 \"Unknown option\" \\\n \"$SCRIPT\" explicit-org --login\ncheck \"instance-url flag rejected\" 2 \"Unknown option\" \\\n \"$SCRIPT\" explicit-org --instance-url https://x.my.salesforce.com\n\n# --- new: show-settings refuses when Dev Hub is OFF ---\ncheck \"show-settings refuses when Dev Hub off\" 1 \"no DevHubSettings to read\" \\\n env SF_TEST_DEVHUB_ENABLED=0 \"$SCRIPT\" explicit-org --show-settings\n\n# --- new: daily-limit NOTE threshold (only active was covered before) ---\ncheck \"threshold NOTE daily above 80 percent\" 0 \"Daily scratch org usage at\" \\\n env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_DAILY_REM=1 SF_TEST_DAILY_MAX=6 \"$SCRIPT\" explicit-org --allocation\n\n# --- new: list-orgs with no authenticated orgs ---\ncheck \"list-orgs reports none authenticated\" 0 \"No orgs are authenticated\" \\\n env SF_TEST_NO_ORGS=1 \"$SCRIPT\" --list-orgs\n\n# A hung CLI must not hold the caller for the full stub sleep.\nhang_start=$(date +%s)\nhang_out=\"$(env SF_TEST_HANG=1 \"$SCRIPT\" --list-orgs 2>&1)\"\nhang_rc=$?\nhang_elapsed=$(( $(date +%s) - hang_start ))\nif [ \"$hang_rc\" -eq 1 ] && [ \"$hang_elapsed\" -lt 35 ] && printf '%s' \"$hang_out\" | grep -Fq \"Could not list authenticated orgs\"; then\n pass=$((pass + 1)); printf 'PASS: list-orgs bounds a hung sf org list (%ss)\\n' \"$hang_elapsed\"\nelse\n fail=$((fail + 1)); printf 'FAIL: list-orgs bounds a hung sf org list (exit %s, %ss)\\n%s\\n' \"$hang_rc\" \"$hang_elapsed\" \"$hang_out\"\nfi\n\n# --- new: JSON fidelity for the added fields ---\ncheck \"status JSON reports edition\" 0 \"\\\"edition\\\": \\\"Developer Edition\\\"\" \\\n env SF_TEST_DEVHUB_ENABLED=1 \"$SCRIPT\" explicit-org --json\ncheck \"status JSON reports isSandbox false (not null) for non-sandbox\" 0 \"\\\"isSandbox\\\": false\" \\\n env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_SANDBOX=false \"$SCRIPT\" explicit-org --json\ncheck \"status JSON reports isSandbox true for sandbox\" 0 \"\\\"isSandbox\\\": true\" \\\n env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_SANDBOX=true \"$SCRIPT\" explicit-org --json\ncheck \"allocation JSON emits warnings array near limit\" 0 \"\\\"warnings\\\"\" \\\n env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_ACTIVE_REM=1 SF_TEST_ACTIVE_MAX=3 \"$SCRIPT\" explicit-org --allocation --json\ncheck \"show-settings JSON emits settings map\" 0 \"enableScratchOrgSnapshotPref\" \\\n env SF_TEST_DEVHUB_ENABLED=1 \"$SCRIPT\" explicit-org --show-settings --json\ncheck \"list-orgs JSON emits normalized array\" 0 \"\\\"isDefault\\\"\" \\\n \"$SCRIPT\" --list-orgs --json\n\n# --- new: a not-enabled sandbox is flagged as ineligible in status ---\ncheck \"status flags sandbox as unable to host Dev Hub\" 0 \"cannot host Dev Hub\" \\\n env SF_TEST_DEVHUB_ENABLED=0 SF_TEST_SANDBOX=true \"$SCRIPT\" explicit-org\n\n# --- safety: cleanup trap treats TMPDIR content as data ---\nunsafe_tmp=\"$WORK_DIR/unsafe'; touch $MARKER; #\"\nmkdir -p \"$unsafe_tmp\"\ncheck \"cleanup trap does not execute TMPDIR content\" 0 \"Dry run passed\" \\\n env SF_TEST_DEVHUB_ENABLED=1 TMPDIR=\"$unsafe_tmp\" \"$SCRIPT\" explicit-org --packaging\nif [ -e \"$MARKER\" ]; then\n fail=$((fail + 1))\n printf 'FAIL: cleanup trap executed TMPDIR content\\n'\nelse\n pass=$((pass + 1))\n printf 'PASS: cleanup trap treated TMPDIR as data\\n'\nfi\n\nprintf '\\nRESULT: %s passed, %s failed\\n' \"$pass\" \"$fail\"\n[ \"$fail\" -eq 0 ]\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":8771,"content_sha256":"f827c969cbece1ea977703d9f622715feed945c9f68a9e43cd6ada951c5523b6"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Enable Dev Hub & View Scratch Org Allocation","type":"text"}]},{"type":"paragraph","content":[{"text":"Enable ","type":"text"},{"text":"Dev Hub","type":"text","marks":[{"type":"strong"}]},{"text":" on a Salesforce org, verify whether it is already on, and see the org's ","type":"text"},{"text":"scratch org allocation","type":"text","marks":[{"type":"strong"}]},{"text":" (Active and Daily limits, how many remain, and a pre-flight warning when close to the limit) — for the default org or a named org. The skill can also read the org's current ","type":"text"},{"text":"DevHubSettings preferences","type":"text","marks":[{"type":"strong"}]},{"text":", configure Dev Hub sub-preferences (packaging, org shape export, scratch org snapshots), list the active scratch orgs created from a Dev Hub, and list which orgs are authenticated when none is specified.","type":"text"}]},{"type":"paragraph","content":[{"text":"Dev Hub is the org feature that lets you ","type":"text"},{"text":"create and manage scratch orgs","type":"text","marks":[{"type":"strong"}]},{"text":" and ","type":"text"},{"text":"second-generation (2GP) / unlocked packages","type":"text","marks":[{"type":"strong"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to use","type":"text"}]},{"type":"paragraph","content":[{"text":"Trigger on requests like:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"Enable Dev Hub\" / \"Turn on Dev Hub\" / \"Set up this org for scratch orgs.\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"Is Dev Hub enabled on my org?\" / \"Check if Dev Hub is on.\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"How many scratch orgs can I create?\" / \"What's my scratch org allocation / limit?\" / \"How many scratch orgs do I have left?\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"Turn on packaging / 2GP / unlocked packages\" / \"Enable org shape export\" / \"Enable scratch org snapshots\" (Dev Hub sub-preferences).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"Which Dev Hub preferences are turned on?\" / \"Show my current DevHubSettings.\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"List the scratch orgs on my Dev Hub.\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"What orgs do I have authenticated?\" / \"I didn't pass an org — what's available?\"","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When NOT to use","type":"text"}]},{"type":"paragraph","content":[{"text":"Do ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" trigger this skill for:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Creating or deleting an individual scratch org","type":"text","marks":[{"type":"strong"}]},{"text":" — that is ","type":"text"},{"text":"sf org create scratch","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"sf org delete scratch","type":"text","marks":[{"type":"code_inline"}]},{"text":", a different workflow. This skill enables the ","type":"text"},{"text":"Dev Hub feature","type":"text","marks":[{"type":"em"}]},{"text":" and reports ","type":"text"},{"text":"allocation","type":"text","marks":[{"type":"em"}]},{"text":"; it does not create scratch orgs.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"How Dev Hub enablement is determined","type":"text"}]},{"type":"paragraph","content":[{"text":"The standard object ","type":"text"},{"text":"ScratchOrgInfo","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" is provisioned and becomes queryable ","type":"text"},{"text":"only when Dev Hub is enabled","type":"text","marks":[{"type":"strong"}]},{"text":". So a successful ","type":"text"},{"text":"SELECT COUNT() FROM ScratchOrgInfo","type":"text","marks":[{"type":"code_inline"}]},{"text":" means Dev Hub is ","type":"text"},{"text":"ON","type":"text","marks":[{"type":"strong"}]},{"text":"; an ","type":"text"},{"text":"INVALID_TYPE","type":"text","marks":[{"type":"code_inline"}]},{"text":" error means it is ","type":"text"},{"text":"OFF","type":"text","marks":[{"type":"strong"}]},{"text":". This is the reliable signal.","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"Do ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" infer enablement from ","type":"text"},{"text":"sf org list limits","type":"text","marks":[{"type":"code_inline"}]},{"text":" alone: it reports ","type":"text"},{"text":"ActiveScratchOrgs","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"DailyScratchOrgs","type":"text","marks":[{"type":"code_inline"}]},{"text":" rows even on orgs where Dev Hub is ","type":"text"},{"text":"off","type":"text","marks":[{"type":"strong"}]},{"text":", so limits show allocation but not enablement.","type":"text"}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"How enabling works (important)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"The Dev Hub master switch is the ","type":"text"},{"text":"deployable","type":"text","marks":[{"type":"strong"}]},{"text":" Metadata API field ","type":"text"},{"text":"DevHubSettings.enableScratchOrgManagementPref","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":". There is ","type":"text"},{"text":"no","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"enableDevHub","type":"text","marks":[{"type":"code_inline"}]},{"text":" field and ","type":"text"},{"text":"no","type":"text","marks":[{"type":"strong"}]},{"text":" dedicated ","type":"text"},{"text":"sf","type":"text","marks":[{"type":"code_inline"}]},{"text":" command to turn it on — deploying this setting is exactly what the Setup toggle does.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enabling is irreversible","type":"text","marks":[{"type":"strong"}]},{"text":" — once on, Dev Hub cannot be turned off.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Requires","type":"text","marks":[{"type":"strong"}]},{"text":" a user with ","type":"text"},{"text":"ModifyAllData","type":"text","marks":[{"type":"strong"}]},{"text":" or ","type":"text"},{"text":"ModifyMetadata","type":"text","marks":[{"type":"strong"}]},{"text":" (a ","type":"text"},{"text":"System Administrator","type":"text","marks":[{"type":"strong"}]},{"text":" has these). A user without them gets ","type":"text"},{"text":"INSUFFICIENT_ACCESS","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cannot","type":"text","marks":[{"type":"strong"}]},{"text":" be enabled in a ","type":"text"},{"text":"sandbox","type":"text","marks":[{"type":"strong"}]},{"text":", or in an org that has a ","type":"text"},{"text":"registered namespace","type":"text","marks":[{"type":"strong"}]},{"text":". The script checks the org's edition/sandbox facts before an ","type":"text"},{"text":"--enable --apply","type":"text","marks":[{"type":"code_inline"}]},{"text":" and refuses (no deploy attempted) if the target is a sandbox; there's no reliable CLI signal for a registered namespace, so that stays a documented caveat rather than an enforced check.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Available in ","type":"text"},{"text":"Developer, Enterprise, Performance, Unlimited","type":"text","marks":[{"type":"strong"}]},{"text":", and ","type":"text"},{"text":"trial","type":"text","marks":[{"type":"strong"}]},{"text":" editions — ","type":"text"},{"text":"status","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"--allocation","type":"text","marks":[{"type":"code_inline"}]},{"text":" show the org's edition when known.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Steps","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CRITICAL:","type":"text","marks":[{"type":"strong"}]},{"text":" Run the bundled helper script, which handles Dev Hub detection, the enablement deploy (with a safe dry-run default), allocation math, and structured output, and works on macOS and Linux. Always invoke it by ","type":"text"},{"text":"absolute path","type":"text","marks":[{"type":"strong"}]},{"text":" from the skill directory — never ","type":"text"},{"text":"./scripts/","type":"text","marks":[{"type":"code_inline"}]},{"text":", which resolves against the user's current directory and will either run the wrong script or fail. The script self-checks this: if ","type":"text"},{"text":"$0","type":"text","marks":[{"type":"code_inline"}]},{"text":" is not absolute it exits with a usage error, so pass the full path to ","type":"text"},{"text":"\u003cskill_dir>","type":"text","marks":[{"type":"code_inline"}]},{"text":" (the directory containing this SKILL.md).","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"bash \"\u003cskill_dir>/scripts/devhub.sh\" \u003calias-or-username> # status: on? + edition + allocation\nbash \"\u003cskill_dir>/scripts/devhub.sh\" # default org (target-org)\nbash \"\u003cskill_dir>/scripts/devhub.sh\" \u003corg> --allocation # allocation + pre-flight warnings\nbash \"\u003cskill_dir>/scripts/devhub.sh\" \u003corg> --show-settings # current DevHubSettings preferences\nbash \"\u003cskill_dir>/scripts/devhub.sh\" --list-orgs # authenticated orgs (no org needed)\nbash \"\u003cskill_dir>/scripts/devhub.sh\" \u003corg> --enable # validate enabling (dry run)\nbash \"\u003cskill_dir>/scripts/devhub.sh\" \u003corg> --enable --apply # actually enable (irreversible)\nbash \"\u003cskill_dir>/scripts/devhub.sh\" \u003corg> --list-scratch # list active scratch orgs","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cskill_dir>","type":"text","marks":[{"type":"code_inline"}]},{"text":" is the absolute path to the directory containing this SKILL.md.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For enablement, default to a dry run first.","type":"text","marks":[{"type":"strong"}]},{"text":" Run ","type":"text"},{"text":"--enable","type":"text","marks":[{"type":"code_inline"}]},{"text":" (no ","type":"text"},{"text":"--apply","type":"text","marks":[{"type":"code_inline"}]},{"text":") to validate the deploy, then relay the result. Because enabling is ","type":"text"},{"text":"irreversible","type":"text","marks":[{"type":"strong"}]},{"text":", only run ","type":"text"},{"text":"--enable --apply","type":"text","marks":[{"type":"code_inline"}]},{"text":" when the user has clearly asked to actually enable Dev Hub. Applied operations require an explicit org alias or username; the script refuses to mutate an implicit default org. The script also refuses to enable on a ","type":"text"},{"text":"sandbox","type":"text","marks":[{"type":"strong"}]},{"text":" — it checks the org's edition facts first and returns an eligibility explanation instead of deploying, and ","type":"text"},{"text":"status","type":"text","marks":[{"type":"code_inline"}]},{"text":" on a sandbox reports the same ineligibility. When the target is ineligible (a sandbox, or an org with a registered namespace), ","type":"text"},{"text":"declining to enable is the correct, complete outcome even if the user explicitly asked to apply it","type":"text","marks":[{"type":"strong"}]},{"text":" — do not deploy. Give a full answer that (1) states Dev Hub ","type":"text"},{"text":"cannot","type":"text","marks":[{"type":"strong"}]},{"text":" be enabled on this org, (2) says ","type":"text"},{"text":"why","type":"text","marks":[{"type":"strong"}]},{"text":" (a sandbox cannot host a Dev Hub; a registered namespace also blocks it), and (3) gives the ","type":"text"},{"text":"alternative","type":"text","marks":[{"type":"strong"}]},{"text":" — enable Dev Hub on the source ","type":"text"},{"text":"production","type":"text","marks":[{"type":"strong"}]},{"text":" org, or a ","type":"text"},{"text":"Developer Edition / trial","type":"text","marks":[{"type":"strong"}]},{"text":" org, with a ","type":"text"},{"text":"System Administrator","type":"text","marks":[{"type":"strong"}]},{"text":", and use that as the Dev Hub. Do not report a scratch-org allocation for an ineligible org. If the deploy is rejected for permissions, surface the Setup-UI fallback it prints.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Relay the script output. When an org can't be authenticated, the script never logs in on its own — it prints the exact ","type":"text"},{"text":"sf org login web","type":"text","marks":[{"type":"code_inline"}]},{"text":" command as guidance; surface that command to the user so they can run it themselves, then re-run the skill. When no org and no default are configured, it also lists the authenticated orgs it found so the user can pick one. Pick optional flags based on the request (see below): ","type":"text"},{"text":"--allocation","type":"text","marks":[{"type":"code_inline"}]},{"text":" for limits only, ","type":"text"},{"text":"--show-settings","type":"text","marks":[{"type":"code_inline"}]},{"text":" for current preference values, ","type":"text"},{"text":"--list-orgs","type":"text","marks":[{"type":"code_inline"}]},{"text":" for discovery, ","type":"text"},{"text":"--list-scratch","type":"text","marks":[{"type":"code_inline"}]},{"text":" to enumerate scratch orgs, ","type":"text"},{"text":"--packaging","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"--snapshots","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"--shape","type":"text","marks":[{"type":"code_inline"}]},{"text":" to turn on sub-preferences, ","type":"text"},{"text":"--json","type":"text","marks":[{"type":"code_inline"}]},{"text":" for automation.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Before you finish","type":"text"}]},{"type":"paragraph","content":[{"text":"Verify these before returning your answer:","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"CRITICAL:","type":"text","marks":[{"type":"strong"}]},{"text":" Invoked the helper via its ","type":"text"},{"text":"absolute path","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"bash \"\u003cskill_dir>/scripts/devhub.sh\" …","type":"text","marks":[{"type":"code_inline"}]},{"text":"), never ","type":"text"},{"text":"./scripts/","type":"text","marks":[{"type":"code_inline"}]},{"text":" (the script rejects a non-absolute ","type":"text"},{"text":"$0","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Did ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" run ","type":"text"},{"text":"--apply","type":"text","marks":[{"type":"code_inline"}]},{"text":" unless the user clearly asked to actually enable Dev Hub or deploy a preference — enabling is ","type":"text"},{"text":"irreversible","type":"text","marks":[{"type":"strong"}]},{"text":".","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Did ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" attempt to log in on the user's behalf — if the org isn't authenticated, relayed the ","type":"text"},{"text":"sf org login web","type":"text","marks":[{"type":"code_inline"}]},{"text":" guidance the script printed instead of running it.","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Relayed the script's own output (status/allocation/settings, the pre-flight warnings, the discovered orgs, the sandbox-eligibility refusal, or the login/Setup-UI guidance it printed), rather than substituting a hand-written answer.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Options","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Flag","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--allocation","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"-A","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show only the scratch org allocation (Active/Daily), including pre-flight ","type":"text"},{"text":"WARN","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"NOTE","type":"text","marks":[{"type":"code_inline"}]},{"text":" lines when close to the limit.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--show-settings","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"-s","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show the org's current ","type":"text"},{"text":"DevHubSettings","type":"text","marks":[{"type":"code_inline"}]},{"text":" preference values (packaging, snapshots, shape, etc.), ON/OFF. Requires Dev Hub to already be enabled.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--list-orgs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"List authenticated orgs (alias, username, connected status, default marker). No target org required.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--list-scratch","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"-l","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"List active scratch orgs created from this Dev Hub.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--enable","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"-e","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enable Dev Hub (deploys ","type":"text"},{"text":"enableScratchOrgManagementPref=true","type":"text","marks":[{"type":"code_inline"}]},{"text":"). Dry run unless ","type":"text"},{"text":"--apply","type":"text","marks":[{"type":"code_inline"}]},{"text":"; refuses on a sandbox.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--configure","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"-c","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Configure sub-preferences without (re)enabling the master switch. Pair with a pref flag.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--packaging","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enablePackaging2=true","type":"text","marks":[{"type":"code_inline"}]},{"text":" (Unlocked + 2GP packages).","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--snapshots","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableScratchOrgSnapshotPref=true","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--shape","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableShapeExportPref=true","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--scratch-management","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enableScratchOrgManagementPref=true","type":"text","marks":[{"type":"code_inline"}]},{"text":" (the Dev Hub switch).","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--pref KEY=VALUE","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Any ","type":"text"},{"text":"DevHubSettings","type":"text","marks":[{"type":"code_inline"}]},{"text":" sub-pref (KEY starts with ","type":"text"},{"text":"enable","type":"text","marks":[{"type":"code_inline"}]},{"text":", VALUE ","type":"text"},{"text":"true","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"false","type":"text","marks":[{"type":"code_inline"}]},{"text":"). Repeatable.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--apply","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Actually deploy to the explicit org argument. Default for ","type":"text"},{"text":"--enable","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"--configure","type":"text","marks":[{"type":"code_inline"}]},{"text":" is a validate-only dry run.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Emit machine-readable JSON.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--fail-if-disabled","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Exit ","type":"text"},{"text":"3","type":"text","marks":[{"type":"code_inline"}]},{"text":" if Dev Hub is not enabled (CI/cron gate).","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--help","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"-h","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Show usage.","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"--enable","type":"text","marks":[{"type":"code_inline"}]},{"text":" may be combined with sub-pref flags to enable and configure at once (e.g. ","type":"text"},{"text":"--enable --packaging --apply","type":"text","marks":[{"type":"code_inline"}]},{"text":"). If omitted, the org defaults to ","type":"text"},{"text":"target-org","type":"text","marks":[{"type":"code_inline"}]},{"text":", then ","type":"text"},{"text":"target-dev-hub","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Output examples","type":"text"}]},{"type":"paragraph","content":[{"text":"The script prints the authoritative output at runtime. If you need to calibrate what an enabled-vs-disabled status transcript looks like (including the allocation table and the enable/Setup-UI guidance), read ","type":"text"},{"text":"examples/status-output.md","type":"text","marks":[{"type":"link","attrs":{"href":"examples/status-output.md","title":null}},{"type":"code_inline"}]},{"text":" — otherwise skip it to keep this workflow lean.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Structured output for automation (","type":"text"},{"text":"--json","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"--json","type":"text","marks":[{"type":"code_inline"}]},{"text":" in any mode for machine-readable output (no prose). Status returns ","type":"text"},{"text":"devHubEnabled","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"status","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"edition","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"isSandbox","type":"text","marks":[{"type":"code_inline"}]},{"text":", and an ","type":"text"},{"text":"allocation","type":"text","marks":[{"type":"code_inline"}]},{"text":" object (with ","type":"text"},{"text":"usedPct","type":"text","marks":[{"type":"code_inline"}]},{"text":" per limit and a ","type":"text"},{"text":"warnings","type":"text","marks":[{"type":"code_inline"}]},{"text":" array); ","type":"text"},{"text":"--show-settings","type":"text","marks":[{"type":"code_inline"}]},{"text":" returns ","type":"text"},{"text":"org","type":"text","marks":[{"type":"code_inline"}]},{"text":" and a ","type":"text"},{"text":"settings","type":"text","marks":[{"type":"code_inline"}]},{"text":" map of preference key → boolean; ","type":"text"},{"text":"--list-orgs","type":"text","marks":[{"type":"code_inline"}]},{"text":" returns a normalized array of ","type":"text"},{"text":"{alias, username, connectedStatus, isDefault}","type":"text","marks":[{"type":"code_inline"}]},{"text":"; enablement returns ","type":"text"},{"text":"success","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"applied","type":"text","marks":[{"type":"code_inline"}]},{"text":", and ","type":"text"},{"text":"devHubVerifiedState","type":"text","marks":[{"type":"code_inline"}]},{"text":". Deterministic, no LLM needed.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"bash \"\u003cskill_dir>/scripts/devhub.sh\" my-devhub --json\n# {\"org\":\"my-devhub\",\"devHubEnabled\":true,\"status\":\"enabled\", ... }","type":"text"}]},{"type":"paragraph","content":[{"text":"--fail-if-disabled","type":"text","marks":[{"type":"code_inline"}]},{"text":" exits ","type":"text"},{"text":"3","type":"text","marks":[{"type":"code_inline"}]},{"text":" (and prints an ","type":"text"},{"text":"ALERT:","type":"text","marks":[{"type":"code_inline"}]},{"text":" line to stderr) if Dev Hub is not enabled, so a scheduled job can gate on it.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Exit codes","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"0","type":"text","marks":[{"type":"code_inline"}]},{"text":" success","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"1","type":"text","marks":[{"type":"code_inline"}]},{"text":" an org could not be queried, or a deploy failed (auth/connection/deploy)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"2","type":"text","marks":[{"type":"code_inline"}]},{"text":" bad usage or a missing dependency (","type":"text"},{"text":"sf","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"jq","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"3","type":"text","marks":[{"type":"code_inline"}]},{"text":" Dev Hub is not enabled (only when ","type":"text"},{"text":"--fail-if-disabled","type":"text","marks":[{"type":"code_inline"}]},{"text":" is set)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Authentication (guidance only)","type":"text"}]},{"type":"paragraph","content":[{"text":"This skill ","type":"text"},{"text":"never runs an interactive login itself","type":"text","marks":[{"type":"strong"}]},{"text":" — it has no ","type":"text"},{"text":"--login","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"--instance-url","type":"text","marks":[{"type":"code_inline"}]},{"text":" flag, and it never invokes ","type":"text"},{"text":"sf org login web","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"sf org login device","type":"text","marks":[{"type":"code_inline"}]},{"text":". If the target org can't be queried (not authenticated, expired session, wrong instance), the script prints the exact login command as copy-paste ","type":"text"},{"text":"guidance","type":"text","marks":[{"type":"strong"}]},{"text":" and stops; relay that command to the user and let them run it, then re-run the skill:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"text"},"content":[{"text":" my-org could not query org (...)\n\n This org is not authenticated (or the session expired). Authentication is\n a precondition for this skill — run one of these yourself, then re-run:\n sf org login web --alias 'my-org' # prod / DE / trial\n sf org login web --alias \u003cmy-alias> --instance-url https://MYDOMAIN.my.salesforce.com # sandbox / My Domain\n List existing logins with: sf org list","type":"text"}]},{"type":"paragraph","content":[{"text":"When no org and no default is configured at all, the script also runs org discovery (","type":"text"},{"text":"--list-orgs","type":"text","marks":[{"type":"code_inline"}]},{"text":") and lists the authenticated orgs it found, so the user can pick one instead of guessing an alias.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Manual fallback (if the script is unavailable)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Detect Dev Hub (INVALID_TYPE error means OFF; a count means ON):\nsf data query --query \"SELECT COUNT() FROM ScratchOrgInfo\" --target-org \u003corg> --json\n\n# Read current DevHubSettings preferences (requires Dev Hub already ON):\nsf api request rest \"/services/data/v62.0/tooling/sobjects/DevHubSettings/DevHub\" \\\n --target-org \u003corg> --json\n\n# Enable Dev Hub via the Tooling API (what the Setup toggle does; irreversible):\nsf api request rest \"/services/data/v62.0/tooling/sobjects/DevHubSettings/DevHub\" \\\n --method PATCH \\\n --body '{\"FullName\":\"DevHub\",\"Metadata\":{\"enableScratchOrgManagementPref\":true}}' \\\n --target-org \u003corg>\n\n# Or enable in the UI: Setup > Quick Find > \"Dev Hub\" > turn Enable Dev Hub On.\n\n# View scratch org allocation:\nsf org list limits --target-org \u003corg> --json | jq '.result[] | select(.name|test(\"ScratchOrg\"))'\n\n# List authenticated orgs:\nsf org list --json","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Notes","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Requires the Salesforce CLI (","type":"text"},{"text":"sf","type":"text","marks":[{"type":"code_inline"}]},{"text":") and ","type":"text"},{"text":"jq","type":"text","marks":[{"type":"code_inline"}]},{"text":" on the PATH, plus at least one authenticated org. This skill only ever prints the ","type":"text"},{"text":"sf org login web","type":"text","marks":[{"type":"code_inline"}]},{"text":" command as guidance — it never runs it.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"After enabling, set the org as your default Dev Hub: ","type":"text"},{"text":"sf config set target-dev-hub \u003corg>","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enabling ","type":"text"},{"text":"packaging","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"enablePackaging2","type":"text","marks":[{"type":"code_inline"}]},{"text":") requires Dev Hub to be on first — ","type":"text"},{"text":"--enable --packaging","type":"text","marks":[{"type":"code_inline"}]},{"text":" handles the ordering in a single deploy.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Non-admin users still need object access (Read/Create on ","type":"text"},{"text":"ScratchOrgInfo","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"ActiveScratchOrg","type":"text","marks":[{"type":"code_inline"}]},{"text":") to create/view scratch orgs, and the \"Create and Update Second-Generation Packages\" permission to build 2GP/unlocked packages.","type":"text"}]}]}]}]},"metadata":{"date":"2026-11-02","name":"dx-org-devhub-configure","author":"@skillopedia","source":{"stars":1139,"repo_name":"sf-skills","origin_url":"https://github.com/forcedotcom/sf-skills/blob/HEAD/skills/dx-org-devhub-configure/SKILL.md","repo_owner":"forcedotcom","body_sha256":"dfcd75091b94a0400ea94f0f2d934d3ff6e20c0151af39d3ec0b075f3bd3873d","cluster_key":"14663733b85d5d534c25324c0798c6e1a0754a66fed56b6e9c09489f9dc308e5","clean_bundle":{"format":"clean-skill-bundle-v1","source":"forcedotcom/sf-skills/skills/dx-org-devhub-configure/SKILL.md","text_bytes":46864,"source_commit":"a8a18ce1e4ba12e69b4073eab98ce31bfbd8271e","skills_sh_rank":8110,"attachment_count":3,"text_attachments":3,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/dx-org-devhub-configure/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"devops-infrastructure","category_label":"DevOps"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"devops-infrastructure","metadata":{"domains":["Developer Experience"],"version":"1.1","cliTools":[{"tool":["jq"],"semver":">=1.6.0"},{"tool":["sf"],"semver":">=2.0.0"}],"accessCheck":"UserPermissions.ModifyAllData","minApiVersion":"62.0"},"import_tag":"skills-sh-top20k-2026-11","description":"Enable Dev Hub on a Salesforce org, view its status and scratch org allocation, or read its current DevHubSettings preferences, using the Salesforce CLI (sf). Use when someone wants to turn on or enable Dev Hub, set up an org for scratch orgs or 2GP/unlocked packages, check whether Dev Hub is already enabled, see scratch org allocation (Active/Daily limits, remaining, and a pre-flight warning near the limit), see which Dev Hub preferences (packaging, org shape export, scratch org snapshots) are on or off, configure those preferences, list active scratch orgs, or list authenticated orgs when none is specified. Enabling deploys enableScratchOrgManagementPref, is irreversible, needs a System Administrator (ModifyAllData or ModifyMetadata), and does not work in sandboxes. DO NOT TRIGGER for creating or deleting individual scratch orgs.","allowed-tools":"Read, Bash(bash), Bash(sf api request rest), Bash(sf data query), Bash(sf org list), Bash(sf project deploy), Bash(sf config get), Bash(sf org display), Bash(sf org open), Bash(jq)"}},"renderedAt":1793666285308}

Enable Dev Hub & View Scratch Org Allocation Enable Dev Hub on a Salesforce org, verify whether it is already on, and see the org's scratch org allocation (Active and Daily limits, how many remain, and a pre-flight warning when close to the limit) — for the default org or a named org. The skill can also read the org's current DevHubSettings preferences , configure Dev Hub sub-preferences (packaging, org shape export, scratch org snapshots), list the active scratch orgs created from a Dev Hub, and list which orgs are authenticated when none is specified. Dev Hub is the org feature that lets yo…