
Shopify Onboarding Dev
Onboard onto Shopify’s dev documentation stack with correct base URLs, staging hosts, and Minerva auth when building against shopify.dev APIs.
Overview
Shopify Onboarding Dev is an agent skill for the Build phase that configures Shopify developer base URLs, staging hosts, and Minerva authentication for shopify.dev API work.
Install
npx skills add https://github.com/shopify/shopify-ai-toolkit --skill shopify-onboarding-devWhat is this skill?
- Resolves shopify.dev production vs shop.dev vs numbered staging base URLs
- Enforces MINERVA_TOKEN when SHOPIFY_DEV_STAGING_SERVER_NUMBER is set
- Validates staging server number as a positive integer before requests
- Documents devx minerva-auth flow for staging audiences
- Skill use logging hooks via Shopify agent-skills toolkit scripts
- 3 documented base URL families: production shopify.dev, shop.dev, and numbered staging hosts
Adoption & trust: 3.7k installs on skills.sh; 373 GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
You are building against Shopify dev docs or APIs but staging requires Minerva cookies and the correct host, so agents keep calling the wrong URL or fail auth silently.
Who is it for?
Indie Shopify app developers wiring agents to official dev staging and documentation endpoints before feature implementation.
Skip if: Merchants configuring a live theme or marketing who never touch shopify.dev staging or Minerva.
When should I use this skill?
Starting Shopify app or API integration work that may target staging documentation servers requiring Minerva authentication.
What do I get? / Deliverables
Your agent and scripts use a resolved base URL with optional staging headers so later Shopify toolkit skills run against an authenticated dev environment.
- Validated Shopify dev base URL and optional auth headers configuration
- Documented env vars for staging server number and MINERVA_TOKEN
Recommended Skills
Journey fit
Build is where ecommerce extensions and app backends connect to Shopify; onboarding dev environments is the first integration step before feature work. Integrations subphase captures environment setup, staging server numbers, and authenticated calls to Shopify dev infrastructure.
How it compares
Environment and auth onboarding for Shopify dev—not a substitute for Shopify’s product admin or theme customization skills.
Common Questions / FAQ
Who is shopify-onboarding-dev for?
Solo builders and small teams developing Shopify apps or integrations who need staging-aware HTTP setup before using other shopify-ai-toolkit skills.
When should I use shopify-onboarding-dev?
At the beginning of Build/integrations when you set SHOPIFY_DEV_STAGING_SERVER_NUMBER or need to confirm which shopify.dev host and Minerva token your agent should use.
Is shopify-onboarding-dev safe to install?
It involves secret Minerva tokens and network calls to Shopify infrastructure—review Security Audits on this page and never commit MINERVA_TOKEN to your repo.
SKILL.md
READMESKILL.md - Shopify Onboarding Dev
#!/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");