Claude Code Hooks & the Feature Pipeline
TL;DR: A gated, multi-phase pipeline that turns a Figma frame into a reviewed, QA’d theme feature — built from hooks, a coordinator command, and a dedicated builder subagent.
/figma-to-feature is Solis’s one real command, and this page covers the full pipeline built around it: a coordinator command, a dedicated builder subagent, two hooks, a plan template, and a small on-disk state directory, six pieces working together. The result is a pipeline that refuses to write any theme file until a human has explicitly approved a written plan, builds one reviewable phase at a time, and runs real QA (static check, storefront render, theme editor) before calling a feature done.
This setup was built by the team for this exact repo, not by this handbook. The rest of this page documents what it does, verifies the pieces that could be checked against live sources, and flags the couple of things worth reconciling with the rest of this handbook before you rely on it.
Why this is heavier than a plain command
Section titled “Why this is heavier than a plain command”Claude Code Custom Commands also offers /figma-to-liquid, a lighter, illustrative template of a single command that would run a whole plan → build → check → fix → report loop inline, not something Solis has adopted. It’s a useful point of comparison for understanding why /figma-to-feature is built the way it is: for something bigger or riskier than ordinary component work, you want a hard stop on before any code lands, work split into several reviewable chunks, and QA (storefront render at four breakpoints, theme editor block behavior, keyboard/focus) folded into the same run instead of a separate manual pass.
A plain command (illustrated by the /figma-to-liquid template) | /figma-to-feature (Solis’s real pipeline) | |
|---|---|---|
| Runs as | One command, inline | A coordinator command that dispatches a subagent per phase |
| Plan approval | Implicit — the command states its plan back as it goes | Explicit and enforced by a hook. Nothing can be written to sections/, blocks/, snippets/, or assets/ until a plan file literally says Status: approved |
| Build unit | The whole feature, one pass | One numbered phase at a time, each with its own review checkpoint |
| QA | shopify theme check, fixed inline or handed to a subagent | Static check, plus a live storefront render (Playwright) at 375/768/1280/1920, plus a live theme editor pass, plus /code-review on the full diff, plus a written qa-report.md |
| State | None persisted beyond the PR itself | .sol-workflow/{handle}/ — plan, progress log, and QA report, kept as a build record |
| Best for | A section, block, or snippet | A multi-part feature where you want a hard gate before code, and QA built into the same run |
Neither replaces GitHub Workflow review. Both still produce a PR a human reviews before merge.
The six pieces, at a glance
Section titled “The six pieces, at a glance”| Piece | Type | What it does | Download |
|---|---|---|---|
/figma-to-feature | Command | Coordinates the whole run: reads the design, writes the plan, dispatches each build phase, runs QA. Never writes theme files itself. | figma-to-feature.md |
sol-builder | Subagent | Executes exactly one approved phase per invocation, starting cold each time. | sol-builder.md |
require-plan.sh | Hook (PreToolUse) | Blocks writes to theme component folders until the plan says Status: approved. | require-plan.sh |
restore-index.sh | Hook (Stop, SessionStart) | Restores templates/index.json if a QA preview swap gets orphaned by an interrupted session. | restore-index.sh |
settings.json | Config | Wires both hooks to their events. | settings.json |
plan-template.md | Template | The document the command fills in and the hook checks for approval. | plan-template.md |
All six pieces already exist in Solis, committed at the paths above, since the moment you clone the repo, there’s nothing to set up. The download links are there for adapting this pipeline to a different repo: into .claude/ (commands/, agents/, hooks/, settings.json, and templates/ respectively), then make the hook scripts executable:
chmod +x .claude/hooks/require-plan.sh .claude/hooks/restore-index.shCommit all of it. Same reasoning as every other .claude/ file in this handbook: check it in, and the whole team gets the same gated pipeline the moment they clone the repo, instead of one person having a safety mechanism nobody else does.
How the pieces fit together
Section titled “How the pieces fit together”/figma-to-feature <figma-url> │ ▼Phase 0-1: read design, ask instructions ──────────────────┐ │ │ ▼ │Phase 2: write .sol-workflow/{handle}/plan.md (Status: draft)│ │ │ ▼ │ ┌───────────────┐ user approves ┌──────────────────┐│ │ GATE: present │ ────────────────▶│ Status: approved ││ │ plan in chat │ └──────────────────┘│ └───────────────┘ │ │ ▼ │Phase 3: for each numbered phase in plan §7 ───────────────────┘ │ ├─ dispatch sol-builder (cold start, reads plan.md + AGENTS.md) ├─ require-plan.sh checks plan.md before every Write/Edit │ → blocks if Status isn't "approved" ├─ sol-builder calls validate_theme after every file └─ GATE: coordinator verifies, user reviews, confirms → next phase
Phase 4: QA (theme check → storefront render → theme editor → qa-report.md) │ ▼ GATE: present qa-report.mdPhase 5: close out, delete .sol-workflow/ACTIVE, summarizeThe hook is what makes the gate in Phase 2 real instead of aspirational. Without it, “wait for approval” is just an instruction the coordinator is trusted to follow. With it, an attempt to write to sections/, blocks/, snippets/, or assets/ while the plan still says draft is mechanically blocked, regardless of what the coordinator (or a distracted human mid-conversation) intends to do next.
.sol-workflow/: the state directory this all runs on
Section titled “.sol-workflow/: the state directory this all runs on”| Path | What it holds | Commit it? |
|---|---|---|
.sol-workflow/ACTIVE | The handle of the currently-in-progress run. Its mere existence is what arms require-plan.sh at all. | No. This is local, in-progress session state, not a team fact. Add it to .gitignore. |
.sol-workflow/{handle}/plan.md | The plan itself: front matter Status, the numbered phases, the progress log. | Yes. This is the build record /figma-to-code-workflow’s “Document” step asks for elsewhere in this handbook, just automated. |
.sol-workflow/{handle}/qa-report.md | What Phase 4 produces: pass/fail per check, what could only be verified manually. | Yes, same reasoning. |
.sol-workflow/config.json | The *.myshopify.com store domain, asked for once per repo. | Yes — it’s a domain, not a secret, and the whole point is asking once per repo instead of once per person. |
.sol-workflow/.index-backup.json | A temporary copy of templates/index.json, made during Phase 4’s live storefront QA and restored after. | No. Pure transient scratch state. restore-index.sh exists specifically to clean this up if a session dies before the normal restore step runs. |
None of .sol-workflow/ should reach a Theme Store submission. See “A gap this setup leaves in packaging” below — the existing exclusion list in this handbook didn’t cover this directory until this page added it.
The two hooks
Section titled “The two hooks”require-plan.sh — the actual enforcement
Section titled “require-plan.sh — the actual enforcement”Registered on PreToolUse for Write and Edit, matched in settings.json. Every time Claude attempts either tool, this script runs first:
- If
.sol-workflow/ACTIVEdoesn’t exist, exit immediately and allow the write. Outside an active/figma-to-featurerun, this hook is a total no-op — your normal, unguarded hand-editing of the theme is never affected. - Otherwise, read the attempted file path from the tool call (passed in as JSON on stdin) and check whether it falls inside
sections/,blocks/,snippets/, orassets/. Anything else is allowed through untouched. - For a write inside those folders, read the active run’s
plan.mdand check its front matter forStatus: approved. If it’s there, allow the write. If not, block it (exit code2) and print a message telling Claude exactly what’s missing and what plan file to check.
This is the concrete example behind AI Coding Concepts’s claim that a hook is the one mechanism on that page that can actually enforce a rule rather than just state it. Nothing about /figma-to-feature’s own instructions can be trusted alone to stop a premature write — the hook is what actually stops it.
restore-index.sh — cleanup for an interrupted QA run
Section titled “restore-index.sh — cleanup for an interrupted QA run”Registered on both Stop (end of session) and SessionStart (start of the next one). Phase 4’s live storefront QA temporarily replaces templates/index.json with a version containing only the section under test, so it renders in isolation at http://127.0.0.1:9292. The command’s own instructions say to restore the original file and delete the backup once QA finishes — but if the session ends before that happens (a crash, a closed terminal, hitting a usage limit mid-QA), the real templates/index.json would stay swapped out indefinitely. This hook checks for the backup file on every session boundary and puts the original back if it finds one, so a broken homepage template can’t silently survive past the session that caused it.
The /figma-to-feature command: six gated phases
Section titled “The /figma-to-feature command: six gated phases”The full command file is linear and worth reading in full (it’s short — download it), but the shape is:
- Phase 0 — Preflight. Checks for a resumable run first, then Figma access, then opens
.sol-workflow/{handle}/and writes the handle toACTIVE. This last step is what armsrequire-plan.sh. - Phase 1 — Read the design, then ask. Pulls desktop and mobile frames, summarizes in 10 lines or fewer, then asks a fixed four-question block (behavior, snippets/blocks to reuse, what should be a setting, what to leave out) before writing anything. GATE — waits for the answer.
- Phase 2 — Write the plan. Fills in
plan-template.md, leavesStatus: draft, and presents the whole thing in chat (not just a link to the file). GATE — waits for approval, and only the user’s explicit approval flips the front matter toStatus: approved. - Phase 3 — Execute, one phase at a time. For each numbered phase in the plan, dispatches
sol-builderwith just the plan’s path, the phase number, and anything the previous phase reported. The coordinator then runs thesol-shopify-reviewskill (see Shopify’s Official AI Toolkit for the skill mechanism, and the realsol-shopify-reviewskill itself, below) against every file the builder touched, instead of re-deriving the same checks by hand — an agent checking its own work has blind spots a second, independent pass catches. GATE after each phase. - Phase 4 — QA. Static check first (no store needed), then store access, then a live Playwright render at four breakpoints plus deliberately awkward content (zero blocks, max blocks, very long strings, a missing image), then a live theme editor pass through a browser-automation connection. Writes
qa-report.md. GATE — presents the report. - Phase 5 — Close out. Runs
/code-reviewagainst everything the whole run changed, pinned to a safe, non-ultralevel on purpose so a build never bills the user unexpectedly — this is the one point in the pipeline that runs a general code-quality pass across the whole diff, as opposed tosol-shopify-review’s narrower, this-theme’s-own-conventions check in Phase 3. Once the user gives the go-ahead, deletes.sol-workflow/ACTIVE(disarming the hook), confirmstemplates/index.jsonis back to normal, and summarizes every file touched..sol-workflow/{handle}/itself stays, as the permanent record of the run.
“Gate” isn’t a suggestion in this command’s own wording: it says explicitly that “the user will probably say yes” is not approval, and that gates are hard stops. That’s a deliberate, repeated instruction on top of the one gate (Status: approved) that’s actually hook-enforced — the others rely on the coordinator genuinely stopping, the same trust boundary every command in this handbook operates under.
The sol-builder subagent
Section titled “The sol-builder subagent”sol-builder executes exactly one numbered phase per invocation and nothing more, even with turns left. It’s dispatched fresh each time, with no memory of the conversation that wrote the plan — the plan file is its entire brief, which is why the command’s own rules insist on pasting the user’s instructions into the plan verbatim rather than summarizing them.
Its declared tools:
Read, Write, Edit, Glob, Grep, Bash, Skill,mcp__shopify-dev-mcp__learn_shopify_api,mcp__shopify-dev-mcp__validate_theme,mcp__shopify-dev-mcp__search_docs_chunksWe checked all three mcp__shopify-dev-mcp__* tools against Shopify’s current documentation while writing this page, since Shopify’s Official AI Toolkit had previously (and, as of this update, incorrectly) suggested the Dev MCP server didn’t cover Liquid at all. All three are real: learn_shopify_api (call first, generates a conversation ID), search_docs_chunks (broad documentation search), and validate_theme (validates an entire theme directory against Theme Check rules — and it’s on by default, no extra configuration needed). See that page’s updated section on this for the full correction and what’s still worth double-checking yourself.
Its startup order matters: learn_shopify_api first (once, mandatory), then the whole plan file (not just its own phase), then AGENTS.md’s “Project conventions” section — the whole file is short now, so this is a quick read, not a long reference lookup — then two existing components (blocks/text.liquid and blocks/group.liquid) as a style reference. It validates with validate_theme after every file, not batched at the end, and stops and reports rather than guessing if something in the plan turns out to be impossible as written, or if a file fails validation three times running. If the plan’s front matter doesn’t say Status: approved, it stops and reports that too, rather than relying only on the hook to catch it.
plan-template.md: the contract between coordinator and builder
Section titled “plan-template.md: the contract between coordinator and builder”This is the one document both halves of the pipeline read. The coordinator fills it in; require-plan.sh checks its front matter; sol-builder treats it as its entire brief. A few sections carry more weight than the others:
- §2, custom instructions — pasted verbatim from the user. The builder never sees the original conversation, so anything paraphrased away here is genuinely lost, not just abbreviated.
- §3, component breakdown — the setting-vs-block-vs-snippet-vs-hardcoded decision this handbook’s Figma to Code Workflow also treats as the highest-stakes call in the whole process, here made explicit and justified in writing before any code exists.
- §4, settings and §5, translation keys — also read in full by
sol-builder, since a phase it’s building might depend on a setting or locale key a different phase introduced. - §7, build steps — 3 to 5 of them, each small enough to review in one sitting, foundations (translation keys) first and the section itself last before QA.
- §9, things that might not match
AGENTS.md’s rules exactly — specific to this build, not a copy of anything from elsewhere. There’s no separate “repo ground truth” file this gets pulled from; it’s written fresh, in the plan itself, for whatever this particular build actually needs flagged.
One thing worth knowing, one thing still worth reconciling
Section titled “One thing worth knowing, one thing still worth reconciling”Figma tool names: settled, for Solis. /figma-to-feature calls Figma’s tools by names like mcp__plugin_figma_figma__get_metadata. That naming pattern comes from installing Figma’s official Claude Code plugin (claude plugin install figma@claude-plugins-official), which namespaces its tools by plugin name — and that’s confirmed as Solis’s actual setup: .claude/settings.json’s enabledPlugins has figma@claude-plugins-official enabled project-wide, not a Figma entry in .mcp.json. Figma MCP & Dev Mode recommends the committed .mcp.json route as a default for teams in general, which would instead register the server as plain figma, giving tool names like mcp__figma__get_metadata. That’s not what Solis does, so if you’re adapting the command file for a different repo that uses the .mcp.json route, the tool names need to change accordingly — they’re two different, non-interchangeable names for reaching the same underlying get_metadata tool.
The sol- class and custom-property prefix still isn’t in this handbook’s CSS naming page. AGENTS.md’s “Project conventions” enforces .sol-{block}__{element}--{modifier} classes and --sol-* custom properties as a hard rule, and it’s genuinely live: every real component in sections/, blocks/, and snippets/ follows it. CSS Architecture, Naming & Logical Properties currently documents the same BEM-ish, kebab-case shape but without the project-wide prefix in its examples — that page is the one behind here, not sol-builder.md or AGENTS.md.
A gap this setup leaves in packaging
Section titled “A gap this setup leaves in packaging”.sol-workflow/ is a new repo-root directory this pipeline introduces, and it wasn’t in this handbook’s Theme Store exclusion list until this page. Add it to .shopifyignore alongside the other dev-tooling entries covered in Packaging: Theme Store-Only Directories:
.sol-workflow/None of .sol-workflow/’s content, plan files, QA reports, or state, is theme code. It should never reach a submission zip, the same as .claude/ itself.
Do / Don’t
Section titled “Do / Don’t”| ✅ Do | ❌ Don’t |
|---|---|
Commit all six pieces (.claude/commands/figma-to-feature.md, .claude/agents/sol-builder.md, both hooks, settings.json, plan-template.md) so the whole team gets the same gated pipeline, not just whoever built it. | Treating a PreToolUse hook’s block as a bug and working around it, instead of writing the plan and getting it approved. The hook is doing exactly its job — see require-plan.sh above. |
Let /code-review run automatically at Phase 5 wrap-up, at its safe default level. | Running /code-review ultra yourself right before a /figma-to-feature run finishes, then letting the bare /code-review at wrap-up silently reuse that billed level. Type a specific level if you’re not sure what’s currently set. |
Reach for /figma-to-feature when you specifically want the hard pre-code gate and built-in QA. Default to the lighter /figma-to-liquid template (not something Solis has adopted, see Claude Code Custom Commands) for ordinary section/block/snippet work, if you ever do add it. | Assuming this pipeline is a strict upgrade over a plain command for every job. It’s heavier for a reason. A one-off snippet doesn’t need a gated, multi-phase build with a written QA report. |
Add .sol-workflow/ACTIVE and .sol-workflow/.index-backup.json to .gitignore, but commit .sol-workflow/{handle}/plan.md and qa-report.md as build records. | Assuming a different repo’s Figma tool names match Solis’s without checking. mcp__plugin_figma_figma__* only works if Figma MCP was installed via the plugin route, confirmed as Solis’s setup, but not necessarily true elsewhere. |
Add .sol-workflow/ to .shopifyignore too. It’s dev tooling, not theme code. | Forgetting .sol-workflow/ in .shopifyignore. It’s easy to overlook a directory this handbook didn’t previously ask you to exclude. |
Key takeaways
Section titled “Key takeaways”/figma-to-feature= coordinator command +sol-buildersubagent + two hooks + a plan template +.sol-workflow/state. Heavier than a plain command, worth it for a hard pre-code gate and integrated QA.- The gate is real because a
PreToolUsehook (require-plan.sh) blocks writes to theme folders until the plan saysStatus: approved— not because the command politely asks first. restore-index.shcleans up an orphaned QA preview swap on sessionStop/SessionStart, in case a run is interrupted mid-QA.sol-builder’s Dev MCP tools (learn_shopify_api,validate_theme,search_docs_chunks) are all real and verified —validate_themeis on by default.- Phase 3 runs the
sol-shopify-reviewskill as its independent check; Phase 5 runs/code-review(pinned to a safe level) against the whole diff before handing off for a PR — two different, complementary checks, not the same thing twice. - Figma tool naming is settled for Solis (the plugin route, confirmed via
.claude/settings.json). Still open: thesol-prefix convention isn’t yet documented on this handbook’s CSS naming page. - Add
.sol-workflow/to.shopifyignore— it wasn’t covered before this page.
Further reading
Section titled “Further reading”- AI Coding Concepts — what a hook is, and the other five mechanisms this pipeline builds on
- Claude Code Custom Commands — the lighter
/figma-to-liquidtemplate, not adopted by Solis - Claude Code Subagents — the subagent mechanism
sol-builderuses - Shopify’s Official AI Toolkit — the Dev MCP tools
sol-buildercalls, and Solis’s ownsol-shopify-reviewskill - Figma MCP & Dev Mode — Solis’s actual Figma install method versus this page’s general recommendation
- Managing & Amending AI Rules — the maintenance discipline for
AGENTS.md’s “Project conventions” section - Hooks reference (code.claude.com)