@fluid-app/fluid-cli-theme-dev
v0.1.438
Published
Fluid CLI plugin for theme developer workflows — dev server, push, pull, init, crawl, compare
Readme
@fluid-app/fluid-cli-theme-dev
Fluid CLI plugin for theme development. Adds fluid theme commands for local dev server, push, pull, scaffolding, and
page-clone evidence (crawl / compare).
Installation
npm install -g @fluid-app/fluid-cli @fluid-app/fluid-cli-theme-devRequires @fluid-app/fluid-cli as the core CLI.
Authentication
Log in before using any theme commands:
fluid loginCommands
fluid theme dev
Start a local dev server that proxies your storefront with hot reload:
fluid theme devThe dev server will:
- Create (or reuse) an isolated development theme
- Preserve pulled binary assets as ImageKit URL references without downloading or re-uploading their bytes
- Keep editable source files (Liquid, CSS, JS, SVG, JSON) locally
- Upload a newly added binary once, save its ImageKit URL reference, and remove its local bytes
- Watch for source-file changes and sync them automatically
- Proxy requests to
{company}.fluid.appwith local file overrides
For a pulled theme, a newly created dev theme is a server-side reference clone
of the pulled source. It preserves theme content and DAM/ImageKit references,
so initial dev startup does not reseed every asset from the working copy. The
CLI keeps a compact local index of the development theme's acknowledged
checksums and version. Later startups validate that version, compare local files
to the cached dev state, and send only the actual changes without downloading
the complete remote resource index. A web-editor write, changed ImageKit
manifest, missing or malformed cache, or interrupted write invalidates the
shortcut and falls back to the full remote comparison. Set
FLUID_THEME_DEV_DISABLE_SHADOW_SYNC=1 to force that comparison as an emergency
rollback.
Theme paths that differ only by letter case are refused before pull, push, or dev writes. Windows separators are normalized before comparison. Default macOS and Windows filesystems cannot preserve both resources, so continuing would replace one path and delete the other.
| Flag | Default | Description |
| -------------------------- | ----------- | ----------------------------------------- |
| --host <host> | 127.0.0.1 | Local server host |
| --port <port> | 9292 | Local server port |
| -t, --theme <name-or-id> | auto | Use a specific theme instead of dev theme |
| --live-reload <mode> | full-page | Reload mode: full-page or off |
| --navigate | off | Open browser navigator after start |
| --root <path> | . | Theme root directory |
Member page preview
With fluid theme dev running, open http://127.0.0.1:9292/_members and
choose a page under its member site. Draft pages are included. The URL keeps the
site selection, for example:
http://127.0.0.1:9292/_members/pages/media?members_site_id=123After /_members, the path matches the account host's production path. The
legacy /accounts prefix returned by member metadata is removed. Storefront
pages keep their normal unprefixed URLs.
Optional member_type_id, country_id, and language_id query parameters select
the sample audience and locale. Without a member type, the preview allows
unrestricted authoring; selecting a type applies that site's access rules. Each
tab retains its own context through navigation, history, refresh, and live reload.
This does not sign in as a real member or expose private member collections.
Forms and authentication links cannot perform live member actions in preview.
The selected theme must be accessible with your CLI login. Rendering requires a
server with member-preview contract version 1. Set FLUID_API_BASE to use a local
or staging Rails API; member assets use that environment. Credentials remain in
the CLI process. The local server only accepts its configured host or loopback
hosts and rejects cross-origin requests.
Successful watched uploads refresh the page list before reloading. Failed uploads
retain the last known routes, and a removed page returns an explicit error.
--live-reload off disables automatic reload. System screens report unsupported
until the separate sample-runtime integration ships. The navigation command
integration is a separate follow-up; use /_members for this version.
fluid theme push
Upload local theme files to a remote theme:
fluid theme push # Interactive theme selection
fluid theme push --theme "My Theme" # By name
fluid theme push --theme 42 # By ID
fluid theme push --publish # Push and publish
fluid theme push --nodelete # Keep remote files not present locally
fluid theme push --auto-baseline # First push without a baseline: record
# the server's current state as the
# baseline, then push only local diffsPushing into an existing theme requires a local baseline (recorded by pull, or migrated from a checksum-era .fluid-theme.json). Without one, push refuses so it can't silently clobber the server. --auto-baseline instead records the server's current state as the baseline — no local file is modified, files identical to the server aren't re-uploaded, and files that exist only on the server are never deleted — then pushes what differs locally. Mist Desktop's one-click Publish uses this flag.
Files containing unresolved <<<<<<< / ======= / >>>>>>> conflict markers are never uploaded; push lists them and exits (with a machine-readable FLUID_THEME_PUSH_BLOCKED code=conflict_markers files=… line under --auto-baseline).
fluid theme pull
Download a remote theme to your local directory:
fluid theme pull # Interactive theme selection
fluid theme pull --theme "My Theme" # By name or ID
fluid theme pull --nodelete # Keep local files not present on remote
fluid theme pull --resolve remote # Auto-resolve conflicts to the server's
# side (or `--resolve local` to keep
# yours) instead of writing markersBy default, conflicting edits (changed locally and on the server since the last sync) are written with git-style conflict markers for you to resolve. For non-interactive use, --resolve local keeps your side of each conflicting hunk and --resolve remote takes the server's; before any auto-resolution overwrites local content, the pre-merge working tree is committed to the theme's shadow history (.fluid-theme/repo) so the discarded side stays restorable.
fluid theme init
Scaffold a new theme from the base template:
fluid theme init my-theme
cd my-theme
fluid theme devfluid theme navigate
Interactively select a route and open it in the browser (requires a running dev server):
fluid theme navigatefluid theme skills install
Copy the bundled theme AI skills (e.g. themes-review) into the current directory so an
agent can load them. Defaults to .agents/skills/, the tool-neutral convention for agent
skills:
fluid theme skills install # → .agents/skills/
fluid theme skills install --dir .claude/skills # custom location
fluid theme skills install --force # overwrite existing skills without promptingExisting skills are left untouched unless you confirm the overwrite (or pass --force).
fluid theme crawl <url>
Scrape a public page through Fluid's managed browser (JavaScript rendered) and print JSON with its Markdown, optional HTML, and a hosted screenshot URL. Mist's agent runs this command for every crawl.
fluid theme crawl https://example.com/ # Markdown, main content only
fluid theme crawl https://example.com/ --format html --format screenshot
fluid theme crawl https://example.com/ \
--viewport 1440x900 --full-page --quality 90 --no-main-content-only \
--evidence . # durable page-clone bundle
fluid theme crawl https://example.com/ \
--action '{"type":"click","selector":"#accept-cookies"}' \
--action '{"type":"wait","milliseconds":1000}' # act before the capture| Option | Meaning |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| --format <f> | markdown, html, or screenshot; repeatable or comma-separated. Default markdown, or all three with --evidence |
| --viewport WxH | Exact CSS-pixel viewport (implies a screenshot). Use 1440x900 and 390x844 for desktop/mobile parity |
| --full-page | Capture the complete document height |
| --quality <1-100> | Screenshot quality |
| --no-main-content-only | Keep the nav, announcement bar, and footer. Use it for site cloning |
| --evidence <dir> | Save an evidence bundle under <dir>/.mist-desktop/source-baselines/. Requires --viewport |
| --action <json> | A browser action before the evidence walk: {"type":"wait","milliseconds":N} (up to 10000), {"type":"click","selector":"…"}, or {"type":"scroll","direction":"up\|down"}. Repeatable, up to 8 |
| --post-evidence-action <json> | An action after the evidence walk and before the final screenshot, e.g. to close a drawer the walk opened. Also accepts {"type":"dismiss","selector":"…","scope_selector":"…"}, which the sidecar records. Needs --evidence and --full-page. Repeatable, up to 8 |
| --direct | Skip Fluid's endpoint and call Firecrawl with your own FIRECRAWL_API_KEY |
--evidence writes the bundle in the layout Mist's compare_preview_to_source reads, so
either Mist or fluid theme compare can compare it:
the full screenshot, the Markdown/HTML, the raw HTML, the page's own CSS, and a
.page-evidence.json sidecar with landmarks, computed styles, SHA-256 hashes, and receipts.
The JSON output lists every path (evidence.files). Inline content is capped at about
200KB, or a 16KB excerpt when the full documents are saved. The scrape times out after
60s. With --evidence, stylesheet recovery is bounded at 30s and the screenshot download
at 20s. Both downloads refuse localhost and private-network addresses.
Where the crawl runs. The CLI calls Fluid's crawl endpoint with your fluid login
token, so you do not need a Firecrawl key. If the endpoint is not deployed on your API
host (HTTP 404) or not configured (HTTP 503), and FIRECRAWL_API_KEY is set, the CLI
falls back to Firecrawl directly with that key. Create a key at
https://www.firecrawl.dev/app/api-keys. Errors are printed as JSON
({"ok": false, "error": {"code": …, "message": …}}), and the command exits 1.
fluid theme compare
Render the local fluid theme dev preview at a crawl bundle's exact viewport. It prints
the same banded pixel diff Mist's compare_preview_to_source reports: a bands[] array
and a worst-first summary, with exact-copy and media-parity checks.
fluid theme dev & # serves http://127.0.0.1:9292
fluid theme compare --source . # newest "/" capture in ./.mist-desktop/source-baselines
fluid theme compare --source .mist-desktop/source-baselines/<file>.page-evidence.json \
--route /collections/all --geometry diagnostic --media diagnostic| Option | Default | Meaning |
| ------------------------------- | ----------------------- | ----------------------------------------------------------------------- |
| --source <path> | (required) | A .page-evidence.json sidecar, its directory, or the --evidence dir |
| --route <path> | / | Local route to render |
| --source-route <path> | --route | Source pathname when it differs (for example /en-us for /) |
| --url <url> | http://127.0.0.1:9292 | Base URL of the running preview |
| --mode full\|viewport | full | Whole page, or the top viewport only |
| --copy exact\|diagnostic | exact | exact fails on any ordered rendered-copy mismatch |
| --geometry strict\|diagnostic | strict | strict fails when document height differs by more than 5% |
| --media strict\|diagnostic | strict | strict fails on image/video parity differences |
| --viewport WxH | | Pick the capture at this viewport when --source holds several |
The command refuses mixed captures, silent resizing, failed routes, truncation, horizontal
overflow, unresolved media, and copy mismatches. On a refusal, ok is false and the
command exits 1. A successful run means the evidence is available. It does not mean the
page passes visually. Fix the worst band, then compare again. The local capture is saved
under .mist-desktop/screenshots/.
compare needs a headless browser. Playwright is an optional peer dependency, so a
theme-dev install never downloads browsers. Install it once with:
npm i -g playwright && npx playwright install chromiumTheme Directory Structure
A valid theme directory must contain at least one of: templates/, assets/,
config/, or the asset reference manifest .fluid-assets.json.
Use a .fluidignore file (same syntax as .gitignore) to exclude files from syncing.
Remote binary assets
fluid theme pull keeps binary assets such as images, fonts, video, and PDFs
remote rather than downloading them into assets/. Their ImageKit URL
reference metadata is recorded in .fluid-assets.json. The CLI uses that
manifest when it starts a dev theme or pushes to another theme, so existing
asset_url calls continue to resolve normally without local binary copies.
When a developer adds a new binary file during fluid theme dev, the CLI
uploads it once, records its ImageKit URL reference in the manifest, and
removes its local bytes after the theme resource has been saved. A later
fluid theme push writes that same ImageKit URL into the selected target theme
without a second binary upload.
Binary assets must be direct children of assets/ (for example,
assets/logo.png); nested asset directories are not supported by the theme
resource API.
Do not add .fluid-assets.json to .fluidignore; it is already excluded from
theme uploads and file watching. Commit it with the theme source so every
developer receives the same remote asset references.
Development
For contributors working in this monorepo:
pnpm --filter @fluid-app/fluid-cli-theme-dev build
node packages/cli/core/dist/bin/fluid.mjs theme --helpChoose a member preview page
Run fluid theme navigate while the dev server is running, or start it with
fluid theme dev --navigate, to use the same route picker. Member pages are
grouped by site and include drafts. Storefront choices remain available.
Use --host and --port for a custom local address. theme navigate --theme <id>
must match the running server’s theme. The picker reads routes after acknowledged
syncs and rechecks a member page before opening it. System screens appear only
when the running preview runtime advertises support; unavailable screens are
listed in the terminal. Cancelling the picker leaves the dev server running.
System-screen sample previews
Member navigation also lists profile, messaging, contacts, my-site, orders, and subscriptions when both the Rails catalogue and the packaged CLI runtime support them. The CLI ships its own sample-only account-screen bundle; no CDN update or member login is needed. A missing bundle produces an explicit unavailable response instead of loading a live screen.
Screen links use production paths under /_members, for example
/_members/profile/orders?members_site_id=42. Detail navigation, refresh and
browser back preserve the selected site and audience. Theme layouts, attribute
settings and --fluid-account-* CSS overrides apply to these screens.
Data is synthetic. Writes and sign-out are rejected; payment entry is disabled.
These previews do not verify private member data or real member permissions.
Screens outside the packaged catalogue remain unavailable. From source, run
pnpm --filter @fluid-app/fluid-cli-theme-dev build before starting the CLI;
this also builds and copies the shared sample runtime into the CLI package.
Using member preview in Mist
Start the theme's local preview in Mist, open the Pages sidebar, then choose
Member pages. Expand the group to see each site's custom pages (including
drafts) and supported sample screens directly in the sidebar. The list comes
from the running CLI's development theme, which can have a different ID from
the source theme. Clicking a page keeps its site in members_site_id. You can
also paste a /_members/...?... path into Mist's local preview address bar.
The Prod tab and its URL editor remain available. The /_members prefix is
local-only; use the actual member-site URL when viewing production. Real member
authentication and private Liquid collections are outside the CLI sample-preview
contract.
Troubleshooting member preview
- 401/403: renew
fluid loginand check permission to view the selected company's theme. Browser member login cannot replace the CLI credential. - 404 after editing the manifest: the page or site may have been removed.
Open
/_membersagain after the upload succeeds. - 501 for a system screen: the installed CLI does not include a compatible sample runtime for that screen. Update the CLI; unsupported screens are not silently opened on the live member site.
- 502 / incompatible render response: deploy the Rails member-preview contract and use a CLI version that supports that contract.
- Source build: build the theme CLI from the monorepo root. Its build needs
the shared account-screen source and creates the browser runtime in
dist/dist-cli-preview; a published package already contains these files. - Local Rails: set
FLUID_API_BASEto your local API origin in the process that starts the CLI. The default ishttps://api.fluid.app.
Use a development theme for preview tests. theme dev creates an isolated
copy by default; --theme explicitly targets an existing theme and syncs files
to it. No preview command publishes the theme. The browser receives no member session, and sample data cannot verify live
access rules.
The package acceptance check is pnpm --filter @fluid-app/fluid-cli-theme-dev run test:package
after building. It starts the compiled theme plugin through Commander with a disposable local
API server, verifies draft selection, screen assets and detail URLs, then checks
authorization expiry, unknown sites, unsupported screens and write rejection.
Set FLUID_THEME_PACKAGE_DIR to an unpacked npm package to run the same check on
the distribution artifact. It does not contact production.
The fixture runner does not exercise core CLI plugin discovery or npm package exports. An installed fluid theme dev smoke test remains a release check.
