Not yet assessed
Review the original instructions and requested permissions before installing.
No security review is available for this catalog entry yet.
Inspect and manage Salesforce sandbox configuration, creation, refresh, activation, and deletion.
MUST USE this skill for ANY sandbox request — including simply getting a sandbox's details, status, license type, or pending-activation state by name or ID. TRIGGER when the user: types "sandbox -help"/"sandbox help"; mentions a sandbox ID (07E prefix); asks to list or show sandboxes; asks for the details, status, license type, or config of a sandbox by name or ID; activates or discards a completed refresh; deletes a sandbox; verifies activation or deletion; creates or refreshes a sandbox. DO NOT TRIGGER when: the user wants to clone a sandbox.
Review the original instructions and requested permissions before installing.
No security review is available for this catalog entry yet.
How clearly the skill guides your agent, how complete its workflow is, and how you can check the outcome.
No quality assessment is available for this catalog entry yet.
Original instructions from the publisher’s SKILL.md
# Sandbox Lifecycle Management
Manage Salesforce sandbox environments through Connect REST API — list inventory, activate or discard completed refreshes, create and refresh sandboxes, and permanently delete sandboxes.
## When This Skill Owns the Task
Use `platform-sandbox-configure` when the work involves:
- Listing or retrieving all sandboxes (GET /sandbox/reports)
- Getting details or status of a specific sandbox by name or by ID (07E prefix)
- Checking license usage and remaining capacity by license type (GET /sandbox/licenses)
- Activating a sandbox after a refresh completes (applying the refresh)
- Discarding a completed refresh (keeping existing sandbox data unchanged)
- Permanently deleting a sandbox to free up licenses
- Verifying activation or deletion completed
- Creating a new sandbox (Developer, Developer Pro, Partial Copy, or Full)
- Refreshing an existing sandbox with latest production data
Delegate elsewhere when the user is:
- Cloning a sandbox → Tooling API (`SandboxInfo` sObject)
- Generating a post-copy automation JSON config from an SOP → `automation-sandbox-post-copy-config-generate`
- Applying/running a post-copy automation JSON config against a sandbox → `automation-sandbox-post-copy-configure`
---
## Help (Interactive Menu)
When the user types `sandbox -help` or `sandbox help`, respond with ONLY a text message showing the numbered operation list below. **Do NOT call any API or tool — just display this menu and wait for the user to reply with a number.**
The agent MUST respond with this exact markdown (not in a code block — render it directly as a bullet list):
**Sandbox Lifecycle Management**
**1. Inventory & Details**
- a. List all sandboxes — Names, types, statuses, IDs
- b. Get details (by name) — Status, license, config
- c. Get details (by ID) — Provide a 07E ID directly
- d. Check license usage — Available vs. used counts by license type
**2. Create & Refresh**
- a. Create a new sandbox — Dev, Dev Pro, Partial, Full
- b. Refresh a sandbox — Latest production data
**3. Activate, Discard & Delete**
- a. Activate a sandbox — Apply a completed refresh
- b. Discard a refresh — Reject, keep existing data
- c. Delete a sandbox — Permanent removal
**4. Verify & Monitor**
- a. Verify activation status — Check if activate completed
- b. Verify deletion status — Check if delete completed
**5. Post-Copy Automation**
- a. Create Post Copy Automation JSON Configs — Generate a config from an SOP
- b. Run Post Copy Automation — Apply a config JSON to a sandbox
Reply with a code (e.g. "3a") or describe what you need.
**After the user replies, ask for the required input:**
| Selection | Follow-up question |
|---|---|
| 1a | No input needed — proceed immediately |
| 1b | "What's the sandbox name?" |
| 1c | "What's the sandbox ID? (starts with 07E)" |
| 1d | No input needed — proceed immediately |
| 2a | First call `GET /sandbox/licenses` (Section 9) and show available/used counts; then ask for name + license type (Developer, Developer_Pro, Partial_Copy, Full) |
| 2b | First call `GET /sandbox/reports` (Section 1) and list refresh-eligible sandboxes (`isPendingActivation: false`); then ask which to refresh |
| 3a | "Which sandbox? Provide a name or 07E ID." |
| 3b | "Which sandbox? Provide a name or 07E ID." |
| 3c | "Which sandbox? Provide a name or 07E ID." |
| 4a | "Which sandbox did you activate? Provide a name or 07E ID." |
| 4b | "Which sandbox did you delete? Provide a name or 07E ID." |
| 5a | "Delegating to the post-copy config generator — please share the SOP (file, text, or screenshot)." |
| 5b | "Delegating to the post-copy config runner — please share the config JSON file and the target sandbox." |
Execute the corresponding operation below. **Exception:** 5a/5b delegate — 5a → `automation-sandbox-post-copy-config-generate`; 5b → `automation-sandbox-post-copy-configure`. This skill does not implement post-copy automation; do not generate or apply a config directly.
---
## API Base
**CRITICAL:** For sandbox operations in this skill, use the Connect REST API. Two discovery paths exist:
- **By name:** Call `GET /sandbox/reports` to list all sandboxes and find the matching one by `sandboxName`.
- **By ID (07E prefix):** Call `GET /sandbox/sandboxes/{sandboxId}` directly — do NOT call `/sandbox/reports`.
Both paths return sandbox records with `sandboxId` (prefix `07E`) which is required for all lifecycle mutation operations.
```bash
sf api request rest "/services/data/v66.0/sandbox/reports" --method GET
```
See `references/api-response-shapes.md` for the full response shape.
**IMPORTANT:** Do NOT use Tooling API (`SandboxInfo`/`SandboxProcess`) for discovery — mutation endpoints require the Connect REST API's `sandboxId` (07E), NOT `SandboxInfo.Id` (0GQ) or `SandboxProcess.Id` (0GR).
**NEVER use SOQL / `run_soql_query` / `sf data query` for lifecycle reads (status, inventory, details, license, pending-activation).** This data lives ONLY in the Connect REST API — no SObject returns it. (`sf data query --use-tooling-api` on `SandboxInfo` is still valid for Create/Refresh mutations, not a lifecycle read.)
**Report API results exactly as they come back — never invent an error or a cause.** `count: 0` is a *successful* result (sandbox absent) — record `not_found`, don't reinterpret as a failure or retry via SOQL. If the API errors, capture the error body verbatim — do NOT speculate why (e.g. "must be a scratch org"); this endpoint doesn't report org edition/type, so any such guess is a fabrication.
Required permission: `ManageSandboxes`
## Irreversible Actions — Always Confirm First
| Action | Why irreversible |
|---|---|
| Create | Consumes a license of the selected type |
| Activate | Overwrites sandbox with refreshed data |
| Discard | Refresh data is lost |
| Delete | Sandbox permanently removed |
| Refresh with `AutoActivate=true` | Auto-applies on completion — same effect as Activate |
---
## Operations
### 1. List Sandbox Inventory
**Endpoint:** `GET /services/data/v66.0/sandbox/reports`
Returns a list of all sandboxes with their IDs, names, statuses, and license types.
```bash
sf api request rest "/services/data/v66.0/sandbox/reports" --method GET
```
See `references/api-response-shapes.md` for the full response shape.
**Use when:** User asks "show me all sandboxes", "how many sandboxes do I have", "what's the status of my sandboxes"
**Key response fields:**
- `sandbox.sandboxId` (07E prefix) — Required for all mutation operations
- `sandbox.sandboxName` — The sandbox name (top-level field)
- `sandbox.license` — Developer, Developer Pro, Partial Copy, Full
- `sandbox.isPendingActivation` — true if refresh is pending activation
- `sandbox.canActivate` / `canDelete` / `canDiscard` — Permission flags
---
### 2. Get Sandbox Details
**Endpoint:** `GET /services/data/v66.0/sandbox/sandboxes/{sandboxId}`
Returns detailed info for a specific sandbox.
**Use when:** User asks about a specific sandbox's status, configuration, or metadata.
**Key response fields:**
- `status` — Active, Pending Activation, Activating, Completed, etc.
- `isPendingActivation` — true if a refresh completed and awaits user decision
- `sandboxType` — Developer, DeveloperPro, PartialCopy, Full
- `sourceId` — ID of the source org
---
### 3. Activate Sandbox (Apply Refresh)
**Endpoint:** `PATCH /services/data/v66.0/sandbox/activate/{sandboxId}`
**CRITICAL DOMAIN RULE:** This operation ONLY applies to sandboxes with a completed refresh in "Pending Activation" state. It applies the refreshed data to the sandbox. It does NOT "bring an inactive sandbox online" or "start" a sandbox.
**Pre-conditions:**
- Sandbox must be in `Pending Activation` status
- A refresh must have completed successfully
- User must have `ManageSandboxes` permission
**Before calling PATCH /activate:**
- [ ] Confirmed sandbox is in `Pending Activation` status via GET `/sandbox/sandboxes/{id}` (`isPendingActivation: true`)
- [ ] Confirmed a refresh has completed successfully
- [ ] Received explicit user confirmation — this overwrites the sandbox with the refreshed data and cannot be undone
**Use when:** User says "activate it", "apply the refresh", "use the latest data"
**After activation:** The sandbox runs with the newly refreshed production data.
---
### 4. Verify Activation
**Endpoint:** `GET /services/data/v66.0/sandbox/sandboxes/{sandboxId}`
Poll this endpoint after activation to confirm status changed to `Active`. This is a verification step, not a standalone user action.
**Use when:** Agent needs to confirm activation completed (called automatically after activate).
---
### 5. Discard Sandbox (Reject Refresh)
**Endpoint:** `DELETE /services/data/v66.0/sandbox/discardsandbox/{sandboxId}`
**CRITICAL DOMAIN RULE:** This operation ONLY applies to sandboxes with a completed refresh in "Pending Activation" state. It rejects the refresh — the existing sandbox continues running with its current data unchanged. It does NOT:
- Free up licenses
- Soft-delete or hide the sandbox
- Reset the sandbox to match production
**Pre-conditions:**
- Sandbox must be in `Pending Activation` status
- A refresh must have completed
**Before calling DELETE /discardsandbox:**
- [ ] Confirmed sandbox is in `Pending Activation` status via GET `/sandbox/sandboxes/{id}` (`isPendingActivation: true`)
- [ ] Confirmed this is a discard (reject refresh), NOT a delete (permanent removal)
- [ ] Received explicit user confirmation — the refresh data will be permanently lost and cannot be undone
**Use when:** User says "discard the refresh", "keep existing data", "don't apply the refresh", "reject the refresh"
**WARNING:** Discard is not reversible. The user will need to trigger a new refresh if they want fresh production data later.
---
### 6. Delete Sandbox (Permanent)
**Endpoint:** `DELETE /services/data/v66.0/sandbox/deletesandbox/{sandboxId}`
Permanently removes a sandbox and frees the license.
**Pre-conditions:**
- Sandbox must exist
- User must have `ManageSandboxes` permission
**Before calling DELETE /deletesandbox:**
- [ ] Surfaced sandbox details (name, license, status) with user and received explicit delete approval
**Use when:** User says "delete this sandbox", "remove it permanently", "free up the license"
**WARNING:** This is irreversible. Always confirm with the user before executing. Surface the sandbox name, license, and status as a safety check.
**If asked to restore a deleted sandbox:** No recovery path is documented today — escalate to Support rather than guessing at one.
---
### 7. Create a New Sandbox
Creates a new sandbox from scratch. Two approaches are supported — pick based on the user's preference; default to Approach A unless the user asks for a definition file or a repeatable DX blueprint.
**Pre-conditions:**
- Available license of the requested type must exist in the org
- Sandbox name must be unique and not already in use
- User must have `ManageSandboxes` permission
**Before creating — always confirm first:**
- [ ] Collected Name/License; asked about that license's optional inputs (`references/definition-file-approach.md`)
- [ ] Shown this confirmation summary — common fields plus the license's own fields:
> **Creating a new sandbox — please confirm:**
> - **Name:** `<SandboxName>`
> - **Description:** `<Description or "(none)">`
> - **Create From:** Production
> - **License:** `<Developer | Developer Pro | Partial Copy | Full>`
> - *(plus this license's fields — see `references/definition-file-approach.md`)*
>
> Feel free to change any of these before I proceed.
- [ ] Received explicit confirmation — this consumes a license of the selected type
#### Approach A — Tooling API record (direct)
**API:** Tooling API — `SandboxInfo` sObject
**Required inputs:**
- `SandboxName` — Name for the new sandbox (alphanumeric, max 10 chars)
- `LicenseType` — One of: `Developer`, `Developer_Pro`, `Partial_Copy`, `Full`
**Optional inputs:**
- `Description` — sandbox purpose
- `Features` — storage upgrade: `Developer`→400 MB, `Developer_Pro`→2 GB (irreversible); not for `Partial_Copy`/`Full`
- `ApexClassId` — Apex class implementing `SandboxPostCopy` (runs post-creation)
- `ActivationUserGroupId` — Access group (default: All Active Users)
- `TemplateId` / `HistoryDays` / `CopyChatter` / `CopyArchivedActivities` — `Partial_Copy`/`Full`-only; per-license table in `references/definition-file-approach.md`
```bash
# Create a Developer sandbox
sf data create record --sobject SandboxInfo --use-tooling-api --values "SandboxName='mybox' LicenseType='Developer'"
```
#### Approach B — Sandbox definition file (Salesforce CLI)
DX-native path: write a JSON definition file, then `sf org create sandbox --definition-file <file> --alias <name> --target-org <org>`. Prefer for a checked-in, repeatable config or name-based Apex/group references. See `references/definition-file-approach.md` for the JSON example, command, and field table.
**After creation:** A `SandboxProcess` record is created with Status = `Processing`. The sandbox copy begins immediately.
**Wrong type created:** Delete and recreate with the correct type.
**Renaming:** Not a standalone action — only takes effect via a Refresh's `SandboxName` input.
---
### 8. Refresh an Existing Sandbox
Refreshes a sandbox with the latest production data. Two approaches are supported — pick based on the user's preference; default to Approach A unless the user asks for a definition file.
#### Approach A — Tooling API record (direct)
**API:** Tooling API — `SandboxInfo` sObject (PATCH)
Refreshes by updating the existing `SandboxInfo` record.
**Required inputs:**
- Sandbox name — to look up the `SandboxInfo` record ID (0GQ prefix)
**Optional inputs:**
- `SandboxName` — New name for the refreshed sandbox (if user wants to rename it; alphanumeric, max 10 chars)
- `Description` — New or updated description for the sandbox
- `AutoActivate` — `true` to auto-activate when refresh completes (default: false)
- `Features` — storage upgrade: `Developer`→400 MB, `Developer_Pro`→2 GB (irreversible); not for `Partial_Copy`/`Full`
- `ActivationUserGroupId` — Access group (default: All Active Users)
- `TemplateId` / `HistoryDays` / `CopyChatter` — `Partial_Copy`/`Full`-only; per-license table in `references/definition-file-approach.md`
**Before triggering refresh — always confirm first:**
- [ ] Collected the sandbox name; asked about its license's optional inputs (`references/definition-file-approach.md`)
- [ ] Shown this confirmation summary:
> **Refreshing sandbox `<name>` — please confirm:**
> - **Rename to:** `<SandboxName or "(no change)">`
> - **Description:** `<Description or "(no change)">`
> - **Auto-Activate:** `<Yes | No (default)>`
> - **Sandbox Access:** `<ActivationUserGroupId or "All Active Users">`
> - *(plus this license's fields — see `references/definition-file-approach.md`)*
>
> Feel free to change any of these before I proceed.
- [ ] Received explicit confirmation — refresh overwrites the sandbox with production data; Auto-Activate=Yes applies automatically (equivalent to Activate)
**Steps:**
```bash
# 1. Look up SandboxInfo record Id by name
sf data query --query "SELECT Id, SandboxName, LicenseType, Description FROM SandboxInfo WHERE SandboxName = '<name>'" --use-tooling-api --json
# 2. PATCH to trigger refresh; include SandboxName/Description only if the user changed them
# Description is free text — escape any embedded single quotes (' -> \') before interpolating
sf data update record --sobject SandboxInfo --use-tooling-api --record-id <0GQ-id> --values "AutoActivate=true SandboxName='<newName>' Description='<description>'"
```
#### Approach B — Sandbox definition file (Salesforce CLI)
Refresh from the same JSON definition-file blueprint used for create, using `sf org refresh sandbox --name <name> --definition-file <file> --target-org <org>`. See `references/definition-file-approach.md` for the JSON example, command, and field table.
**Pre-conditions:**
- Sandbox must exist and be in a refreshable state
- Refresh interval must have elapsed (Developer = 1 day, Dev Pro = 1 day, Partial = 5 days, Full = 29 days)
- User must have `ManageSandboxes` permission
**After refresh:** A new `SandboxProcess` record is created with Status = `Processing`. If `AutoActivate=true`, the sandbox activates automatically when done. Otherwise it enters `Pending Activation` state.
**Refresh interval not met:** State the last-refreshed date and eligible date. For a fresher copy sooner, a clone (delegated) works if a spare license exists.
---
### 9. Check License Usage
**Endpoint:** `GET /services/data/v66.0/sandbox/licenses`
Returns license capacity, usage, and remaining counts per license type — no sandbox name or ID needed.
```bash
sf api request rest "/services/data/v66.0/sandbox/licenses" --method GET
```
See `references/api-response-shapes.md` for the full response shape.
**Use when:** User asks "how many sandbox licenses do I have left", "what's my license usage", "can I create another Full sandbox", or before creating/refreshing a sandbox to confirm capacity exists for that `licenseType`.
**Key response fields:**
- `licenseType` — `DEVELOPER`, `DEVELOPER_PRO`, `PARTIAL`, `FULL`
- `limit` — Total licenses of this type
- `used` — Currently allocated
- `available` — Remaining (i.e. `limit - used`)
**Create/Refresh blocked by a license limit:** offer to pick an available type, free one up by deleting a stale sandbox, ask the admin for a license increase, or — if it's an expired Courtesy Full Copy — purchase/convert it.
---
## Decision Guide for Agents
Resolve `sandboxId` first: by name, call `GET /sandbox/reports` and match `sandboxName`; by ID (07E prefix), call `GET /sandbox/sandboxes/{sandboxId}` directly — don't call `/sandbox/reports`.
| User says... | Operation | Key check |
|---|---|---|
| "Show all my sandboxes" | GET /sandbox/reports | — |
| "What's the status of X?" | GET /sandbox/reports (by name) or GET /sandbox/sandboxes/{id} (by ID) | — |
| "Activate sandbox X" | 1. Resolve `sandboxId`<br>2. PATCH /sandbox/activate/{sandboxId} | Must be isPendingActivation: true; confirm with user first |
| "Discard the refresh on X" | 1. Resolve `sandboxId`<br>2. DELETE /sandbox/discardsandbox/{sandboxId} | Must be isPendingActivation: true; confirm with user first |
| "Delete sandbox X" | 1. Resolve `sandboxId`<br>2. DELETE /sandbox/deletesandbox/{sandboxId} | Confirm with user first |
---
## Common Mistakes to Avoid
| Mistake | Correct understanding |
|---|---|
| Using activate to "start" any sandbox | Activate ONLY applies completed refreshes |
| Using discard to "hide" or "soft-delete" | Discard ONLY rejects a pending refresh |
| Activating without checking status first | Always verify isPendingActivation = true |
| Skipping confirmation on Create, Activate, Discard, Delete, or Refresh with `AutoActivate=true` | See Irreversible Actions above — always confirm first |
| Offering `AutoActivate` during Create | Refresh-only field |
| Offering `ApexClassId` during Refresh | Create-only field |