Shopify CI/CD CLI — scaffolds GitHub Actions workflows, branch strategy, and store config for single-store and multi-store theme repositories.
Commit linting and AI-assisted commits are available as optional setup steps:
- Conventional commit linting: During
climaybe init, you can choose to automatically install and configure commitlint and Husky to enforce Conventional Commits in your theme repository. - Cursor AI commit skill: You can also opt-in to installing the Cursor AI commit skill (
.cursor/skills/commit/SKILL.md) for AI-assisted, conventional commit message support in your project.
Both options streamline commit message quality and team workflows but are fully optional during setup.
Install in your theme repo (project-only, no global install):
cd your-shopify-theme-repo
npm install -D climaybeRun commands with npx climaybe (or add scripts to your package.json).
cd your-shopify-theme-repo
npm install -D climaybe
npx climaybe initThe interactive setup will ask for your store URL(s) and configure everything automatically.
Interactive setup that configures your repo for CI/CD.
- Prompts for your store URL (e.g.,
voldt-staging.myshopify.com) - Extracts subdomain as alias, lets you override
- Asks if you want to add more stores
- Asks whether to enable optional preview + cleanup workflows (default: yes)
- Asks whether to enable optional build + Lighthouse workflows (default: yes)
- Asks whether to enable commitlint + Husky (enforce conventional commits on
git commit) - Asks whether to add Cursor commit skill to the project (
.cursor/skills/commit/SKILL.md) for AI-assisted conventional commits - Based on store count, sets up single-store or multi-store mode
- Writes
package.jsonconfig - Scaffolds GitHub Actions workflows
- Creates git branches and store directories (multi-store)
- Optionally installs commitlint, Husky, and the Cursor skill
Add a new store to an existing setup.
npx climaybe add-store- Prompts for new store URL + alias
- Creates
staging-<alias>andlive-<alias>branches - Creates
stores/<alias>/directory structure - If store count goes from 1 to 2+, automatically migrates from single to multi-store mode
Switch your local dev environment to a specific store (multi-store only).
npx climaybe switch voldt-norwayCopies stores/<alias>/ JSON files to the repo root so you can preview that store locally.
Sync root JSON files back to a store directory (multi-store only).
npx climaybe sync voldt-norwayIf no alias is given, syncs to the default store.
Create missing staging and per-store branches (staging-<alias>, live-<alias>) from your current branch (usually main). Use when the repo only has main (e.g. after a fresh clone) so the main → staging-<store> sync can run.
npx climaybe ensure-branches
git push origin --allRefresh GitHub Actions workflows from the latest bundled templates.
npx climaybe update-workflowsUseful after updating the CLI to get the latest workflow improvements.
Set up only commitlint + Husky (conventional commits enforced on git commit). Use this if you skipped it at init or want to add it later.
npx climaybe setup-commitlintAdd only the Cursor commit skill to this project (.cursor/skills/commit/SKILL.md). Use this if you skipped it at init or want to add it later.
npx climaybe add-cursor-skillThe CLI writes config into the config field of your package.json:
{
"config": {
"port": 9295,
"default_store": "voldt-staging.myshopify.com",
"preview_workflows": true,
"build_workflows": true,
"commitlint": true,
"cursor_skills": true,
"stores": {
"voldt-staging": "voldt-staging.myshopify.com",
"voldt-norway": "voldt-norway.myshopify.com"
}
}
}Workflows read this config at runtime — no hardcoded values in YAML files.
staging → main
staging— development branchmain— production branch
staging → main → staging-<store> → live-<store>
staging— development branchmain— shared codebase (not live)staging-<store>— per-store staging with store-specific JSON datalive-<store>— per-store production
Direct pushes to staging-<store> or live-<store> are automatically synced back to main (no PR; multistore-hotfix-to-main merges the branch into main).
| Workflow | Purpose |
|---|---|
ai-changelog.yml |
Reusable workflow. Sends commits to Gemini API, returns classified changelog. |
version-bump.yml |
Reusable workflow. Bumps version in settings_schema.json, creates git tag. |
| Workflow | Trigger | What it does |
|---|---|---|
release-pr-check.yml |
PR from staging to main |
Finds latest tag on main, AI changelog to PR head, creates pre-release patch tag (e.g. v3.1.13) to lock state; posts changelog comment |
post-merge-tag.yml |
Push to main (merged PR) |
Staging→main only: minor bump from latest tag (e.g. v3.1.13 → v3.2.0). No version in PR title |
nightly-hotfix.yml |
Cron 02:00 US Eastern | Collects commits since latest tag (incl. hotfix backports), AI changelog, patch bump and tag |
| Workflow | Trigger | What it does |
|---|---|---|
main-to-staging-stores.yml (main-to-staging-<store>) |
Push to main |
Merges main into each staging-<alias>; root JSONs ignored. For hotfix-backport, skips the store that sent the hotfix; other stores get the merge. Skips only on pure store-sync. |
stores-to-root.yml |
Push to staging-* |
From main merge: stores→root. From elsewhere (e.g. Shopify): root→stores |
pr-to-live.yml |
After stores-to-root | Opens PR from staging-<alias> to live-<alias> |
root-to-stores.yml |
Push to live-* |
From main merge: stores→root. From elsewhere: root→stores (same as stores-to-root on staging-*) |
multistore-hotfix-to-main.yml |
Push to staging-* or live-* (and after root-to-stores) |
Merges store branch into main (no PR). Skips when push is a merge from main (avoids loop) |
Enabled via climaybe init prompt (Enable preview + cleanup workflows?; default: yes).
| Workflow | Trigger | What it does |
|---|---|---|
pr-update.yml |
PR opened/synchronize/reopened (base: main, staging, develop, staging-, live-) | Shares draft theme, renames with -PR<number>, comments preview + customize URLs; uses default store for main/staging/develop, or the store for staging-<alias>/live-<alias> |
pr-close.yml |
PR closed (same branch set) | Deletes matching preview themes and comments deleted count + names |
reusable-share-theme.yml |
workflow_call | Shares Shopify draft theme and returns theme_id |
reusable-rename-theme.yml |
workflow_call | Renames shared theme to include PR<number> (fails job on rename failure) |
reusable-comment-on-pr.yml |
workflow_call | Posts preview comment including Customize URL |
reusable-cleanup-themes.yml |
workflow_call | Deletes preview themes by PR number and exposes cleanup outputs |
reusable-extract-pr-number.yml |
workflow_call | Extracts padded/unpadded PR number outputs for naming and API-safe usage |
Enabled via climaybe init prompt (Enable build + Lighthouse workflows?; default: yes).
| Workflow | Trigger | What it does |
|---|---|---|
build-pipeline.yml |
Push to main/staging/develop |
Runs reusable build and Lighthouse checks (when required secrets exist) |
reusable-build.yml |
workflow_call | Runs Node build + Tailwind compile, then commits compiled assets when changed |
create-release.yml |
Push tag v* |
Builds release archive and creates GitHub Release using release-notes.md |
- Version format: Always three-part (e.g.
v3.2.0). No version in code or PR title; the system infers from tags. - No tags yet? The system uses
theme_versionfromconfig/settings_schema.json(theme_info), creates that tag on main (e.g.v1.0.0), and continues from there. - Staging → main: On PR, a pre-release patch tag (e.g. v3.1.13) locks the current minor line; on merge, minor bump (e.g. v3.1.13 → v3.2.0).
- Non-staging to main (hotfix backports, direct commits): Patch bump only, via nightly workflow at 02:00 US Eastern (not at commit time).
- Version bump runs only on main (post-merge-tag and nightly-hotfix). Main-to-staging-stores merges main into each
staging-<alias>on every push (version bumps and hotfixes). When the push is a hotfix from one store (e.g. live-norway), that store’s staging branch is skipped; other stores’ staging branches still get the merge. - Version bumps update
config/settings_schema.jsonand, when present,package.jsonversion.
Full specification: For detailed versioning rules, local dev flow, hotfix behavior, and alignment with the external CI/CD doc, see CI/CD Reference.
Synced between root and stores/<alias>/:
config/settings_data.jsontemplates/*.jsonsections/*.json
NOT synced (travels via branch history):
config/settings_schema.jsonlocales/*.json
- Hotfix sync merge commits (multistore-hotfix-to-main) contain
[hotfix-backport]in the message - Store sync commits contain
[stores-to-root]or[root-to-stores] - Version bump commits contain
chore(release): bump version - All workflows check for these flags and skip accordingly
Add the following secrets to your GitHub repository (or use GitLab CI/CD variables if you use GitLab). You can configure them during climaybe init via the GitHub or GitLab CLI.
| Secret | Required | Description |
|---|---|---|
GEMINI_API_KEY |
Yes | Google Gemini API key for changelog generation |
SHOPIFY_STORE_URL |
Set from config | Store URL is set automatically from the store domain(s) you add during init (no prompt). |
SHOPIFY_THEME_ACCESS_TOKEN |
Yes* | Theme access token for preview workflows (required when preview is enabled). |
SHOP_ACCESS_TOKEN |
Optional* | Required only when optional build workflows are enabled (Lighthouse) |
LHCI_GITHUB_APP_TOKEN |
Optional* | Required only when optional build workflows are enabled (Lighthouse) |
SHOP_PASSWORD |
Optional | Used by Lighthouse action when your store requires password auth |
Store URL: During climaybe init (or add-store), store URL secret(s) are set from your configured store domain(s); you are only prompted for the theme token.
Multi-store: Per-store secrets SHOPIFY_STORE_URL_<ALIAS> and SHOPIFY_THEME_ACCESS_TOKEN_<ALIAS> — the URL is set from config; you must provide the theme token per store. <ALIAS> is uppercase with hyphens as underscores (e.g. voldt-norway → SHOPIFY_STORE_URL_VOLDT_NORWAY). Preview and cleanup: for PRs targeting main, staging, or develop the workflows use the default store (from config.default_store or first in config.stores); for PRs targeting staging-<alias> or live-<alias> they use that store’s credentials. Set either the plain SHOPIFY_* secrets or the _<ALIAS> pair for each store you use in preview.
├── assets/
├── config/
├── layout/
├── locales/
├── sections/
├── snippets/
├── templates/
├── stores/
│ ├── voldt-staging/
│ │ ├── config/settings_data.json
│ │ ├── templates/*.json
│ │ └── sections/*.json
│ └── voldt-norway/
│ ├── config/settings_data.json
│ ├── templates/*.json
│ └── sections/*.json
├── package.json
└── .github/workflows/
- Branch: Single default branch
main. Feature branches open as PRs intomain. - Versioning: SemVer. Versions are bumped automatically when PRs are merged to
mainusing conventional commits:fix:→ patch,feat:→ minor,BREAKING CHANGEorfeat!:→ major. - Flow: Merge to
main→ Release version runs semantic-release (bumpspackage.json, pushes tag) → tag push triggers Release (tests + publish to npm). RequiresNPM_TOKENsecret for npm publish. Do not create tags manually; only the Release version workflow creates tags so that tag and package version stay in sync. - CI: Every PR and push to
mainruns tests on Node 20 and 22 (CI workflow).
See CONTRIBUTING.md for branch, PR, and conventional-commit details.
MIT — Electric Maybe