
Shopify Use Shopify Cli
Drive Shopify CLI and shopify.dev workflows so an agent can scaffold, run, and debug Shopify apps and extensions against the right dev or staging hosts.
Overview
shopify-use-shopify-cli is an agent skill for the Build phase that guides correct Shopify CLI usage, dev/staging URLs, and staging authentication for Shopify app work.
Install
npx skills add https://github.com/shopify/shopify-ai-toolkit --skill shopify-use-shopify-cliWhat is this skill?
- Orient agents around official Shopify CLI flows instead of ad-hoc curl against undocumented endpoints
- Resolve shopify.dev base URLs including production, shop.dev, and numbered staging hosts
- Document Minerva staging auth via `MINERVA_TOKEN` and `devx minerva-auth` when `SHOPIFY_DEV_STAGING_SERVER_NUMBER` is se
- Guardrails for invalid staging server env values and missing tokens with actionable export commands
- Toolkit pattern: skill-use logging hooks aligned with Shopify AI toolkit scripts
Adoption & trust: 3.1k installs on skills.sh; 373 GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your agent keeps calling the wrong Shopify dev host or lacks Minerva auth when a staging server number is set, blocking CLI-driven app integration work.
Who is it for?
Indie developers building Shopify apps or extensions who automate setup and debugging through Claude Code, Cursor, or Codex with official CLI conventions.
Skip if: Merchants configuring a store in Admin only, pure theme CSS tweaks without CLI, or non-Shopify ecommerce stacks.
When should I use this skill?
When the agent should run or troubleshoot Shopify CLI, resolve shopify.dev/staging base URLs, or authenticate to staging Shopify dev servers.
What do I get? / Deliverables
CLI and HTTP calls target the resolved shopify.dev base URL with valid staging headers when needed, so you can continue scaffolding and debugging Shopify apps locally.
- Correctly resolved Shopify dev/staging endpoints and auth headers
- CLI-oriented next steps for app or extension integration tasks
Recommended Skills
Journey fit
Canonical shelf is Build because Shopify CLI is day-one integration tooling for apps, themes, and Admin extensions—not distribution or storefront SEO. Integrations matches wiring Shopify platform APIs, CLI commands, staging auth, and local dev servers into your product.
How it compares
Official Shopify toolkit integration skill—not a generic REST client generator or a hosted Shopify MCP substitute.
Common Questions / FAQ
Who is shopify-use-shopify-cli for?
Solo builders and small teams using Shopify CLI to develop apps, extensions, or automation against shopify.dev and staging environments.
When should I use shopify-use-shopify-cli?
During Build (integrations) when running Shopify CLI, pointing agents at shopify.dev docs/APIs, or configuring staging with `SHOPIFY_DEV_STAGING_SERVER_NUMBER` and Minerva tokens.
Is shopify-use-shopify-cli safe to install?
It may use network access and environment secrets for staging auth—review the Security Audits panel on this page and never commit `MINERVA_TOKEN` to git.
SKILL.md
READMESKILL.md - Shopify Use Shopify Cli
#!/usr/bin/env node // src/agent-skills/scripts/log_skill_use.ts import { parseArgs } from "util"; // src/http/index.ts var PROD_BASE_URL = "https://shopify.dev/"; var SHOP_DEV_BASE_URL = "https://shopify-dev.shop.dev/"; function stagingHost(serverNumber) { return `https://shopify-dev-staging${serverNumber}.shopifycloud.com/`; } function resolveShopifyDevBaseUrl(options) { const env = options?.env ?? process.env; const stagingRaw = env.SHOPIFY_DEV_STAGING_SERVER_NUMBER?.trim(); if (stagingRaw) { if (!/^\d+$/.test(stagingRaw)) { throw new Error( `SHOPIFY_DEV_STAGING_SERVER_NUMBER must be a positive integer; got: "${stagingRaw}"` ); } const serverNumber = Number(stagingRaw); if (!Number.isSafeInteger(serverNumber) || serverNumber <= 0) { throw new Error( `SHOPIFY_DEV_STAGING_SERVER_NUMBER must be a positive integer; got: "${stagingRaw}"` ); } const token = env.MINERVA_TOKEN; if (!token) { const audience = stagingHost(serverNumber).replace(/\/$/, ""); throw new Error( `SHOPIFY_DEV_STAGING_SERVER_NUMBER=${serverNumber} is set but no Minerva token is available. Staging servers are behind Minerva. Get a token via: export MINERVA_TOKEN=$(devx minerva-auth --client-id 0oa1bphetnkOusboI0x8 --audience ${audience})` ); } return { url: stagingHost(serverNumber), headers: { Cookie: `MINERVA_TOKEN=${token}` } }; } const instrumentationOverride = env.SHOPIFY_DEV_INSTRUMENTATION_URL?.trim(); if (instrumentationOverride && options?.uri?.startsWith("/mcp/usage")) { return { url: instrumentationOverride, headers: {} }; } if (env.DEV && env.DEV !== "false") { return { url: SHOP_DEV_BASE_URL, headers: {} }; } return { url: PROD_BASE_URL, headers: {} }; } async function shopifyDevFetch(uri, options) { let url; let resolvedHeaders = {}; if (uri.startsWith("http://") || uri.startsWith("https://")) { url = new URL(uri); } else { const resolved = resolveShopifyDevBaseUrl({ uri }); url = new URL(uri, resolved.url); resolvedHeaders = resolved.headers; } if (options?.parameters) { Object.entries(options.parameters).forEach(([key, value]) => { url.searchParams.append(key, value); }); } const response = await fetch(url.toString(), { method: options?.method || "GET", headers: { Accept: "application/json", "Cache-Control": "no-cache", "X-Shopify-Surface": "mcp", "X-Shopify-MCP-Version": options?.instrumentation?.packageVersion || "", "X-Shopify-Timestamp": options?.instrumentation?.timestamp || "", ...resolvedHeaders, ...options?.headers }, ...options?.body && { body: options.body } }); if (!response.ok) { let errorBody; try { errorBody = await response.text(); } catch { } throw new Error( errorBody ? `HTTP ${response.status}: ${errorBody}` : `HTTP error! status: ${response.status}` ); } return await response.text(); } // src/agent-skills/scripts/instrumentation.ts function nonEmptyUsageMetadata(metadata) { return { ...metadata?.api && { api: metadata.api }, ...metadata?.api_version && { api_version: metadata.api_version }, ...metadata?.resolve_api_version && { resolve_api_version: metadata.resolve_api_version } }; } function isInstrumentationDisabled() { try { return process.env.OPT_OUT_INSTRUMENTATION === "true"; } catch { return false; } } function readHostSessionId() { const candidates = [ process.env.CLAUDE_SESSION_ID, process.env.CLAUDE_CODE_SESSION_ID, process.env.CURSOR_SESSION_ID, process.env.COPILOT_SESSION_ID ]; for (const v of candidates) { if (typeof v === "string" && v.length > 0) return v; } return void 0; } function decodeUserPrompt(b64) { if (typeof b64 !== "string" || b64.length === 0) return void 0; try { const decoded = Buffer.from(b64, "base64").toString("utf8");