climaybe
v3.2.0
Published
Shopify CLI by Electric Maybe for theme CI/CD workflows, branch orchestration, app setup, and dev tooling
Maintainers
Readme
climaybe
Shopify CLI for theme CI/CD (GitHub Actions, branches, multi-store config) and light app repo setup. Same install works in theme or app repositories.
Built by Electric Maybe — a Shopify-focused product and development studio.
Commit linting and Cursor bundle (optional in both flows):
- Conventional commit linting: During
climaybe theme initorclimaybe app init, you can install commitlint and Husky for Conventional Commits. - Cursor bundle (rules + skills + subagents): Opt in to Electric Maybe’s bundled Cursor files under
.cursor/rules/,.cursor/skills/, and.cursor/agents/(themes, JS, a11y, commits, changelog, Linear, theme-translator for locale sync, etc.).
Command layout (Shopify CLI–style)
climaybe theme <command>— canonical commands for theme repos (workflows, stores, branches).- Same commands at the top level —
climaybe initis the same asclimaybe theme init(backward compatible). climaybe app init— app repos only: writesproject_type: "app"inclimaybe.config.json, optional commitlint + Cursor bundle. Does not install theme GitHub Actions or store/branch setup.climaybe setup-commitlintandclimaybe add-cursor— always at the top level (stack-agnostic).
Theme-only commands refuse to run when climaybe.config.json → project_type is app.
Install
cd your-shopify-theme-repo # or app repo
npm install -D climaybeRun commands with npx climaybe (or add scripts to your package.json).
When a newer climaybe is available, the CLI can prompt at startup to update. Press Enter to accept the update (npm install -g climaybe@latest) or type n to skip.
Quick Start (theme)
cd your-shopify-theme-repo
npm install -D climaybe
npx climaybe init
# equivalent: npx climaybe theme initThe interactive setup will ask for your store URL(s) and configure everything automatically.
Quick Start (app)
cd your-shopify-app-repo
npm install -D climaybe
npx climaybe app initInstalls optional commitlint/Husky and the Cursor bundle (rules, skills, agents). Use Shopify CLI for app development and deployment.
Commands
climaybe init / climaybe theme init
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 install the Cursor bundle (
.cursor/rules/,.cursor/skills/,.cursor/agents/) — Electric Maybe conventions for themes and AI workflows - Based on store count, sets up single-store or multi-store mode
- Writes
climaybe.config.json - Scaffolds GitHub Actions workflows
- Creates git branches and store directories (multi-store)
- Optionally installs commitlint, Husky, and the Cursor bundle (rules, skills, agents)
climaybe app init
Interactive setup for a Shopify app repository: optional commitlint + Husky, optional Cursor bundle, and project_type: "app" in package.json config. No theme workflows, stores, or staging/live branches.
climaybe add-store / climaybe theme add-store
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
climaybe switch <alias> / climaybe theme switch
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, and sets default_store in climaybe.config.json so climaybe serve / shopify theme dev targets that store. If your current git branch is staging-<alias> or live-<alias>, climaybe serve uses that store’s domain from config (even if default_store differs), matching CI preview behavior.
climaybe sync [alias] / climaybe theme sync
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.
climaybe ensure-branches / climaybe theme ensure-branches
Create missing branches from your current branch (usually main). In single-store mode, this creates staging only. In multi-store mode, this creates staging plus per-store branches (staging-<alias>, live-<alias>). Use when the repo only has main (e.g. after a fresh clone) so the configured sync flow can run.
npx climaybe ensure-branches
git push origin --allclimaybe update / climaybe theme update
Refresh all climaybe-managed project files from your installed CLI version:
- GitHub workflows
- root dev-kit files (
.theme-check.yml,.shopifyignore,.prettierrc,.lighthouserc.js,.gitignore) package.jsonmanaged deps (climaybe,tailwindcss)- optional
.vscode/tasks.json(if enabled) - optional commitlint + Husky files (if enabled)
- optional Cursor bundle files (if enabled)
npx climaybe updateupdate-workflows still works as a backward-compatible alias.
climaybe setup-commitlint
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-commitlintclimaybe add-cursor
Install Electric Maybe Cursor rules, skills, and subagents into .cursor/rules/, .cursor/skills/, and .cursor/agents/ (including theme-translator for theme/locales/). Use this if you skipped the bundle at init or want to refresh from the version of climaybe you have installed.
npx climaybe add-cursorThe previous command name add-cursor-skill still works as an alias. Re-running replaces the bundled rules, skills, and subagent files with the copies shipped by your installed climaybe version (same idea as update).
Configuration
The CLI writes config into climaybe.config.json:
{
"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.
Branch Strategy
Single-store
staging → mainstaging— development branchmain— production branch
Multi-store
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).
Workflows
Shared (both modes)
| 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. |
Single-store
| 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), ignores no-op/empty-tree commits, generates AI changelog, patch bump and tag |
Multi-store (additional)
| 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. Skips no-op sync when branch tree already matches main. For hotfix-backport: if source is staging-<alias>, that same staging branch is skipped; if source is live-<alias>, staging-<alias> is also synced. 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) and skips no-op backports when source and main trees are identical |
Optional preview + cleanup package
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>. Path filter: runs only when the PR changes theme paths (assets/, blocks/, config/, layout/, locales/, sections/, snippets/, templates/, _scripts/, _styles/, shopify.theme.toml, stores/**); docs-only or tooling-only PRs skip preview work. |
| 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 |
Optional build + Lighthouse package
Enabled via climaybe init prompt (Enable build + Lighthouse workflows?; default: yes).
When enabled, builds are resilient:
- If
_scripts/*.jsor_styles/main.cssare missing, the build workflow skips those steps and continues. initmay offer to create entrypoints; default answer is No.- Script bundling preserves comments/spacing and emits bundles only for root entry files (files imported by other top-level
_scripts/*.jsare inlined, not emitted separately). - Script bundles are written to
assets/*.js(readable by default; useclimaybe build-scripts --minifyif you want minified output). - Live minified
assets/*changes are intentionally excluded from hotfix backports tomain(no branch-specific.gitignoresplit required).
Build workflows install deps with npm ci and run npx --no-install climaybe build-scripts plus npx --no-install climaybe build, so CI uses lockfile-pinned versions (no @latest drift).
| Workflow | Trigger | What it does |
|----------|---------|-------------|
| build-pipeline.yml | Push to any branch (ignores docs-only/tooling-only paths; see CI/CD reference) | Runs reusable build; skips entirely on live-* when the pusher is a GitHub [bot] user; Lighthouse only on branch staging, when a build ran, and secrets allow |
| reusable-build.yml | workflow_call | Path-filtered build-scripts / Tailwind (climaybe build), then commits compiled assets when changed |
| create-release.yml | Push tag v*, or workflow_run after Post-Merge Tag / Nightly Hotfix Tag succeed on main | Builds release archive and creates GitHub Release notes from commits since the previous tag. It filters repetitive automation subjects (main→staging syncs, store/root sync chores, bot merge noise) before generating notes. If remaining subjects are low-signal and GEMINI_API_KEY exists, it uses Gemini to generate cleaner merchant-facing notes. Also covers tags created by workflows with GITHUB_TOKEN, which may not trigger tag-push workflows. |
Optional theme dev kit package
During climaybe init, you can enable the Electric Maybe theme dev kit (default: yes). This installs local
dev config defaults (.theme-check.yml, .shopifyignore, .prettierrc,
.lighthouserc.js), writes climaybe.config.json, appends a managed .gitignore block, and optionally adds
.vscode/tasks.json (default: yes) wired to run climaybe dev commands.
Local serve commands keep Theme Check disabled by default for faster startup. Enable it explicitly with
climaybe serve --theme-check or climaybe serve:assets --theme-check.
You can create optional build entrypoints later with:
climaybe create-entrypoints
If these files already exist, init warns that they will be replaced.
Section schema builder
Build Shopify section schemas dynamically from JavaScript or JSON files using climaybe build-schemas. Works directly in sections/ — no separate source folder, no sync issues with the theme editor.
How it works: Add an inline-comment marker at the end of any sections/*.liquid or blocks/*.liquid file. Shopify treats {% # ... %} as a comment and ignores it. The builder finds the marker, resolves the schema from _schemas/, and writes the generated {% schema %}...{% endschema %} block below it. The marker is never removed, so rebuilds always work — even after Shopify theme editor edits.
<section class="hero">{{ section.settings.title }}</section>
{% # schema 'hero-banner' %}
{% schema %}
{
"name": "Hero Banner",
"settings": [...]
}
{% endschema %}On rebuild, only the generated {% schema %} block is replaced. Everything above the marker (including theme editor changes) is preserved.
Supported patterns:
- Shared schemas — one schema file reused across multiple sections
- Partials —
require()shared settings arrays into multiple schemas - Common fieldsets — spread partial arrays into settings (
...linkSettings) - Looping fieldsets — factory functions that generate repeated field groups
- Section-specific overrides — export a function receiving
(filename, inlineContent)to customise per section - Inline JSON overrides — add
{% # { "name": "Custom" } %}below the marker
npx climaybe build-schemas # generate schemas in sections/
npx climaybe build-schemas --dry-run # preview without writing files
npx climaybe build-schemas --list # list schema files and markersSchemas also rebuild automatically during climaybe serve and climaybe serve:assets — the watcher monitors _schemas/ for changes and rebuilds on save, tagged [schema] in green. climaybe build includes schemas alongside scripts and Tailwind.
Example _schemas/hero-banner.js:
const createLinks = require('./partials/create-links');
module.exports = {
name: 'Hero Banner',
settings: [
{ label: 'Title', id: 'title', type: 'text' },
...createLinks(2)
]
};Full examples: See Schema Builder Examples for working code covering every pattern.
You can install/update this later with:
climaybe add-dev-kit (or climaybe theme add-dev-kit)
Versioning
- 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). No-op/empty-tree commits are ignored.
- 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). For hotfix-backport, only astaging-<alias> -> mainsource skips syncing back to the same staging branch; alive-<alias> -> mainsource still syncs intostaging-<alias>. - Version bumps update
config/settings_schema.jsonand, when present,package.jsonversion. - Safety: The version-bump workflow fails if the new tag would not be strictly higher than the latest merged release tag (semver), so the release line cannot step backward.
Full specification: For detailed versioning rules, local dev flow, hotfix behavior, and alignment with the external CI/CD doc, see CI/CD Reference.
File Sync Rules (Multi-store)
Synced between root and stores/<alias>/:
config/settings_data.jsontemplates/*.jsonsections/*.json
NOT synced (travels via branch history):
config/settings_schema.jsonlocales/*.json
Recursive Trigger Prevention
- 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
GitHub Secrets
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 | Optional | Google Gemini API key for AI-generated release notes fallback |
| 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 | Optional* | Theme access token for preview workflows (needed only when you want preview theme publish/cleanup to run). |
| 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 |
Prompting behavior: During climaybe init (or add-store), every GitHub/GitLab secret prompt is skippable. Add values later in CI settings if you prefer.
Store URL: During climaybe init (or add-store), store URL secret(s) are set from your configured store domain(s); theme tokens are optional prompts.
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.
Directory Structure (Multi-store)
├── 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
├── _schemas/ (optional: JS/JSON schema definitions for build-schemas)
│ ├── hero-banner.js
│ └── partials/
│ └── link.js
├── package.json
└── .github/workflows/Releases and versioning
- 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, creates GitHub Release notes, publishes to npm, pushes tag). Optional: tag push runs Verify release tag for an extra test pass and tag vspackage.jsoncheck (no publish). We publish to npmjs.com only (not GitHub Packages). Prefer npm Trusted Publisher (workflow filerelease-version.yml) so no long-livedNPM_TOKENis needed for CI; see CONTRIBUTING.md. 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.
License
MIT — Electric Maybe
