CLI Tool

Theme Factory Docs

Complete reference for the Theme Factory CLI — installation, commands, task format, super agent, and TF rules.

Prerequisites

ToolVersionPurpose
Node.js> 20Runtime for the pipeline
Shopify CLILatestTheme pushing and validation
GitAnyRepo cloning and branch management (only for # GIT repo tasks — not needed for local # Project Name runs)
ClaudeSee belowPowers all AI agents

Claude Authentication

Theme Factory agents run via the Claude Agent SDK. You need one of:

  • Local (recommended): Claude Code installed and logged in — uses your Claude subscription
  • Cloud / CI: Set the ANTHROPIC_API_KEY environment variable — uses API billing
terminal
$ claude login

Shopify CLI

Install and authenticate the Shopify CLI:

terminal
$ npm install -g @shopify/cli
$ shopify auth login --store your-store.myshopify.com

Git Access

Your machine needs SSH or HTTPS access to the GitHub repos you'll be working with. The pipeline clones repos via the URL in your input file.

Git is only required for # GIT repo tasks. If your task uses # Project Name instead, the run is fully local — no clone, branch, commit, or push — and no Git access is needed. See Git repo vs. local project.

Installation

Follow the installation guide or ask Jarvis for help:

Verify installation:

terminal
$ tf --version
$ tf --help

Update to latest stable, or switch release channels:

terminal
$ tf update           # latest stable
$ tf update alpha     # latest alpha release
$ tf update beta      # latest beta release

Authentication

Google (Required)

Theme Factory requires Google authentication with an @anattadesign.com account. This is used for identity tracking and telemetry.

terminal
$ tf auth login

# Check status
$ tf auth status

# Logout
$ tf auth logout

Figma

Required for Figma-linked tasks. Run the OAuth flow once per user:

terminal
$ tf auth figma

This opens your browser to authorize Theme Factory with your Figma account. Tokens auto-refresh — no manual renewal needed.

Shopify Store Access

Required for each Shopify store you work with. No tokens to copy — just install the app and register your email:

  1. Install the Theme Factory app — Open the Theme Factory install link in your browser and follow the prompts to install the app on your store.
  2. Add your email — Once installed, open the app's home page in your Shopify admin and add the email you use with Theme Factory. That's it — the CLI is now authorized to work with this store.

Pre-flight check: The pipeline aborts early if a task references a Figma link without Figma auth, or a Shopify store where the Theme Factory app isn't installed for your email.

First Run

1. Create an Input File

Create a markdown file anywhere on your machine:

my-first-task.md
# GIT repo
https://github.com/your-org/your-theme.git

# Store
your-store.myshopify.com

# Task ID
my-first-task

# Theme Base
Horizon

# Task
Build a hero banner section with a background image,
headline, and CTA button.

No Git repo? Swap the # GIT repo section for a # Project Name to run fully locally — no clone, branch, commit, or push (Shopify push still works):

my-first-task.md
# Project Name
my-first-task

# Store
your-store.myshopify.com

# Theme Base
Horizon

# Task
Build a hero banner section with a background image,
headline, and CTA button.

2. Run the Pipeline

terminal
# Full run — builds, commits, pushes to GitHub + Shopify
$ tf run ./my-first-task.md

# Local only — skip pushing
$ tf run ./my-first-task.md --no-push

# Preview with `shopify theme dev`, then confirm before pushing to Shopify
$ tf run ./my-first-task.md --local

3. Check the Output

  • Logs: A log file is created next to your input file
  • Git: Changes committed on a feature branch (skipped for # Project Name runs)
  • Shopify: Theme pushed as unpublished (unless --no-push or --local)
002

Quick Reference

terminal
# Authenticate
$ tf auth login
$ tf auth figma

# Run pipeline
$ tf run my-task.md
$ tf run my-batch/ --from 2 --to 4

# Interactive super agent
$ tf chat --latest
$ tf chat --repo my-store-theme
$ tf chat --repo 3

# Split large tasks
$ tf split my-task.md
$ tf split my-task.md --text

# Push changes
$ tf push git my-repo
$ tf push shopify my-repo --store my-store.myshopify.com

# List repos & history
$ tf list
$ tf list my-repo
$ tf list my-repo --logs

# Revert last run
$ tf revert --latest

# Clear session memory or Figma cache
$ tf clear memory --latest
$ tf clear figma --latest

# Delete a repo
$ tf delete my-repo --hard

# Audit & auto-fix translation keys
$ tf translations my-repo
$ tf translations my-repo --fix

# Update CLI (optionally pick a channel)
$ tf update
$ tf update alpha
$ tf update beta

# Manage optional plugins
$ tf plugin list
$ tf plugin install website-flow
$ tf plugin uninstall website-flow

tf auth

Authenticate with external services.

tf auth login

Sign in via Google OAuth. Restricts to @anattadesign.com accounts. Also registers with the TF backend for run telemetry.

terminal
$ tf auth login

tf auth status

Show current Google authentication status.

terminal
$ tf auth status

tf auth logout

Clear stored Google authentication.

terminal
$ tf auth logout

tf auth figma

Run the Figma OAuth flow. Opens your browser to authorize Theme Factory with your Figma account. Tokens auto-refresh — no manual renewal needed.

terminal
$ tf auth figma

tf run

Execute a task file or batch directory through the full agent pipeline.

usage
tf run <file-or-dir> [options]
OptionRequiredDescription
<path>YesInput markdown file or split directory
--input <path>NoAlias for the positional argument
--branch <name>NoOverride git branch
--no-pushNoSkip GitHub and Shopify push
--localNoPreview the built theme locally with shopify theme dev, then confirm before pushing to Shopify
--no-shopify-pullNoSkip syncing customizer changes before agents start
--from <N>NoStart from sub-task N (batch mode only)
--to <N>NoStop after sub-task N (batch mode only)
--restartNoForce fresh start, ignore previous session state
--interactiveNoReview and approve the plan before development starts
--show-browserNoShow the browser window during website captures (slow-mo enabled, cache bypassed) — for debugging

Single vs Batch mode is auto-detected: a file runs in single mode, a directory runs in batch mode (sub-tasks sequentially).

Batch Mode

Point tf run at a folder and it will execute every task file inside, one by one, through the full agent pipeline. Useful for splits generated by tf split, or any directory of related task files you want to run as a sequence.

  • File selection — all .md files in the directory are picked up (non-recursive).
  • Order — files are sorted alphabetically by filename, so prefixes like 01-, 02-, 03- determine execution order. Name your files accordingly.
  • Sequential — each sub-task runs to completion before the next one starts. A failure halts the batch.

Use --from and --to to run a slice of the batch (1-indexed, inclusive on both ends):

terminal
# Run every task in the folder, in alphabetical order
$ tf run ./my-batch/

# Run only sub-tasks 2 through 4
$ tf run ./my-batch/ --from 2 --to 4

# Start from sub-task 3 and continue to the end
$ tf run ./my-batch/ --from 3

# Run from the beginning up to and including sub-task 5
$ tf run ./my-batch/ --to 5

Auto-resume — In batch mode, completed sub-tasks are tracked. Re-running the same directory skips completed tasks. Use --from 1 to force a full restart.

Debugging website captures

If a website capture step (click, wait_for, etc.) isn't doing what you expect, run with --show-browser:

terminal
$ tf run ./my-task.md --show-browser

This launches a visible Chromium window with slowMo: 250 so you can watch each step execute. The website cache is bypassed in this mode so captures always re-run. Useful for diagnosing whether a third-party widget (e.g. a Rebuy cart drawer) is responding to clicks or being blocked by anti-bot detection.

Interactive Mode

When --interactive is set, the pipeline pauses after the Analyzer Agent creates the implementation plan. You can review and provide feedback before development begins.

terminal
$ tf run ./my-task.md --interactive

▶ Phase 2/4: Creating implementation plan...
✔ Plan created — 5 file changes (4m 46s)

📋 Plan Review
  Enter feedback to revise, or press Enter to approve.

Feedback> move the hero into a snippet instead
▶ Revising implementation plan (revision #1)...
✔ Plan revised — 6 file changes (45s)

Feedback>
✔ Plan approved — proceeding to development
  • Conversational revisions — each round continues the same session
  • Approve by pressing Enter, or typing approve, yes, ok, lgtm
  • Not available in batch mode

tf chat

Interactive super agent — a Claude session with full read/write access to your theme.

usage
tf chat [target] [options]
OptionDescription
--newStart a new task from scratch (generates task files)
--latestOpen super agent on the latest pipeline repo
--repo <name>Target a specific repo by name or number from tf list
--limit <n>How many recent tasks to show in the picker (default: 10)
--no-pushAuto-commit but ask before pushing to GitHub
<target>Repo name (positional, same as --repo)

By default, the agent automatically commits and pushes to GitHub after every change. Use --no-push to auto-commit but require confirmation before pushing.

terminal
# Super agent on the latest repo
$ tf chat --latest

# Target by name or number
$ tf chat --repo my-store-theme
$ tf chat --repo 3

# Show more recent tasks in the picker
$ tf chat --latest --limit 25

# Auto-commit, ask before push
$ tf chat --latest --no-push

# Create a new task file interactively
$ tf chat --new

tf split

Break a large task into ordered sub-tasks. Defaults to Figma-based splitting.

usage
tf split <file> [--figma|--text] [--new-theme]
OptionRequiredDescription
<file>YesMarkdown task file to split
--figmaNoFigma-based split (default) — fetches page structure from the Figma API
--textNoText-based LLM split — analyzes the task description with AI
--new-themeNoInclude style-guide + global-sections tasks (Figma mode only)

The split directory is created next to the input file. Inspect the generated tasks, then execute the batch:

terminal
$ tf split ./full-redesign.md
$ tf run full-redesign/

tf push

tf push git

Push workspace commits to GitHub.

usage
tf push git <repo> [--branch <name>]
tf push git --latest

tf push shopify

Push theme to a Shopify store. If a theme with the same name already exists, it updates it. Otherwise, it creates a new unpublished theme.

usage
tf push shopify <repo> --store <store> [--name <name>] [--publish]
tf push shopify --latest
OptionDescription
--store <store>Shopify store domain (auto-resolved with --latest)
--name <name>Display name on Shopify (default: repo name)
--publishPublish the theme. Without this flag, the theme is never published.
--latestUse the latest pipeline repo

tf translations

Audit translation key usage in a theme. Scans every .liquid file for {{ 'key' | t }} references, marks each as resolved against locales/en.default.json, and flags Liquid antipatterns that produce visible "Translation missing" errors on the storefront. With --fix, infers English defaults via LLM, rewrites the antipatterns, commits, pushes to git, and deploys to Shopify in one shot.

usage
tf translations <repo> [--missing] [--fix] [--store <store>] [--name <name>] [--no-shopify]
OptionDescription
<repo>Repo name or number from tf list
--missingShow only missing keys (skip resolved ones)
--fixAuto-fill missing keys, rewrite antipatterns, commit + push to git, deploy to Shopify
--store <store>Shopify store domain (overrides auto-resolved value from session metadata)
--name <name>Theme name on Shopify (overrides auto-resolved value, defaults to repo name)
--no-shopifySkip the Shopify deploy step (git push only)

What --fix does

  1. Rewrites | default: '...' | t antipatterns. The chain {{ section.settings.x | default: 'some.key' | t }} looks reasonable but is a bug: when the merchant has set the variable, its value (not the key) gets fed to | t, producing Translation missing: en.<value> on the storefront. Each occurrence is rewritten to an explicit if/else so the merchant's value is shown verbatim, falling back to the translated default only when blank. Deterministic — no LLM call.
  2. Fills missing keys by reading 2 lines of context around each | t reference, then asking the configured dev model for short English defaults. Output is cached to .tf-translations-cache.json before the merge so a failed write never costs you a second LLM call.
  3. Merges into locales/en.default.json while preserving CLDR pluralization objects ({ one: "...", other: "..." }) — these are recognized as already-present leaves rather than false-flagged as missing.
  4. Commits with a chore: prefix, pushes to the current git branch, and deploys to Shopify. Store and theme name are auto-resolved from the most recent session metadata — pass --store/--name to override, or --no-shopify to skip the deploy.
terminal
# Audit only — print the listing, no changes
$ tf translations my-store-theme

# Show only missing keys
$ tf translations my-store-theme --missing

# Full fix: rewrite antipatterns, fill missing keys, commit, push, deploy
$ tf translations my-store-theme --fix

# Repo number works too
$ tf translations 3 --fix

# Deploy to a different store than the last run used
$ tf translations my-store-theme --fix --store other-store.myshopify.com

# Local cleanup only — skip the Shopify deploy
$ tf translations my-store-theme --fix --no-shopify

tf list

List repos in the workspace, or show run history for a specific repo. Alias: tf ls

usage
tf list
tf list <repo>
tf list --latest
tf list <repo> --logs [N]
OptionDescription
(no args)List all repos in workspace
<repo>Show run history (name or number from tf list)
--latestShow run history for the last pipeline repo
--logs [N]View log file for run #N (default: latest)

tf delete

Delete a repo from the workspace. Accepts a repo name or number from tf list.

usage
tf delete <repo-or-number> [--hard]
OptionDescription
<repo-or-number>Repo name or number from tf list
--hardAlso delete session data and Figma cache

Without --hard, only the workspace folder is removed. Session data is preserved so you can re-clone and resume later.

tf revert

Undo the last pipeline run. Resets the branch to its pre-run state, then force-pushes to GitHub and re-pushes to Shopify if they were pushed in the original run.

usage
tf revert --latest [--no-push]
OptionDescription
--latestRequired — revert the most recent run
--no-pushRevert locally without pushing to GitHub/Shopify

Constraints:

  • Only the latest run can be reverted
  • Only one revert per run
  • Reverted runs appear dimmed in tf list output

tf clear

Clear session memory or Figma cache for a repo. Useful when agents are repeating mistakes from stale context, or when Figma designs have changed significantly.

usage
tf clear memory <repo-or-number>
tf clear memory --latest
tf clear figma <repo-or-number>
tf clear figma --latest
CommandDescription
tf clear memoryDeletes session memory and accumulated learnings for a repo
tf clear figmaClears cached Figma data (images, SVGs, component trees)

When to use:

  • Clear memory — when agents keep making the same mistakes based on stale learnings
  • Clear figma — when Figma designs have been updated and you need fresh data

tf update

Update Theme Factory to the latest version.

terminal
$ tf update

Pulls the latest published version. Valid tags: latest, alpha, beta.

terminal
$ tf update           # latest stable
$ tf update alpha     # latest alpha release
$ tf update beta      # latest beta release

tf plugin

Manage optional feature plugins. Each plugin installs its dependencies into an isolated ~/.theme-factory/plugins/<name>/ directory. See the Plugins page for the full list and what each one unlocks.

usage
tf plugin list
tf plugin install <name>
tf plugin uninstall <name>
tf plugin status [<name>]
Sub-commandDescription
listList available plugins and their install status
install <name>Install a plugin's dependencies (runs npm install + post-install steps)
uninstall <name>Remove an installed plugin's directory
status [<name>]Show install state for one or all plugins
terminal
$ tf plugin list
$ tf plugin install website-flow
$ tf plugin status website-flow
$ tf plugin uninstall website-flow

The plugin registry ships with tf source — run tf update to fetch newer plugins as they're added.

004

Task File Format

Tasks are defined as markdown files that tell the pipeline what to build. Each file uses # headings as section keys — ## and deeper are treated as body content within their parent section.

Required Sections

You must provide one of # GIT repo or # Project Name (see Git repo vs. local project below), plus a # Task.

SectionAliasesDescription
# GIT repo# Repo, # GitHub repo, # RepositoryGitHub repo URL (HTTPS). Cloned, branched, committed, and pushed as usual.
# Project Name# Project, # Workspace Name, # WorkspaceLocal-only alternative to a Git repo. The run happens entirely in a workspace folder of this name — no clone, branch, commit, or push. Provide this or # GIT repo.
# Task# DescriptionWhat to build or fix

Optional Sections

SectionAliasesDescription
# Store# Shopify storeShopify store domain
# Client# Client name, # Store URLClient identifier
# Theme Base# Base theme, # BaseBase theme to scaffold from (Dawn, Horizon). Supports Name => repo-url override syntax (see below)
# Figma# Figma linkFigma URLs (one per line)
# Task ID# TaskID, # IDUnique task identifier (defaults to the input filename)
# Theme Name# Theme, # Shopify Theme NameName for the Shopify theme (targets an existing theme by name, or names a new one)
# Theme ID# Theme-ID, # Shopify Theme IDNumeric Shopify theme ID to target directly. Takes precedence over # Theme Name if both are set. Omit both to create a new unpublished theme named [TF] <branch>.
# Git Branch# BranchBranch name (auto-generated if not set). Ignored in local-project mode.
# Base Branch# From BranchBranch to cut the new branch from (defaults to repo's default branch). Errors if it doesn't exist locally or on origin
# Difficulty# Task Difficulty, # Complexityeasy, medium (default), or hard — tunes how much effort agents spend
# Commit Message# Commit, # Commit MsgCustom description for the run's git commits (first line only — anything after it is ignored). It's inserted into the standard format theme-factory(<feature|fix>): <message> [iteration N]. When absent, the task text is used instead. Ignored in local # Project Name mode (no commits).
# Acceptance Criteria# Criteria, # ACBullet list the validator checks against
# Custom Font# Custom Fonts, # Font, # FontsPath to a font folder or individual font file
# References# Reference, # Reference ImagesLocal image paths fed to agents as visual references (label: path, path — caption, or bare path)
# Website Options# Website, # URL OptionsLive-site captures (screenshots + HTML) fed to agents — requires the website-flow plugin

Git repo vs. local project

Every task targets a working copy. There are two ways to define it, and you must use exactly one:

  • # GIT repo — the full Git-backed flow. The pipeline clones the repo, cuts a branch, syncs customizer changes from Shopify, commits the result, and pushes to both GitHub and Shopify.
  • # Project Name — a fully local run, no Git at all. The workspace is ~/.theme-factory/workspace/<project name> (no clone). All Git operations are skipped — no branch setup, commits, GitHub push, diff, or the Git-based Shopify customizer sync. A greenfield scaffold runs without the initial commit. The project name is used as the run label (telemetry, run-state id) and as the default Shopify theme name. Shopify push still works — set a # Store (and # Theme Name/# Theme ID) to deploy.
local-only.md
# Project Name
acme-landing

# Store
acme.myshopify.com

# Theme Base
Horizon

# Task
Build a seasonal landing page section with a hero, three
feature cards, and a newsletter signup.

If a file provides neither # GIT repo nor # Project Name, the parser aborts with a "missing required section" error.

Previewing a local run: tf serve requires a Git-backed workspace and will not preview a local-project run. To preview a # Project Name build before pushing, use tf run … --local instead.

Custom Theme Base Repo

If your team uses a modified version of a base theme (e.g., a cloned and customized Horizon), you can override the scaffolding repo while keeping the original theme's rules:

input.md
# Theme Base
Horizon => git@github.com:my-org/my-custom-horizon.git

This tells Theme Factory to:

  • Apply Horizon's theme rules (schema standards, block patterns, section conventions)
  • Scaffold from your custom repo instead of the official Horizon repository

Without the => override, the standard syntax still works:

input.md
# Theme Base
Horizon

Task Example

homepage-hero.md
# GIT repo
https://github.com/my-org/my-store.git

# Store
my-store.myshopify.com

# Theme Base
Horizon

# Task ID
homepage-hero

# Theme Name
My Store Theme

# Git Branch
feature/homepage-hero

# Task
Build a full-width hero banner section with:
- Background image from Figma
- Headline and subheadline text
- CTA button linking to a collection
- Mobile-responsive layout

Split Task Example

Same format, but with a larger # Task section. The task splitter decomposes it into sub-tasks automatically.

full-homepage.md
# GIT repo
https://github.com/my-org/my-store.git

# Store
my-store.myshopify.com

# Theme Base
Horizon

# Git Branch
feature/full-homepage

# Task
Build the complete homepage with these sections:

## Hero Banner
Full-width hero with background image, headline, CTA button.

## Featured Collections
Two collection cards side by side with product previews.

## Testimonials
Customer testimonial carousel with star ratings.

## Footer
Multi-column footer with newsletter signup form.

Figma Split Config

Used with tf split to auto-generate task files from a Figma design. Label each URL with Desktop or Mobile prefix for automatic pairing.

figma-config.md
# GIT repo
https://github.com/my-org/my-store.git

# Store
my-store.myshopify.com

# Theme Base
Dawn

# Task ID Prefix
MYSTORE

# Theme Name
my-store-redesign

# Git Branch
feature/full-redesign

# Figma
Desktop Homepage: https://figma.com/design/ABC123/...?node-id=10-100
Mobile Homepage: https://figma.com/design/ABC123/...?node-id=10-200
Desktop PLP: https://figma.com/design/ABC123/...?node-id=20-100
Mobile PLP: https://figma.com/design/ABC123/...?node-id=20-200
SectionRequiredDescription
# GIT repoYesGitHub repo URL
# Task ID PrefixYesPrefix for generated task IDs
# FigmaYesLabeled Figma URLs — Desktop/Mobile pairs

Figma URLs

Figma URLs can be provided in an explicit # Figma section (one URL per line), or inline in the # Task body (auto-extracted).

format
https://www.figma.com/design/<fileKey>/<fileName>?node-id=<nodeId>
  • With ?node-id= — fetches the specific node tree (recommended)
  • Without ?node-id= — fetches file-level overview (depth=2, no frame images)

URLs are deduplicated by fileKey:nodeId pair.

Website Options

When you want agents to reference a live site instead of (or in addition to) a Figma design — for example, when redesigning an existing storefront or porting another brand's layout — declare captures under # Website Options. Each capture launches a headless Chromium browser, navigates to the URL, runs a list of steps, and feeds the resulting screenshots + extracted HTML into the agent prompts.

Requires the website-flow plugin. Without it, tasks that use # Website Options abort with tf plugin install website-flow. See the Plugins page.

Format

A capture starts with a name on its own line ending with :. Indented keys configure it:

input.md
# Website Options
home-desktop:
  url: https://acme.com
  viewport: 1440
  steps:
    - wait: "main"
    - dismiss: "#cookie-banner .accept"
    - screenshot
    - extract

mobile-menu:
  url: https://acme.com
  viewport: 390
  steps:
    - click: "button#open-menu"
    - wait_for: "#mobile-menu.is-open"
    - screenshot: "menu-open"
    - extract: "#mobile-menu"

Capture Properties

KeyRequiredTypeDescription
<name>:YesstringCapture identifier (used as the screenshot label and shown in logs)
url:YesstringFull URL to navigate to
viewport:NointegerViewport width in pixels. Default: 1440
steps:NolistOrdered actions to run on the page. Default: wait body → screenshot → extract

Captures without a url: are silently dropped.

Step Actions

Each step is a bullet under steps:. Two forms are supported: - action (no argument) or - action: value. String values can be quoted with single or double quotes.

ActionFormDescription
wait- wait: <selector>Wait until the CSS selector appears in the DOM before continuing
wait_for- wait_for: <selector>Alias for wait
sleep- sleep: <ms>Hard pause for N milliseconds. Use sparingly — prefer wait/wait_for on a selector when possible
click- click: <selector>Click the matched element
hover- hover: <selector>Hover the matched element (triggers :hover styles, dropdowns, etc.)
fill- fill: "<selector>, <text>"Type text into an input. Comma separates selector from value
scroll- scroll: <pixels-or-bottom>Scroll to a pixel offset, or pass bottom to scroll to the page end
dismiss- dismiss: <selector>Click to close (cookie banners, modals). Use <iframe-selector> >>> <inner-selector> to pierce into an iframe
screenshot- screenshot or - screenshot: <label>Capture a full-page screenshot. With a label, the file is named accordingly
extract- extract or - extract: <selector>Extract HTML/text. Without a selector, captures the whole page; with one, scopes to that element

Steps that need a selector (wait, wait_for, click, hover, dismiss) are dropped if the value is missing. Unknown actions are silently ignored.

Defaults

If steps: is omitted entirely, the default sequence runs:

default steps
- wait: "body"
- screenshot
- extract

If viewport: is omitted, the browser opens at 1440px wide.

Where the Captures Go

  • Screenshots — saved under ~/.theme-factory/.cache/<repo>/website/ and surfaced to multimodal agent prompts (the Dev and Analyzer agents see the images directly)
  • Extracted HTML — formatted into the agent prompt as structured markdown
  • Media uploads — when a # Store is set, images and videos found in the captured DOM are uploaded to Shopify Files and CDN URLs are substituted into the agent context
  • Failures are fatal — a missing selector or unreachable URL aborts the run rather than letting agents work against blank capture data

Debugging Captures

When a step doesn't behave as expected (e.g. click doesn't open a drawer, wait_for selector never appears), re-run with --show-browser:

terminal
$ tf run ./my-task.md --show-browser

This launches Chromium with the window visible and slowMo: 250 so each step's action is watchable in real time. The website cache is bypassed in this mode so captures always re-run instead of returning a cached result. While the browser is open, you can also open DevTools to inspect the live DOM, confirm selectors, or run document.querySelector(...) checks against the page Playwright is interacting with.

Split Modes

Splitter mode is selected with CLI flags on tf split:

FlagDescription
--figma (default)Figma design analysis — fetches page structure, generates per-section tasks
--textText-based LLM analysis of the task description
--new-themeFigma mode with extra style-guide and global-sections tasks (greenfield builds)

Generated sub-task files are placed in a folder next to the input file. Each inherits shared metadata and gets its own # Task, # Task ID, and # Acceptance Criteria.

005

What Is It

The Super Agent is an interactive Claude session with full read/write access to your theme. Instead of writing a task file and running the 4-agent pipeline, you talk to Claude directly — describe what you want, paste screenshots, and it edits files, validates, commits, and pushes in real time.

It's the fastest way to make small changes, fix bugs, and iterate on a theme.

terminal
# Open super agent on the repo from your last pipeline run
$ tf chat --latest

# Or target a specific repo
$ tf chat --repo my-store-theme
$ tf chat --repo 3

# Auto-commit, ask before push
$ tf chat --latest --no-push

By default, the agent automatically commits and pushes to GitHub after every change. Use --no-push to auto-commit but require confirmation before pushing.

How it differs from tf run:

tf run (Pipeline)tf chat (Super Agent)
InputMarkdown task fileConversation
Execution4-agent pipeline (Context, Analyzer, Dev, Validator)Single agent, direct file editing
SpeedMinutes per iterationSeconds per edit
ScreenshotsNot supportedPaste images, agent analyzes and fixes
Best forLarge features, new sectionsQuick fixes, tweaks, visual debugging

When to Use

The Super Agent is ideal for smaller, quicker work where the full pipeline would be overkill:

  • Visual tweaks — spacing, colors, font sizes, alignment
  • Bug fixes — broken layouts, missing elements, CSS issues
  • Quick iterations — adjusting what the pipeline built
  • Content updates — copy changes, link updates, schema tweaks
  • Experimentation — try ideas without writing a formal task

For large features (new sections, full page builds, complex logic), use tf run with a task file — the multi-agent pipeline provides structured planning and validation.

Typical Workflow

terminal
# 1. Run the pipeline to build a feature
$ tf run my-task.md

# 2. Open super agent to fix/tweak the result
$ tf chat --latest

# 3. Describe issues or paste screenshots
You: The hero section has too much padding on mobile

# 4. Agent edits the file, validates, and shows preview
✔ Updated sections/hero.liquid — reduced mobile padding

# 5. Use --no-push to keep changes local
$ tf chat --latest --no-push

Fixing with Screenshots

One of the most powerful features — paste or drag a screenshot directly into the terminal. The agent analyzes the image visually, identifies the problem, finds the responsible file, and fixes it.

How it works:

  1. Take a screenshot of the visual issue in your browser
  2. Paste it into the terminal (or drag the image file in)
  3. Optionally describe what's wrong — or let the agent figure it out
  4. The agent cross-references the screenshot with the actual theme files
  5. It edits the code, runs shopify theme check, and pushes

Example: Paste a screenshot showing a misaligned product grid. The agent identifies it's caused by a CSS flex issue in assets/collection.css, fixes the alignment, validates the change, and pushes to Shopify — all in one conversation turn.

This makes the Super Agent especially effective for QA workflows — review the theme in the browser, screenshot any issues, and the agent fixes them one by one.

Capabilities

The Super Agent is loaded with full context about your repo and has access to everything it needs:

What It Can Do

  • Read and edit any file — Liquid, CSS, JS, JSON, schemas
  • Run theme checkshopify theme check for validation
  • Commit and push to GitHub — with branch awareness
  • Push to Shopify — and show a preview URL after each push
  • Fetch Figma data — if authenticated, inspect designs and download images
  • Upload images to Shopify — from Figma exports or local files
  • Analyze screenshots — visual debugging from pasted images

What It Knows

  • Learnings — accumulated knowledge from all previous pipeline runs and chat sessions
  • Theme inventory — complete file listing with section schemas and capabilities
  • Agent rules — CSS, Liquid, JS, and responsive design standards
  • TF rules — client-specific component specs from the repo's .tf-rules/ directory

Revert Safety

Before the Super Agent starts, a revert pointer is saved. If anything goes wrong, tf revert --latest resets to the state before the chat session — not the entire repo history.

terminal
# Undo everything the super agent changed
$ tf revert --latest

What Are TF Rules

TF Rules are markdown files that live inside your client's theme repository. They teach Theme Factory about client-specific components, patterns, and requirements — so the agents don't have to figure them out from scratch every time.

When you run a task, Theme Factory reads the .tf-rules/ directory in the repo and injects relevant rules into the agent's context based on keyword matching.

Theme Factory assembles every agent prompt from 4 layers, from universal to specific:

  1. Identity — core agent role (built into Theme Factory)
  2. Agent Rules — universal coding standards for all themes (built into Theme Factory)
  3. Theme Rules — base-theme-specific rules, e.g. Dawn vs Horizon (built into Theme Factory)
  4. TF Rules — your client-specific rules (lives in the client repo)

Layers 1-3 are maintained by Theme Factory. Layer 4 is yours — it's where you capture everything unique about a client's theme.

Setting Up

Create a .tf-rules/ directory in the root of your client's theme repository:

terminal
$ mkdir -p .tf-rules/shared .tf-rules/dev-agent .tf-rules/validator-agent
DirectoryLoaded For
.tf-rules/shared/All agents
.tf-rules/dev-agent/Dev agent only
.tf-rules/analyzer-agent/Analyzer agent only
.tf-rules/validator-agent/Validator agent only
.tf-rules/context-agent/Context agent only

No rebuilds needed. Rules are read at runtime from markdown files — just commit them to the repo and they're active on the next run.

Rule Format

Each rule is a markdown file with YAML frontmatter that controls when it gets loaded:

.tf-rules/dev-agent/header.md
---
alwaysApply: false
triggers:
  - header
  - navigation
  - nav
  - sticky
  - mega-menu
---

# Header Component

The header uses sections/header.liquid with sticky positioning.
It has a mega-menu powered by a nested block structure.

Key files: sections/header.liquid, assets/header.js
Mobile: collapses to hamburger at 990px breakpoint.

The sticky behavior uses position: sticky with a
100px offset. Do not change to position: fixed.

Triggers

The triggers field contains lowercase keywords. When your task description mentions any of these words, the rule is automatically injected into the agent's prompt.

  • Case-insensitive — triggers are lowercased for matching
  • Multi-word triggers work — "sticky header" matches if the task contains that phrase
  • Per-task filtering — different rules load for different tasks, keeping context focused
  • Set alwaysApply: true for rules that should load on every task (e.g., global design system conventions)
  • Files without frontmatter are treated as alwaysApply: true

Keep triggers specific. Too many generic triggers cause noise. "header" and "mega-menu" are good. "style" or "section" are too broad.

What to Define

Good candidates for TF Rules:

RuleWhy
Complex headersMega-menus, sticky behavior, mobile drawers — things that aren't obvious from the code alone
Custom PDP layoutsNon-standard product page structures, custom blocks, variant behavior
Design system rulesClient-specific spacing, color usage, typography conventions (set alwaysApply: true)
Non-standard filtersCustom filter implementations, third-party integrations
Component behaviorClick interactions, animation patterns, state management that isn't visible in Figma

Think of TF Rules as onboarding notes. If a new developer would need to know something specific about a component before working on it, that's a good candidate for a TF Rule.

Learnings

Theme Factory also stores a learnings.md file inside .tf-rules/. This file is automatically populated with knowledge discovered during pipeline runs and chat sessions.

  • Pipeline adds schema constraints (valid value ranges, select options) when it encounters errors
  • Super Agent adds conventions and client preferences when you correct it during a chat session
learnings.md
[pipeline] Setting 'popover_border_radius' range is 0-16, clamp values exceeding this
[chat] Client uses scheme-3 for green backgrounds, scheme-1 for white

Since it's committed to git, learnings are shared with anyone cloning the repo. All agents read this file on every run.

006

What Are Plugins

Plugins are optional feature packs that aren't bundled with Theme Factory by default. They typically wrap heavy dependencies (large npm packages, headless browser binaries, native modules) that not every user needs.

Installing a plugin downloads its dependencies into an isolated directory under ~/.theme-factory/plugins/<name>/ — each plugin has its own node_modules/, so plugins can't conflict with each other or with tf itself. Uninstalling deletes the whole directory.

When a feature that depends on a plugin runs, tf loads the plugin's modules lazily. If the plugin isn't installed, the feature aborts with the exact install command.

Available Plugins

PluginUnlocksHeavy Deps
website-flow# Website Options in task files, live-site capture during tf chatplaywright + Chromium browser (~150 MB on disk)

The registry ships with tf source — run tf update to fetch newer plugins as they're added.

Commands

terminal
$ tf plugin list                # list plugins with install status
$ tf plugin install <name>     # install a plugin's dependencies
$ tf plugin uninstall <name>   # remove an installed plugin
$ tf plugin status [<name>]    # install state for one or all plugins

website-flow

Adds live-website capture using Playwright + headless Chromium.

Unlocks:

  1. # Website Options in task files — declarative captures that take screenshots and extract HTML from a live site, feeding both into agent prompts. See Website Options for the full property reference.
  2. Live-site capture in tf chat — the super agent can navigate, screenshot, and extract from real pages on demand.

Install:

terminal
$ tf plugin install website-flow

The first install downloads a Chromium browser binary (~150 MB) — this is a one-time cost. Subsequent runs reuse the same browser.

Without it: any task using # Website Options, or any tf chat session that asks for a live capture, aborts with:

error
Playwright is not installed. Website capture requires the `website-flow` plugin.
  Install:  tf plugin install website-flow

Where Plugins Live

~/.theme-factory/
~/.theme-factory/
└── plugins/
    └── website-flow/
        ├── package.json         # Synthetic manifest (auto-generated by tf)
        └── node_modules/        # Isolated dependencies

Safe to delete by hand. tf plugin install <name> rebuilds it from scratch.

007

Building a Plugin

Integration plugins teach the Theme Factory pipeline how to integrate a third-party app (Recharge, Klaviyo, Yotpo, …) into a Shopify theme without modifying core code.

A plugin contributes knowledge (what the app is + how to build it), optional tools (MCP tools the agents can call), and optional store credentials (per-store IDs/keys fetched at build time). When a task is relevant, an LLM selects the plugin, its knowledge is injected into the analyzer/dev/validator agents, and the theme is built accordingly.

Plugins live in a separate repo (tf-plugins) under plugins/<name>/, or in any local directory used via --with-plugin during development.

What a Plugin Contributes

ContributionFile(s)What it doesRisk
Knowledgeknowledge/*.mdMarkdown injected into the analyzer/dev/validator prompts when engaged — "how this app is built into a theme."none (text)
Store credentialsstoreSettings in plugins.jsonPer-store IDs/keys fetched from the store-settings API and baked into the theme (no merchant theme settings).none (values only)
Toolstools.tsMCP tools the agents can call during a run (e.g. query a 3rd-party API).code (sandbox later)
SDK scriptsdk in plugins.jsonA storefront <script> URL surfaced to the dev agent to include.low

Knowledge is the core contribution — most integrations are 80% knowledge. Reach for tools.ts only when the build genuinely needs to call something.

Anatomy

A plugin is a directory. Only plugins.json is required.

my-plugin/
my-plugin/
  plugins.json          # manifest — the contract (required)
  knowledge/            # how-it-works markdown (one file per topic)
    overview.md
    gotchas.md
  tools.ts              # OPTIONAL — MCP tools (export const tools = [...])
  README.md             # OPTIONAL — human notes

plugins.json Reference

plugins.json
{
  "name": "yotpo-reviews",          // unique id (kebab-case)
  "version": "0.3.0",               // semver
  "kind": "integration",            // "integration" | "development" | "runtime-dep"
  "coreApi": "^1.0.0",              // host API semver range this plugin targets
  "description": "…",               // REQUIRED — natural language: what it is + WHEN to use it
                                    //   (this is what the LLM selector reads to decide relevance)
  "dependsOn": ["theme"],           // other plugins required (resolved + ordered first)
  "storeSettings": ["yotpo_instance_id"],   // per-store Setting keys to fetch + inject
  "sdk": "https://…/loader.js",     // OPTIONAL storefront script URL surfaced to the dev agent
  "npmDeps": {},                    // OPTIONAL npm deps (for tools.ts)
  "provides": {
    "knowledge": "knowledge/",      // dir of .md files (default "knowledge/")
    "tools": "tools.ts"             // OPTIONAL path to the tools module
  }
}

The description is the most important field. Detection is LLM-based (no keywords) — the model reads your description against the task to decide whether to engage the plugin. Write it as what the integration is and when it should be used, and scope it explicitly. Example:

"Yotpo product reviews for Shopify themes — the Reviews Widget and Star Rating widget. Use when a task involves Yotpo reviews, star ratings, or review counts. REVIEWS ONLY — not Yotpo Loyalty, SMS, or Subscriptions."

Knowledge

knowledge/ is a folder of Markdown files. When the plugin is engaged, all of them are concatenated and injected into the agents' prompts (analyzer, dev, validator). You do not categorize knowledge by agent — the host routes it.

Write knowledge as directives the planner can act on, not passive reference. This matters: the analyzer turns your knowledge into plan steps + acceptance criteria, and the plan wins over vague hints. If you want a specific outcome, say so explicitly and name the exact markup. Good knowledge:

  • names the exact Liquid/markup to emit;
  • says when it overrides the base theme's own pattern (e.g. "use the Yotpo widget, NOT the theme's native review block, NOT static stars");
  • documents real gotchas (load order, empty states, double-render, etc.).

Frontmatter is optional. A leading --- … --- block is stripped before injection, so you can keep notes there.

Store Credentials

Third-party integrations usually need per-store IDs/keys (a Yotpo instance id, an app key, …). Do not expose these as merchant-editable theme settings. Instead:

  1. Store the value per shop in the backend Setting table (key → value).
  2. Declare the key(s) in plugins.json:
    plugins.json
    "storeSettings": ["yotpo_instance_id"]
  3. At build time the host calls GET /api/store-settings?shop=<shop>, and injects only your declared keys' values into your plugin's knowledge block under "Store-provided credentials".
  4. Your knowledge tells the agent to bake the literal value in (and to fall back to a merchant setting only if the value is absent).

Only the keys you declare are injected — unrelated store settings never reach the prompt.

Tools (tools.ts)

Use a tool when the build needs to call something at runtime (e.g. fetch live data from a 3rd-party API). A tool is an MCP tool the analyzer/dev/validator can invoke.

tools.ts must export const tools = [...] using the Agent SDK's tool() primitive:

tools.ts
import { tool } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod/v4";

export const tools = [
  tool(
    "verify_widget_selectors",
    "Check the theme renders the required widget mount points",
    { theme_path: z.string().describe("Absolute path to the theme directory") },
    async (args) => {
      // …do work…
      return { content: [{ type: "text" as const, text: "ok" }] };
    },
  ),
];
  • Authored in TypeScript; the host transpiles it with esbuild on load (you ship .ts, never a build artifact).
  • The Agent SDK and zod are provided by the host — import them normally; they are resolved from Theme Factory's own dependencies.
  • Tools are namespaced per plugin (plugin-<name>), so they can't collide with core tools.
  • Need a secret/token? Read it from a store credential (see above) — never commit secrets.

How a Plugin Gets Engaged

  1. Discovery — the host finds installed plugins and any --with-plugin dirs.
  2. Selection — an LLM reads each candidate's description + the task and returns the plugins to engage. (No keyword triggers.)
  3. Dependencies — each engaged plugin's dependsOn is resolved.
  4. Contribution — engaged plugins' knowledge (+ injected store creds) is added to the agent prompts; their tools are registered as MCP servers.

Unengaged plugins cost ~nothing — only their one-line description is read.

Developing & Testing a Plugin

Author a plugin anywhere, then run Theme Factory against it with --with-plugin pointing at the directory (it just needs a valid plugins.json):

terminal
$ tf run <task.md> --with-plugin ./integrations/my-plugin
# absolute paths and multiple plugins work too:
$ tf run <task.md> --with-plugin /abs/path/a --with-plugin ./b
  • Works in single and batch runs.
  • A --with-plugin plugin is unverified (trust: local) — fine for dev.
  • It shadows an installed plugin with the same name, so you can test a local copy over a published one.

Confirm it engaged: the run prints [plugins] Engaged: <name> and writes an INTEGRATION PLUGINS section to logs/<runId>.log. If your plugin should have applied but didn't, check that section first.

What Is Not Supported Yet

These are planned but not implemented — don't rely on them:

  • Lifecycle hooks (webhook.ts with atStart() / beforeContext() / …) — deferred. Plugins are knowledge + tools + store creds for now.
  • tf plugin install / registry index / checksums — there is no installer or verification yet for integration plugins. They are consumed via --with-plugin or by being present in the plugins dir.
  • Sandboxed tool executiontools.ts runs in-process for now. Only ship tools you trust.
  • Deterministic <script> injection for sdk — the URL is surfaced to the dev agent rather than spliced in by the host.

Reference Plugin: yotpo-reviews

The yotpo-reviews plugin (in the tf-plugins repo) is the canonical example — a knowledge-only integration that:

  • engages on review/rating tasks via its description;
  • pulls the store's yotpo_instance_id from store settings and bakes it into the modern yotpo-widget-instance markup;
  • relies on the Yotpo App Embed for the loader (never hardcodes a loader URL, which would go stale);
  • explicitly overrides the base theme's native review pattern (no static stars, no metafields.reviews.rating).

Read its knowledge/ files for the directive style that makes the planner actually produce the integration.