✓ Verified 💻 Development ✓ Enhanced Data

Fastmode

Create, deploy, and host a website for free.

Rating
4.8 (207 reviews)
Downloads
5,538 downloads
Version
1.0.0

Overview

Create, deploy, and host a website for free.

Key Features

1

Check for Existing Projects

2

Decide — Existing or New Project

Complete Documentation

View Source →

FastMode CLI — Complete Agent Reference

FastMode lets you create a live website, deploy it to the cloud, and manage all its content — entirely from the command line. One-time browser login for OAuth authentication, then every operation runs in the terminal. No local servers, no manual dashboards.

  • Free cloud hosting — every site gets a live URL at yoursite.fastmode.ai
  • Free SSL — HTTPS included automatically
  • Custom domains — connect any domain (e.g. www.example.com)
  • Full CMS — any content structure (blog, team, products, portfolios, anything)
  • Agent-native — every operation works via CLI, zero human intervention needed

Table of Contents


End-to-End Workflow

This is the complete sequence to go from nothing to a live website.

bash
# 1. Authenticate (one-time — credentials persist at ~/.fastmode/credentials.json)
fastmode login

# 2. Create a project (gets a free hosted URL instantly)
fastmode projects create "Acme Corp"
fastmode use "Acme Corp"

# 3. Define content structure (write schema.json, then sync it)
fastmode schema sync -f schema.json

# 4. Add content
fastmode items create posts -n "Welcome" -d '{"title": "Welcome to Acme", "body": "<p>We build great things.</p>"}'
fastmode items create team -n "Jane Doe" -d '{"role": "Founder", "bio": "<p>Visionary leader.</p>"}'

# 5. Build HTML templates with {{tokens}}, package into a zip, validate, deploy
fastmode validate package site.zip
fastmode deploy site.zip
# Deploy waits for build to finish and reports success or failure with error details

# 6. If the build failed, check what went wrong
fastmode status
# Fix the issue, then re-deploy


CRITICAL: Before You Build Anything

STOP. Before writing ANY HTML, templates, or manifest.json, complete these steps.

Step 1: Check for Existing Projects

bash
fastmode projects

This lists all the user's existing FastMode projects.

Step 2: Decide — Existing or New Project

If projects exist: Ask the user: "Is this website for one of your existing projects, or should I create a new one?" Let the user choose.

If NO projects exist: This is a new user — ask: "What would you like to name your new project?"

Step 3a: For EXISTING Projects

  • User selects the project from the list
  • Run fastmode use "Project Name" to set it as default
  • Run fastmode schema show to get the current collections and fields
  • Use this schema to build templates with the correct field names

Step 3b: For NEW Projects

  • Ask for the project name if you don't have it
  • Run fastmode projects create "Project Name"
  • Run fastmode use "Project Name"
  • You'll create the schema later with fastmode schema sync
  • Optionally generate sample content: fastmode generate-samples

Checkpoint — Confirm Before Continuing

RequirementHow to Get It
Project selected/createdfastmode projects / fastmode projects create
Default setfastmode use "Project Name"
Schema known (existing)fastmode schema show
If you don't have a project set, DO NOT PROCEED. Go back to Step 1.

WHY THIS MATTERS:

  • For existing projects: The schema determines which fields to use in templates — get it wrong and the build fails
  • For new projects: You need the project before you can deploy
  • Always: The user must confirm which project to use — never assume

Website Analysis (Do This Before Writing Code)

Before writing any HTML or templates, analyze the site:

  • Map ALL URLs — document every page path (/, /about, /blog, /blog/post-slug, etc.)
  • Categorize each page — Static (fixed content), List (shows multiple items), or Detail (single item from a collection)
  • Identify collections — repeating content that should be CMS-managed (blog posts, team members, products, testimonials, etc.)
  • Document assets — all CSS, JS, image, and font file locations
  • PRESERVE original URLs — if the site uses /resources for articles, keep /resources. Do NOT change it to /blog. Use the manifest's path configuration.

Command Reference

Authentication

bash
fastmode login                          # Open browser for OAuth device flow
fastmode logout                         # Delete ~/.fastmode/credentials.json
fastmode whoami                         # Show current user email and name
  • login uses OAuth 2.0 device authorization flow: opens a browser window where the user approves access on fastmode.ai, then credentials are saved automatically. The browser is only needed for this one-time login step.
  • OAuth scopes: The token grants access to the user's FastMode projects only (project management, schema editing, content CRUD, deployments). No third-party service access is requested.
  • Credentials persist at ~/.fastmode/credentials.json with restricted file permissions (0o600 — owner read/write only). Treat this file as a sensitive secret.
  • Tokens auto-refresh. If a token expires, the next command will refresh it silently using the stored refresh token.
  • If credentials are missing or invalid, most commands will trigger the login flow automatically.
  • logout deletes ~/.fastmode/credentials.json and revokes the stored tokens.

Projects

bash
fastmode projects                       # List all projects (default action)
fastmode projects list                  # Same as above
fastmode projects create "Name"         # Create a new project
fastmode projects create "Name" --subdomain custom-sub  # Custom subdomain
fastmode projects create "Name" --force                  # Skip similar-name check
fastmode use <project>                  # Set default project for all commands
  • projects create checks for existing projects with similar names. Use --force to skip.
  • Subdomain auto-generated from name if not provided (lowercase, hyphens, max 30 chars).
  • use stores the default in ~/.fastmode/config.json. Does NOT validate the project exists.

Schema

bash
fastmode schema show                    # Show all collections and fields
fastmode schema show -p "Project Name"  # Specify project
fastmode schema sync -f schema.json     # Create collections and fields from JSON file
fastmode schema field-types             # List all available field types (no auth needed)
  • schema show requires authentication and a project.
  • schema sync reads a local JSON file and creates/updates the schema. Skips duplicates. Two-phase: creates collections first, then fields (handles relation dependencies).
  • schema field-types works without authentication.

Content Items

bash
fastmode items list <collection>                          # List all items
fastmode items list posts --limit 10 --sort publishedAt --order desc
fastmode items get <collection> <slug>                    # Get single item
fastmode items create <collection> -n "Name" -d '{"field": "value"}'
fastmode items create posts -n "Title" -f data.json       # Data from file
fastmode items create posts -n "Draft Post" -d '{}' --draft
fastmode items update <collection> <slug> -d '{"field": "new value"}'
fastmode items update posts my-post -n "New Title"
fastmode items update posts my-post --publish             # Publish a draft
fastmode items update posts my-post --unpublish           # Revert to draft
fastmode items delete <collection> <slug> --confirm       # REQUIRES --confirm
fastmode items relations <collection>                     # Show linkable items for relation fields
fastmode items relations posts --field author             # Options for specific field

See the Content Items section below for detailed rules on data formats, relation fields, and drafts.

Client Portal Management

bash
fastmode clients list                              # List portal clients with access
fastmode clients invite [email protected]         # Invite with default permissions
fastmode clients invite [email protected] -n "Jane" --permissions cms.read,cms.write
fastmode clients invitations                       # List pending invitations
fastmode clients update-permissions <accessId> --permissions cms.read,editor
fastmode clients revoke <accessId> --confirm       # REQUIRES --confirm
fastmode clients cancel-invite <invitationId> --confirm  # REQUIRES --confirm

See the Client Portal Management section below for details on permissions, invite flow, and examples.

Deployment & Build Status

bash
fastmode deploy site.zip                # Deploy and wait for build to finish
fastmode deploy site.zip --force        # Skip GitHub sync check
fastmode deploy site.zip --no-wait      # Upload only, don't wait for build
fastmode deploy site.zip --timeout 300000  # Custom timeout in ms (default: 120000)
fastmode status                         # Check current build/deploy status
fastmode deploys                        # List deployment history
fastmode deploys --limit 5             # Limit number of results

See Deployment & Build Status below for the full deploy lifecycle.

Validation

bash
fastmode validate manifest manifest.json
fastmode validate template index.html -t custom_index
fastmode validate template post.html -t custom_detail -c posts
fastmode validate template post.html -t custom_detail -c posts -p "My Project"
fastmode validate template about.html -t static_page
fastmode validate package site.zip
  • Template types: custom_index (collection listing), custom_detail (single item), static_page (fixed page).
  • -c specifies the collection slug (required for custom_index and custom_detail).
  • -p validates tokens against the actual project schema (reports missing fields).
  • All validation commands exit with code 1 on errors — safe for CI/CD pipelines.

Documentation & Examples

bash
fastmode examples <type>                # Code examples for a specific pattern
fastmode guide                          # Full website conversion guide
fastmode guide templates                # Template syntax guide
fastmode guide common_mistakes          # Common pitfalls to avoid
fastmode generate-samples               # Generate placeholder content for empty collections
fastmode generate-samples -c posts team # Specific collections only

Available example types: manifest_basic, manifest_custom_paths, blog_index_template, blog_post_template, team_template, downloads_template, form_handling, asset_paths, data_edit_keys, each_loop, conditional_if, nested_fields, featured_posts, parent_context, equality_comparison, comparison_helpers, youtube_embed, nested_collection_loop, loop_variables, common_mistakes.

Available guide sections: full, first_steps, analysis, structure, seo, manifest, templates, tokens, forms, assets, checklist, common_mistakes.


Project Resolution

Every project-scoped command (schema, items, deploy, status, etc.) needs a project. Resolution order:

  • -p / --project flag — explicit on the command: -p "My Project" or -p abc123-uuid
  • FASTMODE_PROJECT environment variable — set in shell: export FASTMODE_PROJECT="My Project"
  • Default project — saved by fastmode use "My Project" in ~/.fastmode/config.json
If none is set, the command prints an error and exits with code 1:
text
Error: No project specified.
Use -p <id-or-name>, set FASTMODE_PROJECT env var, or run: fastmode use <project>

Project identifiers can be:

  • UUID — used directly (e.g. 550e8400-e29b-41d4-a716-446655440000)
  • Project name — resolved via API (exact match first, then partial match, case-insensitive)

Schema & Field Types

Creating a Schema

Write a schema.json file and sync it:

bash
fastmode schema sync -f schema.json

schema.json Format

json
{
  "collections": [
    {
      "slug": "posts",
      "name": "Blog Posts",
      "nameSingular": "Blog Post",
      "fields": [
        { "slug": "title", "name": "Title", "type": "text", "isRequired": true },
        { "slug": "excerpt", "name": "Excerpt", "type": "textarea" },
        { "slug": "body", "name": "Body", "type": "richText" },
        { "slug": "featured-image", "name": "Featured Image", "type": "image" },
        { "slug": "category", "name": "Category", "type": "select", "options": "News, Tutorial, Update" },
        { "slug": "tags", "name": "Tags", "type": "multiSelect", "options": "JavaScript, Python, DevOps, AI" },
        { "slug": "featured", "name": "Featured", "type": "boolean" },
        { "slug": "author", "name": "Author", "type": "relation", "referenceCollection": "team" }
      ]
    },
    {
      "slug": "team",
      "name": "Team Members",
      "nameSingular": "Team Member",
      "fields": [
        { "slug": "role", "name": "Role", "type": "text" },
        { "slug": "bio", "name": "Bio", "type": "richText" },
        { "slug": "photo", "name": "Photo", "type": "image" },
        { "slug": "email", "name": "Email", "type": "email" }
      ]
    }
  ]
}

To add fields to existing collections, use fieldsToAdd:

json
{
  "fieldsToAdd": [
    {
      "collectionSlug": "posts",
      "fields": [
        { "slug": "reading-time", "name": "Reading Time", "type": "number" }
      ]
    }
  ]
}

You can combine collections and fieldsToAdd in the same file. Duplicate collections and fields are automatically skipped.

Available Field Types

TypeDescriptionTemplate UsageNotes
textSingle-line text{{field}}Titles, names, short strings
textareaMulti-line plain text{{field}}Descriptions, excerpts
richTextFormatted HTML content{{{field}}}MUST use triple braces
numberNumeric value{{field}}Prices, counts, order
booleanTrue/false toggle{{#if field}}Toggles, flags
dateDate only{{field}}Birth dates, event dates
datetimeDate and time{{field}}Timestamps
imageImage file/URL{{field}}Renders as URL
fileDownloadable file (max 10MB){{field}}Link as
urlWeb link{{field}}External URLs
videoEmbedYouTube/Vimeo/Wistia/Loom{{field}}Embed URL
emailEmail with validation{{field}}Validated email addresses
selectSingle dropdown{{field}}Requires "options": "A, B, C"
multiSelectMultiple selections{{field}}Requires "options": "A, B, C"
relationLink to another collection{{field.name}}Requires "referenceCollection": "slug"

Relation Fields — CRITICAL

Relation fields link items between collections (e.g. a post has an author from the team collection). When creating or updating items with relation fields:

  • You MUST use the item's UUID, not its name or slug
  • Use fastmode items relations to get the available IDs
  • Example: fastmode items relations posts --field author shows team member IDs
bash
# First, find the author's item ID
fastmode items relations posts --field author
# Output shows: ID: 550e8400-..., Name: Jane Doe, Slug: jane-doe

# Then use that ID when creating a post
fastmode items create posts -n "My Post" -d '{"title": "My Post", "author": "550e8400-e29b-41d4-a716-446655440000"}'

WRONG: "author": "Jane Doe" — this will NOT work. CORRECT: "author": "550e8400-e29b-41d4-a716-446655440000" — use the UUID.


Content Items

Creating Items

bash
fastmode items create <collection> -n "Item Name" -d '{"field": "value"}'

FlagDescription
-n, --name Required. Item name/title.
-s, --slug URL slug. Auto-generated from name if omitted.
-d, --data Field data as JSON string.
-f, --file Read field data from a JSON file (takes precedence over -d).
-p, --project Project ID or name.
--draftCreate as unpublished draft.
Data rules:
  • -d value must be valid JSON. Keys are field slugs.
  • -f reads from a JSON file. If both -f and -d are given, -f wins.
  • If neither -d nor -f is given, the item is created with just the name (no field data).
  • Rich text fields accept raw HTML: "body": "

    Title

    Content here.

    "
  • Relation fields require UUIDs (see above).
  • Without --draft, items are published immediately (publishedAt set to now).

Updating Items

bash
fastmode items update <collection> <slug> -d '{"field": "new value"}'

FlagDescription
-n, --name New name/title.
-d, --data Updated fields as JSON. Only provided fields change — others are preserved.
-f, --file Read updated data from a JSON file.
-p, --project Project ID or name.
--publishSet publishedAt to now (make item live).
--unpublishSet publishedAt to null (revert to draft).
Update is a partial merge. Only the fields you provide in -d are changed. All other fields remain as they are.

Deleting Items

bash
fastmode items delete <collection> <slug> --confirm

The --confirm flag is required. Without it, the command refuses to run and exits with code 1. This is a safety measure — deletion is permanent and cannot be undone.

Always ask the user for confirmation before deleting.

Draft / Publish Mechanics

ActionCommand
Create as published (default)fastmode items create posts -n "Title" -d '{...}'
Create as draftfastmode items create posts -n "Title" -d '{...}' --draft
Publish a draftfastmode items update posts my-slug --publish
Unpublish (revert to draft)fastmode items update posts my-slug --unpublish
  • Draft items have publishedAt: null and are not visible on the live site.
  • Published items have a publishedAt timestamp and appear on the live site.
  • Without --draft, new items are published immediately.

Client Portal Management

The client portal lets you give external clients (your customers, collaborators) limited access to manage content on your FastMode site. Clients get their own login, separate from your admin account, with configurable permissions.

How It Works

  • You invite a client by email — they receive a unique invite link
  • Client clicks the link — creates a password and gets portal access
  • Client manages content — based on the permissions you assigned
  • You control access — update permissions or revoke access at any time
The portal is auto-enabled on the project when you send the first invitation. No manual setup needed.

Available Permissions

PermissionDescription
cms.readView collection items
cms.writeCreate, edit, archive, and delete items
editorAccess the visual editor
forms.readView form submissions
dnsManage DNS settings
apiAccess API and integrations
notificationsManage notification rules
billingView plans and manage billing
Default permissions (used when none specified): cms.read, cms.write, editor, forms.read

Inviting Clients

bash
# Invite with default permissions
fastmode clients invite [email protected]

# Invite with a name
fastmode clients invite [email protected] -n "Jane Smith"

# Invite with specific permissions
fastmode clients invite [email protected] -n "Jane Smith" --permissions cms.read,forms.read

# Invite with all permissions
fastmode clients invite [email protected] --permissions cms.read,cms.write,editor,forms.read,dns,api,notifications,billing

The command returns an invite URL — share this with the client. The link expires in 7 days.

Important:

  • Each email can only be invited once per project
  • If a client already has access, the invite will fail
  • If a pending invitation already exists for the email, the invite will fail

Listing Clients and Invitations

bash
# See who has portal access
fastmode clients list

# See pending (unaccepted) invitations
fastmode clients invitations

clients list shows the access ID for each client — you need this ID to update permissions or revoke access.

Updating Permissions

bash
# First, get the access ID from the list
fastmode clients list

# Update permissions (replaces ALL existing permissions)
fastmode clients update-permissions <accessId> --permissions cms.read,cms.write,editor

Permissions are replaced entirely — if a client had cms.read,cms.write,editor,forms.read and you set --permissions cms.read, they will ONLY have cms.read.

Revoking Access

bash
# Revoke a client's portal access (requires --confirm)
fastmode clients revoke <accessId> --confirm

The --confirm flag is required. Without it, the command refuses to run.

Always ask the user for confirmation before revoking access.

Revoking access is a soft delete — the client's account still exists but they cannot access this project's portal. Their active sessions are terminated immediately.

Canceling Invitations

bash
# Cancel a pending invitation (requires --confirm)
fastmode clients cancel-invite <invitationId> --confirm

The invitation link will no longer work. Use fastmode clients invitations to get the invitation ID.

Typical Workflow

bash
# 1. Invite your client
fastmode clients invite [email protected] -n "Design Agency" --permissions cms.read,cms.write,editor

# 2. Share the invite URL from the output with the client

# 3. Later, check who has access
fastmode clients list

# 4. Restrict a client to read-only
fastmode clients update-permissions abc12345 --permissions cms.read

# 5. Remove a client who no longer needs access
fastmode clients revoke abc12345 --confirm


Package Structure

The deployment package is a .zip file with this exact structure:

text
site.zip
├── manifest.json              # REQUIRED — defines pages and CMS templates
├── pages/                     # Static HTML pages
│   ├── index.html             # Homepage (REQUIRED — must have path "/")
│   ├── about.html
│   └── contact.html
├── templates/                 # CMS-powered templates (if using collections)
│   ├── posts_index.html       # Blog listing page
│   ├── posts_detail.html      # Single blog post page
│   └── team_index.html        # Team listing page
└── public/                    # ALL static assets (CSS, JS, images, fonts)
    ├── css/
    │   └── style.css
    ├── js/
    │   └── main.js
    └── images/
        ├── logo.png
        └── favicon.ico

Strict Rules

  • manifest.json MUST be at the root of the zip.
  • Static pages go in pages/. One HTML file per page.
  • CMS templates go in templates/. Convention: {collection}_index.html and {collection}_detail.html.
  • ALL static assets go in public/. CSS, JavaScript, images, fonts — everything.
  • Reference assets with /public/ prefix in HTML. Example: .
  • A homepage is required. One page must have "path": "/" in the manifest.

Critical: Asset Paths

WRONG — will 404:

html
<link href="/assets/css/style.css" rel="stylesheet">
<link href="/css/style.css" rel="stylesheet">
<link href="../css/style.css" rel="stylesheet">
<script src="js/main.js"></script>

CORRECT:

html
<link href="/public/css/style.css" rel="stylesheet">
<script src="/public/js/main.js"></script>
<img src="/public/images/logo.png" alt="Logo">

This also applies inside CSS files — background images AND fonts:

css
/* WRONG */
background-image: url('../images/bg.jpg');
background-image: url('images/bg.jpg');
src: url('../fonts/custom.woff2');

/* CORRECT */
background-image: url('/public/images/bg.jpg');
src: url('/public/fonts/custom.woff2');

Asset path conversion table:

Original PathConverted Path
css/style.css/public/css/style.css
../css/style.css/public/css/style.css
./images/logo.png/public/images/logo.png
/images/logo.png/public/images/logo.png
../fonts/custom.woff/public/fonts/custom.woff
External URLs (Google Fonts, CDNs, etc.) stay unchanged.


Manifest Format

The manifest.json file defines the site structure. It uses a FLAT format for CMS templates (not nested).

Basic Example (Static Only)

json
{
  "pages": [
    { "path": "/", "file": "pages/index.html", "title": "Home" },
    { "path": "/about", "file": "pages/about.html", "title": "About" },
    { "path": "/contact", "file": "pages/contact.html", "title": "Contact" }
  ]
}

With CMS Collections

json
{
  "pages": [
    { "path": "/", "file": "pages/index.html", "title": "Home" },
    { "path": "/about", "file": "pages/about.html", "title": "About" }
  ],
  "cmsTemplates": {
    "postsIndex": "templates/posts_index.html",
    "postsIndexPath": "/blog",
    "postsDetail": "templates/posts_detail.html",
    "postsDetailPath": "/blog",
    "teamIndex": "templates/team_index.html",
    "teamIndexPath": "/team"
  }
}

CMS Template Keys — FLAT Format

Each collection needs 2-4 keys in cmsTemplates. The format is {collectionSlug}Index, {collectionSlug}IndexPath, {collectionSlug}Detail, {collectionSlug}DetailPath.

KeyRequiredDescription
{slug}IndexYesPath to the collection listing template file
{slug}IndexPathYesURL path for the listing page (e.g. /blog)
{slug}DetailNoPath to the single item template file
{slug}DetailPathNoURL path prefix for item pages (e.g. /blog → /blog/item-slug)
Example for a "services" collection:
json
"cmsTemplates": {
  "servicesIndex": "templates/services_index.html",
  "servicesIndexPath": "/services",
  "servicesDetail": "templates/services_detail.html",
  "servicesDetailPath": "/services"
}

Common Manifest Mistakes — AI Agents Frequently Get This Wrong

AI agents frequently use a nested object format or "collections" key that FastMode does NOT support. Read carefully.

WRONG — using "collections" key (MOST COMMON AI MISTAKE):

json
{
  "collections": {
    "posts": {
      "indexPath": "/blog",
      "indexFile": "collections/posts/index.html",
      "detailPath": "/blog/:slug",
      "detailFile": "collections/posts/detail.html"
    }
  }
}

WRONG — nested objects inside cmsTemplates:

json
"cmsTemplates": {
  "posts": {
    "indexPath": "/blog",
    "detailPath": "/blog"
  }
}

WRONG — singular slug names:

json
"postIndex": "..."   // Should be "postsIndex"
"postDetail": "..."  // Should be "postsDetail"

CORRECT — flat keys using cmsTemplates, matching the collection slug exactly:

json
"cmsTemplates": {
  "postsIndex": "templates/posts_index.html",
  "postsIndexPath": "/blog",
  "postsDetail": "templates/posts_detail.html",
  "postsDetailPath": "/blog"
}

Key rules:

  • Use cmsTemplates, NOT collections
  • Use FLAT keys: {slug}Index, {slug}Detail, {slug}IndexPath, {slug}DetailPath
  • Do NOT nest objects inside collection names
  • Use fastmode validate manifest manifest.json to catch these errors before deploying

Optional: Head/Body Injection

json
{
  "pages": [...],
  "cmsTemplates": {...},
  "defaultHeadHtml": "<link rel=\"stylesheet\" href=\"/public/css/global.css\">",
  "defaultBodyEndHtml": "<script src=\"/public/js/analytics.js\"></script>"
}


Template Syntax

FastMode templates use Handlebars-style tokens. There are three types of templates:

  • Static pages (pages/): Fixed HTML with optional data-edit-key attributes for inline CMS editing and optional {{#each}} loops for dynamic content.
  • Index templates (templates/): Collection listing pages. MUST contain at least one {{#each collectionSlug}} loop.
  • Detail templates (templates/): Single item pages. MUST contain CMS tokens like {{name}}, {{{body}}}, etc.

SEO Tags — Do NOT Include

FastMode automatically manages all SEO meta tags. Including them in your HTML will cause duplicate tags (bad for SEO ranking). Remove ALL of these from your templates:

TagWhy to Remove
...Managed via CMS Settings
Managed via CMS Settings
Managed via CMS Settings
Open Graph auto-generated
Twitter cards auto-generated
Favicon managed in settings
Favicon managed in settings
Managed by FastMode
Managed in settings
Correct structure:
html
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <!-- SEO managed by Fast Mode — do not add title, description, or OG tags -->
  <link rel="stylesheet" href="/public/css/style.css">
  <!-- External fonts, scripts, etc. are fine -->
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
</head>

Built-in Fields (Every Item Has These)

TokenDescriptionExample
{{name}}Item name/title

{{name}}

{{slug}}URL slug
{{url}}Full URL to detail pageRead more
{{publishedAt}}Publish date
{{createdAt}}Creation date
{{updatedAt}}Last modified date

Regular Fields — Double Braces {{field}}

Used for text, number, date, image, url, email, select, boolean fields:

html
<h1>{{name}}</h1>
<p>{{excerpt}}</p>
<img src="{{featured-image}}" alt="{{name}}">
<span>Category: {{category}}</span>
<a href="{{website-url}}">Visit</a>

Rich Text Fields — Triple Braces {{{field}}}

CRITICAL: Rich text fields contain HTML. You MUST use triple braces {{{ }}} so the HTML renders correctly. Double braces will escape the HTML and display raw tags as text.

html
<!-- CORRECT — HTML renders properly -->
<div class="content">{{{body}}}</div>
<div class="bio">{{{bio}}}</div>

<!-- WRONG — HTML appears as escaped text like &lt;p&gt;Hello&lt;/p&gt; -->
<div class="content">{{body}}</div>

Loops — {{#each collection}}

Used in index templates and static pages to iterate over collection items.

Basic loop:

html
{{#each posts}}
  <article>
    <h2><a href="{{url}}">{{name}}</a></h2>
    <p>{{excerpt}}</p>
  </article>
{{/each}}

Loop modifiers:

ModifierDescriptionExample
limit=NMaximum items{{#each posts limit=6}}
sort="field"Sort by field{{#each posts sort="publishedAt"}}
order="asc\desc"Sort direction{{#each posts sort="name" order="asc"}}
featured=trueOnly featured items{{#each posts featured=true limit=3}}
where="field.slug:{{slug}}"Filter by relation{{#each posts where="author.slug:{{slug}}"}}
Combined modifiers:
html
<!-- Latest 3 featured posts, newest first -->
{{#each posts featured=true limit=3 sort="publishedAt" order="desc"}}
  <article>{{name}}</article>
{{/each}}

Loop Variables

Available only inside {{#each}} blocks:

VariableDescriptionExample
{{@index}}Zero-based index (0, 1, 2...)Item {{@index}}
{{@first}}True for the first item{{#if @first}}hero{{/if}}
{{@last}}True for the last item{{#unless @last}},{{/unless}}
{{@length}}Total number of itemsShowing {{@length}} items
Do NOT use loop variables outside {{#each}} blocks — they will produce warnings and undefined values.

html
{{#each posts}}
  {{#if @first}}
    <div class="hero">
      <h1>{{name}}</h1>
    </div>
  {{else}}
    <div class="card">
      <h3>{{name}}</h3>
    </div>
  {{/if}}
{{/each}}

Conditionals — {{#if}}, {{#unless}}

html
<!-- Show if field has a value -->
{{#if image}}
  <img src="{{image}}" alt="{{name}}">
{{/if}}

<!-- Show if field has a value, with fallback -->
{{#if thumbnail}}
  <img src="{{thumbnail}}" alt="">
{{else}}
  <div class="placeholder">No image</div>
{{/if}}

<!-- Show if field is empty/missing -->
{{#unless posts}}
  <p>No posts yet.</p>
{{/unless}}

Equality & Comparison Helpers

html
<!-- Equal -->
{{#if (eq status "published")}}
  <span class="badge">Published</span>
{{/if}}

<!-- Not equal — useful for "Related Items" excluding current item -->
{{#unless (eq slug ../slug)}}
  <a href="{{url}}">{{name}}</a>
{{/unless}}

<!-- Numeric comparisons -->
{{#if (lt @index 1)}}   <!-- Less than -->
{{#if (gt @index 0)}}   <!-- Greater than -->
{{#if (lte price 100)}} <!-- Less than or equal -->
{{#if (gte stock 5)}}   <!-- Greater than or equal -->
{{#if (ne status "draft")}} <!-- Not equal -->

Hero + grid layout pattern:

html
{{#each posts}}
  {{#if (lt @index 1)}}
    <div class="hero"><h1>{{name}}</h1></div>
  {{else}}
    {{#if (lt @index 4)}}
      <div class="featured"><h3>{{name}}</h3></div>
    {{else}}
      <div class="list-item">{{name}}</div>
    {{/if}}
  {{/if}}
{{/each}}

Relation Fields — Dot Notation

Access fields on related items using dot notation:

html
{{#each posts}}
  <article>
    <h2>{{name}}</h2>
    {{#if author}}
      <span class="author">By {{author.name}}</span>
      {{#if author.photo}}
        <img src="{{author.photo}}" alt="{{author.name}}">
      {{/if}}
    {{/if}}
  </article>
{{/each}}

Available: {{relation.name}}, {{relation.slug}}, {{relation.url}}, {{relation.anyField}}.

Parent Context — ../

Inside a loop, access the parent scope (the current page's item) with ../:

html
<!-- On an author detail page, show only THIS author's posts -->
<h1>{{name}}</h1>

<h2>Posts by {{name}}</h2>
{{#each posts}}
  {{#if (eq author.name ../name)}}
    <article>
      <h2><a href="{{url}}">{{name}}</a></h2>
    </article>
  {{/if}}
{{/each}}

Nested Loops with @root.

When nesting loops, use @root. to reference root-level collections:

html
{{#each categories}}
  <h3>{{name}}</h3>
  {{#each @root.posts where="category.slug:{{slug}}"}}
    <a href="{{url}}">{{name}}</a>
  {{/each}}
{{/each}}

Inline Editing — data-edit-key (CRITICAL for Static Pages)

Without data-edit-key attributes, static pages have NO editable content in the CMS dashboard. Every text element that should be editable MUST have one.

html
<!-- Static pages — REQUIRED for editable content -->
<h1 data-edit-key="home-hero-title">Welcome to Our Site</h1>
<p data-edit-key="home-hero-subtitle">We build amazing things.</p>
<p data-edit-key="home-about-text">Our story began in 2020...</p>

<!-- Hierarchical naming for sections -->
<section class="about">
  <h2 data-edit-key="about-section-title">About Us</h2>
  <p data-edit-key="about-section-paragraph-1">First paragraph...</p>
  <p data-edit-key="about-section-paragraph-2">Second paragraph...</p>
</section>

<!-- CMS templates — optional, for hardcoded headers -->
<h1 data-edit-key="blog-page-title">Our Blog</h1>

Naming convention: {page}-{section}-{element}

Examples: home-hero-title, about-team-heading, contact-form-intro, services-cta-button

Rules:

  • Keys must be unique across the entire site (not just the page).
  • Use lowercase with hyphens.
  • For different pages, prefix with the page name.
  • Static pages without edit keys will appear in the CMS but have nothing editable.

Video Embeds

html
{{#if video}}
  <iframe
    src="{{video}}"
    allowfullscreen
    referrerpolicy="strict-origin-when-cross-origin"
    title="Video"
  ></iframe>
{{/if}}

The referrerpolicy="strict-origin-when-cross-origin" attribute is required for YouTube embeds — without it, videos may show Error 150/153.

Images — Static vs CMS Content

There are two types of images and they are handled differently:

1. Static/UI images — logos, icons, decorative backgrounds bundled with the site:

html
<!-- KEEP these as static /public/ paths -->
<img src="/public/images/logo.png" alt="Company Logo">
<img src="/public/images/icons/arrow.svg" alt="">

2. CMS content images — post images, team photos, product images managed through the CMS:

html
<!-- USE CMS tokens — NEVER hardcode content image URLs -->
{{#if image}}
  <img src="{{image}}" alt="{{name}}">
{{/if}}

Rule of thumb: If it's site branding/design → keep static. If it's content that changes per item → use CMS tokens.

Always wrap CMS images in {{#if}} — not every item may have an image:

html
{{#if image}}
  <img src="{{image}}" alt="{{name}}">
{{else}}
  <div class="placeholder-image"></div>
{{/if}}

Common mistake — mixing static and CMS images:

html
<!-- WRONG: hardcoded image inside a CMS loop -->
{{#each products}}
  <img src="/images/product-placeholder.jpg" alt="Product">  <!-- BAD -->
  <h2>{{name}}</h2>
{{/each}}

<!-- CORRECT: all content comes from CMS -->
{{#each products}}
  {{#if image}}
    <img src="{{image}}" alt="{{name}}">
  {{/if}}
  <h2>{{name}}</h2>
{{/each}}

Forms

html
<form data-form-name="contact" action="/_forms/contact" method="POST">
  <input type="text" name="name" placeholder="Your name" required>
  <input type="email" name="email" placeholder="Your email" required>
  <textarea name="message" placeholder="Your message" required></textarea>
  <button type="submit">Send Message</button>
</form>

Rules:

  • data-form-name attribute is required.
  • action must point to /_forms/{formName}.
  • All inputs must have name attributes.
  • A submit button is required.
CRITICAL: Remove Original Form Handlers

If the source site has JavaScript that handles form submissions, you MUST remove or replace it. Original site JS often does e.preventDefault() and shows a "fake" success toast — the data goes nowhere.

javascript
// PROBLEM: This blocks real submissions!
form.addEventListener('submit', (e) => {
  e.preventDefault();
  showToast('Message sent!');  // FAKE! Data not saved!
});

Option A (simplest): Remove the original JavaScript form handler entirely. The native

will submit correctly.

Option B (keep JS UX): Replace the handler with one that actually POSTs to FastMode:

javascript
form.addEventListener('submit', async (e) => {
  e.preventDefault();
  const formName = form.dataset.formName;
  const response = await fetch('/_forms/' + formName, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(Object.fromEntries(new FormData(form)))
  });
  if (response.ok) {
    form.reset();
    alert('Message sent!');  // NOW it's real!
  }
});


Deployment & Build Status

How Deployment Works

  • Upload: fastmode deploy site.zip reads the zip, validates it, and uploads it to the server.
  • Build: The server processes the package (renders templates, publishes pages). This happens asynchronously.
  • Wait: By default, deploy polls for build status every 3 seconds until the build completes or times out (default 2 minutes).
  • Result: Success message with page count and version, or failure message with error details.

Deploy Flags

FlagDescription
--forceSkip the GitHub connection check. Use if the project has GitHub connected but you want to deploy via CLI anyway.
--no-waitUpload only — don't wait for the build to finish. Useful for fire-and-forget.
--timeout Custom build timeout in milliseconds. Default: 120000 (2 minutes).

Checking Build Status

After every deploy or content change, check the build status:

bash
fastmode status

If the build failed, status shows:

  • The error message
  • Build logs
  • What went wrong
Always run fastmode status after deploying to verify the build succeeded.

If a build fails:

  • Run fastmode status to see the error
  • Fix the issue (template errors, invalid tokens, missing files, etc.)
  • Re-deploy with fastmode deploy site.zip

Deploy History

bash
fastmode deploys                # Show last 10 deployments
fastmode deploys --limit 5     # Show last 5

Shows status, version, duration, source, and errors for each deployment.

Exit Codes

  • deploy: Exits 1 if the build fails (when waiting).
  • status: Exits 1 if the latest deploy shows "Failed".
  • Both: Exit 1 if no project is specified.

Validation

Always validate before deploying. Validation catches errors that would cause build failures.

Validation Workflow

bash
# 1. Validate the manifest
fastmode validate manifest manifest.json

# 2. Validate each template
fastmode validate template pages/index.html -t static_page
fastmode validate template templates/posts_index.html -t custom_index -c posts
fastmode validate template templates/posts_detail.html -t custom_detail -c posts

# 3. Validate the complete package
fastmode validate package site.zip

What Gets Checked

Manifest validation:

  • Valid JSON syntax
  • pages array exists and is not empty
  • Homepage (path /) exists
  • All file paths are valid
  • cmsTemplates format is correct (flat keys, not nested)
Template validation:
  • Balanced tags: {{#each}} has matching {{/each}}, {{#if}} has {{/if}}
  • Index templates have at least one {{#each}} loop
  • Detail templates have CMS tokens
  • Rich text fields use triple braces {{{field}}}
  • Loop variables only used inside loops
  • Asset paths use /public/ prefix
  • Forms have required attributes
  • YouTube iframes have referrerpolicy
Package validation:
  • manifest.json exists at root
  • All referenced files exist in the zip
  • Assets are in public/ (not assets/ or root)
  • Templates are in templates/ (not collections/)
  • All templates pass individual validation

Validation with Schema Check

Add -p to validate tokens against the actual project schema:

bash
fastmode validate template templates/posts_detail.html -t custom_detail -c posts -p "My Project"

This reports which tokens reference fields that don't exist in the schema yet, with instructions to create them via fastmode schema sync.


Common Mistakes & How to Fix Them

1. Assets return 404

Problem: CSS, JS, or images don't load. Cause: Files are in /assets/ instead of /public/, or paths don't include /public/. Fix: Move all static files to the public/ folder. Reference them as /public/css/style.css.

2. Rich text shows as raw HTML

Problem: Content displays

Hello

as text instead of rendering it. Cause: Using double braces {{body}} on a rich text field. Fix: Use triple braces {{{body}}} for all richText fields.

3. Collection listing page is blank

Problem: Index template shows no items. Cause: Missing {{#each collectionSlug}} loop. Fix: Add a loop: {{#each posts}}...{{/each}}.

4. All detail pages look the same

Problem: Every item page shows identical content. Cause: Detail template has no CMS tokens — just static HTML. Fix: Use tokens like {{name}}, {{{body}}}, {{image}} in the detail template.

5. Manifest uses wrong format

Problem: Build fails with manifest errors. Cause: Using nested objects or "collections" instead of flat "cmsTemplates" keys. Fix: Use flat format: "postsIndex", "postsIndexPath", "postsDetail", "postsDetailPath".

6. Relation field is empty after create

Problem: Created an item with a relation field but it's null. Cause: Used the item's name instead of its UUID. Fix: Run fastmode items relations --field to get the UUID, then use that.

7. Forms don't submit

Problem: Form appears to submit (shows toast/alert) but no data is received. Cause: Original JavaScript calls preventDefault() and shows a fake success message. Fix: Remove any form JavaScript that blocks submission. Use data-form-name and action="/_forms/formName".

8. Static pages can't be edited in CMS

Problem: Pages appear in the CMS but have no editable content. Cause: Missing data-edit-key attributes on text elements. Fix: Add data-edit-key="unique-key" to every text element that should be editable.

9. Deploy blocked by GitHub

Problem: deploy refuses to upload, says GitHub is connected. Cause: Project has GitHub auto-deploy enabled. Fix: Use --force flag: fastmode deploy site.zip --force.

10. Build fails after deploy

Problem: Upload succeeds but build fails. Fix: Run fastmode status to see the error. Common causes: invalid tokens, missing template files, malformed manifest. Fix the issue and re-deploy.

11. Template URLs don't match manifest

Problem: Links in templates point to wrong paths. Cause: Template hardcodes /posts/ but manifest sets "postsIndexPath": "/blog". Fix: Make sure hardcoded links in templates match the paths defined in manifest.json.

12. Loop variables undefined

Problem: {{@index}} or {{@first}} shows nothing. Cause: Used outside of a {{#each}} block. Fix: Only use loop variables inside {{#each}}...{{/each}}.

13. Duplicate SEO meta tags

Problem: SEO tags show up twice in the rendered HTML. Cause: HTML templates include </code>, <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200"><meta name="description"></code>, or Open Graph tags. <strong class="font-semibold">Fix:</strong> Remove all SEO tags from templates. FastMode manages them automatically via CMS Settings. See the <a href="#seo-tags--do-not-include" class="text-primary-600 hover:text-primary-700 underline" target="_blank" rel="noopener noreferrer">SEO Tags section</a> above.</p><p class="my-4 text-gray-700 leading-relaxed"><h3 class="text-xl font-semibold text-gray-900 mt-8 mb-4">14. CSS background images and fonts broken</h3></p><p class="my-4 text-gray-700 leading-relaxed"><strong class="font-semibold">Problem:</strong> Background images or custom fonts don't load. <strong class="font-semibold">Cause:</strong> CSS files use relative paths like <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">url('../images/bg.jpg')</code> or <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">url('../fonts/custom.woff')</code>. <strong class="font-semibold">Fix:</strong> Update all paths inside CSS files to use <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">/public/</code> prefix: <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">url('/public/images/bg.jpg')</code>, <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">url('/public/fonts/custom.woff2')</code>.</p><p class="my-4 text-gray-700 leading-relaxed"><h3 class="text-xl font-semibold text-gray-900 mt-8 mb-4">15. Hardcoded example content instead of CMS tokens</h3></p><p class="my-4 text-gray-700 leading-relaxed"><strong class="font-semibold">Problem:</strong> Index page shows static placeholder cards instead of real CMS data. <strong class="font-semibold">Cause:</strong> Template has hardcoded HTML cards instead of <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">{{#each}}</code> loops with CMS tokens. <strong class="font-semibold">Fix:</strong> Replace hardcoded content blocks with <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">{{#each collection}}...{{/each}}</code> loops using CMS field tokens.</p><p class="my-4 text-gray-700 leading-relaxed"><hr class="my-8 border-t border-gray-300"></p><p class="my-4 text-gray-700 leading-relaxed"><h2 class="text-2xl font-bold text-gray-900 mt-10 mb-6 border-b border-gray-200 pb-2">Pre-Deployment Checklist</h2></p><p class="my-4 text-gray-700 leading-relaxed">Run through this checklist before every deploy:</p><p class="my-4 text-gray-700 leading-relaxed"><strong class="font-semibold">Structure:</strong> <ul class="my-4 space-y-2"><li class="ml-6 mb-2 text-gray-700 list-disc">[ ] <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">manifest.json</code> at package root</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] Static pages in <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">pages/</code> folder</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] CMS templates in <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">templates/</code> folder</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] ALL assets in <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">public/</code> folder (not <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">assets/</code>)</li> </ul> <strong class="font-semibold">SEO (CRITICAL):</strong> <ul class="my-4 space-y-2"><li class="ml-6 mb-2 text-gray-700 list-disc">[ ] NO <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200"><title></code> tags in HTML</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] NO <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200"><meta name="description"></code> tags</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] NO <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200"><meta property="og:*"></code> tags</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] NO <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200"><link rel="icon"></code> tags</li> </ul> <strong class="font-semibold">Manifest:</strong> <ul class="my-4 space-y-2"><li class="ml-6 mb-2 text-gray-700 list-disc">[ ] Homepage page with <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">"path": "/"</code> exists</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] CMS templates use flat <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">cmsTemplates</code> keys (NOT nested, NOT <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">collections</code>)</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] Paths match original site URLs</li> </ul> <strong class="font-semibold">Templates:</strong> <ul class="my-4 space-y-2"><li class="ml-6 mb-2 text-gray-700 list-disc">[ ] Index templates have <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">{{#each}}</code> loops</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] Detail templates have CMS tokens (<code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">{{name}}</code>, <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">{{{body}}}</code>, etc.)</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] Rich text fields use triple braces <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">{{{field}}}</code></li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] All <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">{{#each}}</code> have matching <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">{{/each}}</code></li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] All <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">{{#if}}</code> have matching <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">{{/if}}</code></li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] Static UI images use <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">/public/</code> paths</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] Content images use CMS tokens with <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">{{#if}}</code> wrappers</li> </ul> <strong class="font-semibold">Static Pages:</strong> <ul class="my-4 space-y-2"><li class="ml-6 mb-2 text-gray-700 list-disc">[ ] <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">data-edit-key</code> on every editable text element</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] Keys are unique across the entire site</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] Forms have <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">data-form-name</code> and <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">action="/_forms/{name}"</code></li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] Original form JavaScript handlers removed or replaced</li> </ul> <strong class="font-semibold">Assets:</strong> <ul class="my-4 space-y-2"><li class="ml-6 mb-2 text-gray-700 list-disc">[ ] All HTML asset paths use <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">/public/</code> prefix</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] CSS <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">background-image</code> and font <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">url()</code> paths use <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">/public/</code> prefix</li> <li class="ml-6 mb-2 text-gray-700 list-disc">[ ] External URLs (Google Fonts, CDNs) unchanged</li> </ul> <strong class="font-semibold">Validation:</strong> <div class="relative group my-6"> <div class="absolute top-2 right-2 px-2 py-1 text-xs font-medium text-gray-400 bg-gray-800 rounded">bash</div> <pre class="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto text-sm leading-relaxed"><code class="language-bash">fastmode validate manifest manifest.json fastmode validate template <each-template> -t <type> [-c <collection>] fastmode validate package site.zip</code></pre> </div></p><p class="my-4 text-gray-700 leading-relaxed"><hr class="my-8 border-t border-gray-300"></p><p class="my-4 text-gray-700 leading-relaxed"><h2 class="text-2xl font-bold text-gray-900 mt-10 mb-6 border-b border-gray-200 pb-2">Error Handling & Exit Codes</h2></p><p class="my-4 text-gray-700 leading-relaxed">All commands exit with code <strong class="font-semibold">0</strong> on success and code <strong class="font-semibold">1</strong> on failure.</p><p class="my-4 text-gray-700 leading-relaxed"><h3 class="text-xl font-semibold text-gray-900 mt-8 mb-4">Commands that exit 1</h3></p><p class="my-4 text-gray-700 leading-relaxed"><table class="w-full my-6 border-collapse"><thead><tr><th class="bg-gray-100 px-4 py-2 text-left text-sm font-semibold text-gray-900 border-b-2 border-gray-300">Scenario</th><th class="bg-gray-100 px-4 py-2 text-left text-sm font-semibold text-gray-900 border-b-2 border-gray-300">Commands</th></tr></thead><tbody><tr class="border-b border-gray-200 hover:bg-gray-50"><td class="px-4 py-2 text-sm text-gray-700">No project specified</td><td class="px-4 py-2 text-sm text-gray-700">All project-scoped commands</td></tr><tr class="border-b border-gray-200 hover:bg-gray-50"><td class="px-4 py-2 text-sm text-gray-700">File not found</td><td class="px-4 py-2 text-sm text-gray-700">schema sync, items create -f, validate *</td></tr><tr class="border-b border-gray-200 hover:bg-gray-50"><td class="px-4 py-2 text-sm text-gray-700">Invalid JSON</td><td class="px-4 py-2 text-sm text-gray-700">schema sync, items create -d, items update -d</td></tr><tr class="border-b border-gray-200 hover:bg-gray-50"><td class="px-4 py-2 text-sm text-gray-700">Validation errors</td><td class="px-4 py-2 text-sm text-gray-700">validate manifest, validate template, validate package</td></tr><tr class="border-b border-gray-200 hover:bg-gray-50"><td class="px-4 py-2 text-sm text-gray-700">Build failed</td><td class="px-4 py-2 text-sm text-gray-700">deploy (when waiting), status</td></tr><tr class="border-b border-gray-200 hover:bg-gray-50"><td class="px-4 py-2 text-sm text-gray-700">Delete without --confirm</td><td class="px-4 py-2 text-sm text-gray-700">items delete</td></tr></tbody></table> <h3 class="text-xl font-semibold text-gray-900 mt-8 mb-4">Error Messages</h3></p><p class="my-4 text-gray-700 leading-relaxed"><div class="relative group my-6"> <div class="absolute top-2 right-2 px-2 py-1 text-xs font-medium text-gray-400 bg-gray-800 rounded">text</div> <pre class="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto text-sm leading-relaxed"><code class="language-text">Error: No project specified. Use -p <id-or-name>, set FASTMODE_PROJECT env var, or run: fastmode use <project></code></pre> </div></p><p class="my-4 text-gray-700 leading-relaxed"><div class="relative group my-6"> <div class="absolute top-2 right-2 px-2 py-1 text-xs font-medium text-gray-400 bg-gray-800 rounded">text</div> <pre class="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto text-sm leading-relaxed"><code class="language-text">Error: File not found: schema.json</code></pre> </div></p><p class="my-4 text-gray-700 leading-relaxed"><div class="relative group my-6"> <div class="absolute top-2 right-2 px-2 py-1 text-xs font-medium text-gray-400 bg-gray-800 rounded">text</div> <pre class="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto text-sm leading-relaxed"><code class="language-text">Error: Invalid JSON in --data argument</code></pre> </div></p><p class="my-4 text-gray-700 leading-relaxed"><div class="relative group my-6"> <div class="absolute top-2 right-2 px-2 py-1 text-xs font-medium text-gray-400 bg-gray-800 rounded">text</div> <pre class="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto text-sm leading-relaxed"><code class="language-text">Error: Deletion requires the --confirm flag. This action cannot be undone.</code></pre> </div></p><p class="my-4 text-gray-700 leading-relaxed"><h3 class="text-xl font-semibold text-gray-900 mt-8 mb-4">Authentication Errors</h3></p><p class="my-4 text-gray-700 leading-relaxed">Most commands auto-trigger <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">fastmode login</code> if credentials are missing or expired. If authentication fails: <ul class="my-4 space-y-2"><li class="ml-6 mb-2 text-gray-700 list-decimal">Run <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">fastmode login</code> manually</li> <li class="ml-6 mb-2 text-gray-700 list-decimal">Complete the browser flow</li> <li class="ml-6 mb-2 text-gray-700 list-decimal">Retry the command</li> </ul> <h3 class="text-xl font-semibold text-gray-900 mt-8 mb-4">File Locations</h3></p><p class="my-4 text-gray-700 leading-relaxed"><table class="w-full my-6 border-collapse"><thead><tr><th class="bg-gray-100 px-4 py-2 text-left text-sm font-semibold text-gray-900 border-b-2 border-gray-300">Path</th><th class="bg-gray-100 px-4 py-2 text-left text-sm font-semibold text-gray-900 border-b-2 border-gray-300">Purpose</th></tr></thead><tbody><tr class="border-b border-gray-200 hover:bg-gray-50"><td class="px-4 py-2 text-sm text-gray-700">~/.fastmode/credentials.json</td><td class="px-4 py-2 text-sm text-gray-700">OAuth tokens (auto-created by login)</td></tr><tr class="border-b border-gray-200 hover:bg-gray-50"><td class="px-4 py-2 text-sm text-gray-700">~/.fastmode/config.json</td><td class="px-4 py-2 text-sm text-gray-700">Default project setting (created by use)</td></tr></tbody></table> Both files have restricted permissions (0o600 — owner read/write only).</p><p class="my-4 text-gray-700 leading-relaxed"><hr class="my-8 border-t border-gray-300"></p><p class="my-4 text-gray-700 leading-relaxed"><h2 class="text-2xl font-bold text-gray-900 mt-10 mb-6 border-b border-gray-200 pb-2">Notes</h2> <ul class="my-4 space-y-2"><li class="ml-6 mb-2 text-gray-700 list-disc">All project-scoped commands use your default project (set with <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">fastmode use</code>). Override with <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">-p <name-or-id></code>.</li> <li class="ml-6 mb-2 text-gray-700 list-disc">Item data (<code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">-d</code>) must be valid JSON. For complex data, write a file and use <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">-f data.json</code>.</li> <li class="ml-6 mb-2 text-gray-700 list-disc">Rich text fields accept HTML content (e.g. <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200"><p></code>, <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200"><h2></code>, <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200"><ul></code>, <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200"><a></code>). Always use triple braces in templates.</li> <li class="ml-6 mb-2 text-gray-700 list-disc">Relation fields require item IDs (UUIDs). Use <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">fastmode items relations</code> to find available IDs.</li> <li class="ml-6 mb-2 text-gray-700 list-disc">The <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">--draft</code> flag creates unpublished items. Use <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">--publish</code>/<code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">--unpublish</code> to change status.</li> <li class="ml-6 mb-2 text-gray-700 list-disc">Every site gets free hosting, free SSL, and a <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">.fastmode.ai</code> subdomain. Custom domains can be configured.</li> <li class="ml-6 mb-2 text-gray-700 list-disc">After deploying or making content changes, always run <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">fastmode status</code> to verify the build succeeded.</li> <li class="ml-6 mb-2 text-gray-700 list-disc">Use <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">fastmode examples <type></code> and <code class="px-1.5 py-0.5 text-sm text-primary-700 bg-primary-50 rounded font-mono border border-primary-200">fastmode guide [section]</code> for built-in documentation and code snippets.</li> </ul> <hr class="my-8 border-t border-gray-300"></p><p class="my-4 text-gray-700 leading-relaxed"><h2 class="text-2xl font-bold text-gray-900 mt-10 mb-6 border-b border-gray-200 pb-2">Package Provenance</h2> <ul class="my-4 space-y-2"><li class="ml-6 mb-2 text-gray-700 list-disc"><strong class="font-semibold">npm package:</strong> <a href="https://www.npmjs.com/package/fastmode-cli" class="text-primary-600 hover:text-primary-700 underline" target="_blank" rel="noopener noreferrer">fastmode-cli</a></li> <li class="ml-6 mb-2 text-gray-700 list-disc"><strong class="font-semibold">Source code:</strong> <a href="https://github.com/arihgoldstein/fastmode-mcp" class="text-primary-600 hover:text-primary-700 underline" target="_blank" rel="noopener noreferrer">github.com/arihgoldstein/fastmode-mcp</a></li> <li class="ml-6 mb-2 text-gray-700 list-disc"><strong class="font-semibold">Website:</strong> <a href="https://fastmode.ai" class="text-primary-600 hover:text-primary-700 underline" target="_blank" rel="noopener noreferrer">fastmode.ai</a></li> <li class="ml-6 mb-2 text-gray-700 list-disc"><strong class="font-semibold">Author:</strong> Arih Goldstein</li> <li class="ml-6 mb-2 text-gray-700 list-disc"><strong class="font-semibold">License:</strong> MIT</li> </ul></p></div> </div> </div> <!-- Installation --> <section class="card" aria-labelledby="installation-heading" data-astro-cid-jrlgpo3w> <h2 id="installation-heading" class="text-2xl font-bold text-gray-900 mb-4" data-astro-cid-jrlgpo3w>Installation</h2> <div class="code-block-container relative group " data-astro-cid-i4kugh4e> <div class="flex items-center justify-between px-4 py-2 bg-gray-800 border-b border-gray-700 rounded-t-lg" data-astro-cid-i4kugh4e> <span class="text-sm text-gray-300 font-mono" data-astro-cid-i4kugh4e>Terminal</span> <span class="text-xs text-gray-500 uppercase" data-astro-cid-i4kugh4e>bash</span> </div> <div class="relative" data-astro-cid-i4kugh4e> <pre class="!mt-0 !rounded-t-none" data-astro-cid-i4kugh4e><code id="code-935ph3tmz" class="language-bash" data-astro-cid-i4kugh4e> openclaw install fastmode </code></pre> <!-- Copy Button --> <button class="copy-button absolute top-2 right-2 p-2 bg-gray-700 hover:bg-gray-600 text-gray-300 rounded-lg transition-all duration-200 opacity-0 group-hover:opacity-100 focus:opacity-100" data-code-id="code-935ph3tmz" aria-label="Copy code to clipboard" data-astro-cid-i4kugh4e> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-i4kugh4e> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" data-astro-cid-i4kugh4e></path> </svg> <span class="copy-text sr-only" data-astro-cid-i4kugh4e>Copy</span> </button> <!-- Copied Indicator --> <div class="copied-indicator absolute top-2 right-14 px-3 py-1.5 bg-green-600 text-white text-sm rounded-lg opacity-0 transition-opacity duration-200 pointer-events-none" data-astro-cid-i4kugh4e> Copied! </div> </div> </div> <script>(function(){const codeId = "code-935ph3tmz"; const copyButton = document.querySelector(`[data-code-id="${codeId}"]`); const copiedIndicator = document.querySelector('.copied-indicator'); if (copyButton) { copyButton.addEventListener('click', async () => { const codeElement = document.getElementById(codeId); const code = codeElement?.textContent || ''; try { await navigator.clipboard.writeText(code); // Show copied state copyButton.classList.add('copied'); copiedIndicator?.classList.remove('opacity-0'); // Reset after 2 seconds setTimeout(() => { copyButton.classList.remove('copied'); copiedIndicator?.classList.add('opacity-0'); }, 2000); } catch (err) { console.error('Failed to copy code:', err); } }); } })();</script> </section> <!-- Verification Command (if available from enhanced data) --> <!-- Code Examples (if available) --> <div class="card" data-astro-cid-cpq6uwpo><h2 class="text-2xl font-bold text-gray-900 mb-6 flex items-center" data-astro-cid-cpq6uwpo><span class="text-2xl mr-2" data-astro-cid-cpq6uwpo>💻</span>Code Examples</h2><div class="space-y-6" data-astro-cid-cpq6uwpo><div class="code-example" data-astro-cid-cpq6uwpo><h3 class="text-lg font-semibold text-gray-900 mb-2" data-astro-cid-cpq6uwpo># Fix the issue, then re-deploy</h3><div class="relative" data-astro-cid-cpq6uwpo><div class="flex items-center justify-between bg-gray-800 text-gray-300 px-4 py-2 rounded-t-lg text-sm" data-astro-cid-cpq6uwpo><span class="font-mono" data-astro-cid-cpq6uwpo>-fix-the-issue-then-re-deploy.txt</span><button class="copy-btn px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white rounded text-xs font-medium transition-colors" data-astro-cid-cpq6uwpo> Copy Code </button></div><pre class="bg-gray-900 text-gray-100 p-4 rounded-b-lg overflow-x-auto text-sm leading-relaxed" data-astro-cid-cpq6uwpo><code class="language-text" data-astro-cid-cpq6uwpo>--- ## CRITICAL: Before You Build Anything **STOP. Before writing ANY HTML, templates, or manifest.json, complete these steps.** ### Step 1: Check for Existing Projects</code></pre></div></div><div class="code-example" data-astro-cid-cpq6uwpo><h3 class="text-lg font-semibold text-gray-900 mb-2" data-astro-cid-cpq6uwpo>fastmode projects</h3><div class="relative" data-astro-cid-cpq6uwpo><div class="flex items-center justify-between bg-gray-800 text-gray-300 px-4 py-2 rounded-t-lg text-sm" data-astro-cid-cpq6uwpo><span class="font-mono" data-astro-cid-cpq6uwpo>fastmode-projects.txt</span><button class="copy-btn px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white rounded text-xs font-medium transition-colors" data-astro-cid-cpq6uwpo> Copy Code </button></div><pre class="bg-gray-900 text-gray-100 p-4 rounded-b-lg overflow-x-auto text-sm leading-relaxed" data-astro-cid-cpq6uwpo><code class="language-text" data-astro-cid-cpq6uwpo>This lists all the user's existing FastMode projects. ### Step 2: Decide — Existing or New Project **If projects exist:** Ask the user: "Is this website for one of your existing projects, or should I create a new one?" Let the user choose. **If NO projects exist:** This is a new user — ask: "What would you like to name your new project?" ### Step 3a: For EXISTING Projects 1. User selects the project from the list 2. Run `fastmode use "Project Name"` to set it as default 3. Run `fastmode schema show` to get the current collections and fields 4. **Use this schema to build templates with the correct field names** ### Step 3b: For NEW Projects 1. Ask for the project name if you don't have it 2. Run `fastmode projects create "Project Name"` 3. Run `fastmode use "Project Name"` 4. You'll create the schema later with `fastmode schema sync` 5. Optionally generate sample content: `fastmode generate-samples` ### Checkpoint — Confirm Before Continuing | Requirement | How to Get It | |-------------|---------------| | Project selected/created | `fastmode projects` / `fastmode projects create` | | Default set | `fastmode use "Project Name"` | | Schema known (existing) | `fastmode schema show` | **If you don't have a project set, DO NOT PROCEED.** Go back to Step 1. **WHY THIS MATTERS:** - For existing projects: The schema determines which fields to use in templates — get it wrong and the build fails - For new projects: You need the project before you can deploy - Always: The user must confirm which project to use — never assume --- ## Website Analysis (Do This Before Writing Code) Before writing any HTML or templates, analyze the site: 1. **Map ALL URLs** — document every page path (`/`, `/about`, `/blog`, `/blog/post-slug`, etc.) 2. **Categorize each page** — Static (fixed content), List (shows multiple items), or Detail (single item from a collection) 3. **Identify collections** — repeating content that should be CMS-managed (blog posts, team members, products, testimonials, etc.) 4. **Document assets** — all CSS, JS, image, and font file locations 5. **PRESERVE original URLs** — if the site uses `/resources` for articles, keep `/resources`. Do NOT change it to `/blog`. Use the manifest's path configuration. --- ## Command Reference ### Authentication</code></pre></div></div><div class="code-example" data-astro-cid-cpq6uwpo><h3 class="text-lg font-semibold text-gray-900 mb-2" data-astro-cid-cpq6uwpo>fastmode whoami # Show current user email and name</h3><div class="relative" data-astro-cid-cpq6uwpo><div class="flex items-center justify-between bg-gray-800 text-gray-300 px-4 py-2 rounded-t-lg text-sm" data-astro-cid-cpq6uwpo><span class="font-mono" data-astro-cid-cpq6uwpo>fastmode-whoami--show-current-user-email-and-name.txt</span><button class="copy-btn px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white rounded text-xs font-medium transition-colors" data-astro-cid-cpq6uwpo> Copy Code </button></div><pre class="bg-gray-900 text-gray-100 p-4 rounded-b-lg overflow-x-auto text-sm leading-relaxed" data-astro-cid-cpq6uwpo><code class="language-text" data-astro-cid-cpq6uwpo>- `login` uses OAuth 2.0 device authorization flow: opens a browser window where the user approves access on `fastmode.ai`, then credentials are saved automatically. The browser is only needed for this one-time login step. - **OAuth scopes:** The token grants access to the user's FastMode projects only (project management, schema editing, content CRUD, deployments). No third-party service access is requested. - Credentials persist at `~/.fastmode/credentials.json` with restricted file permissions (`0o600` — owner read/write only). Treat this file as a sensitive secret. - Tokens auto-refresh. If a token expires, the next command will refresh it silently using the stored refresh token. - If credentials are missing or invalid, most commands will trigger the login flow automatically. - `logout` deletes `~/.fastmode/credentials.json` and revokes the stored tokens. ### Projects</code></pre></div></div><div class="code-example" data-astro-cid-cpq6uwpo><h3 class="text-lg font-semibold text-gray-900 mb-2" data-astro-cid-cpq6uwpo>fastmode use <project> # Set default project for all commands</h3><div class="relative" data-astro-cid-cpq6uwpo><div class="flex items-center justify-between bg-gray-800 text-gray-300 px-4 py-2 rounded-t-lg text-sm" data-astro-cid-cpq6uwpo><span class="font-mono" data-astro-cid-cpq6uwpo>fastmode-use-project--set-default-project-for-all-commands.txt</span><button class="copy-btn px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white rounded text-xs font-medium transition-colors" data-astro-cid-cpq6uwpo> Copy Code </button></div><pre class="bg-gray-900 text-gray-100 p-4 rounded-b-lg overflow-x-auto text-sm leading-relaxed" data-astro-cid-cpq6uwpo><code class="language-text" data-astro-cid-cpq6uwpo>- `projects create` checks for existing projects with similar names. Use `--force` to skip. - Subdomain auto-generated from name if not provided (lowercase, hyphens, max 30 chars). - `use` stores the default in `~/.fastmode/config.json`. Does NOT validate the project exists. ### Schema</code></pre></div></div><div class="code-example" data-astro-cid-cpq6uwpo><h3 class="text-lg font-semibold text-gray-900 mb-2" data-astro-cid-cpq6uwpo>fastmode schema field-types # List all available field types (no auth needed)</h3><div class="relative" data-astro-cid-cpq6uwpo><div class="flex items-center justify-between bg-gray-800 text-gray-300 px-4 py-2 rounded-t-lg text-sm" data-astro-cid-cpq6uwpo><span class="font-mono" data-astro-cid-cpq6uwpo>fastmode-schema-field-types--list-all-available-field-types-no-auth-needed.txt</span><button class="copy-btn px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white rounded text-xs font-medium transition-colors" data-astro-cid-cpq6uwpo> Copy Code </button></div><pre class="bg-gray-900 text-gray-100 p-4 rounded-b-lg overflow-x-auto text-sm leading-relaxed" data-astro-cid-cpq6uwpo><code class="language-text" data-astro-cid-cpq6uwpo>- `schema show` requires authentication and a project. - `schema sync` reads a local JSON file and creates/updates the schema. Skips duplicates. Two-phase: creates collections first, then fields (handles relation dependencies). - `schema field-types` works without authentication. ### Content Items</code></pre></div></div><div class="code-example" data-astro-cid-cpq6uwpo><h3 class="text-lg font-semibold text-gray-900 mb-2" data-astro-cid-cpq6uwpo>fastmode items relations posts --field author # Options for specific field</h3><div class="relative" data-astro-cid-cpq6uwpo><div class="flex items-center justify-between bg-gray-800 text-gray-300 px-4 py-2 rounded-t-lg text-sm" data-astro-cid-cpq6uwpo><span class="font-mono" data-astro-cid-cpq6uwpo>fastmode-items-relations-posts---field-author--options-for-specific-field.txt</span><button class="copy-btn px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white rounded text-xs font-medium transition-colors" data-astro-cid-cpq6uwpo> Copy Code </button></div><pre class="bg-gray-900 text-gray-100 p-4 rounded-b-lg overflow-x-auto text-sm leading-relaxed" data-astro-cid-cpq6uwpo><code class="language-text" data-astro-cid-cpq6uwpo>See the [Content Items](#content-items) section below for detailed rules on data formats, relation fields, and drafts. ### Client Portal Management</code></pre></div></div><div class="code-example" data-astro-cid-cpq6uwpo><h3 class="text-lg font-semibold text-gray-900 mb-2" data-astro-cid-cpq6uwpo>fastmode clients cancel-invite <invitationId> --confirm # REQUIRES --confirm</h3><div class="relative" data-astro-cid-cpq6uwpo><div class="flex items-center justify-between bg-gray-800 text-gray-300 px-4 py-2 rounded-t-lg text-sm" data-astro-cid-cpq6uwpo><span class="font-mono" data-astro-cid-cpq6uwpo>fastmode-clients-cancel-invite-invitationid---confirm--requires---confirm.txt</span><button class="copy-btn px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white rounded text-xs font-medium transition-colors" data-astro-cid-cpq6uwpo> Copy Code </button></div><pre class="bg-gray-900 text-gray-100 p-4 rounded-b-lg overflow-x-auto text-sm leading-relaxed" data-astro-cid-cpq6uwpo><code class="language-text" data-astro-cid-cpq6uwpo>See the [Client Portal Management](#client-portal-management) section below for details on permissions, invite flow, and examples. ### Deployment & Build Status</code></pre></div></div><div class="code-example" data-astro-cid-cpq6uwpo><h3 class="text-lg font-semibold text-gray-900 mb-2" data-astro-cid-cpq6uwpo>fastmode deploys --limit 5 # Limit number of results</h3><div class="relative" data-astro-cid-cpq6uwpo><div class="flex items-center justify-between bg-gray-800 text-gray-300 px-4 py-2 rounded-t-lg text-sm" data-astro-cid-cpq6uwpo><span class="font-mono" data-astro-cid-cpq6uwpo>fastmode-deploys---limit-5--limit-number-of-results.txt</span><button class="copy-btn px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white rounded text-xs font-medium transition-colors" data-astro-cid-cpq6uwpo> Copy Code </button></div><pre class="bg-gray-900 text-gray-100 p-4 rounded-b-lg overflow-x-auto text-sm leading-relaxed" data-astro-cid-cpq6uwpo><code class="language-text" data-astro-cid-cpq6uwpo>See [Deployment & Build Status](#deployment--build-status) below for the full deploy lifecycle. ### Validation</code></pre></div></div><div class="code-example" data-astro-cid-cpq6uwpo><h3 class="text-lg font-semibold text-gray-900 mb-2" data-astro-cid-cpq6uwpo>fastmode validate package site.zip</h3><div class="relative" data-astro-cid-cpq6uwpo><div class="flex items-center justify-between bg-gray-800 text-gray-300 px-4 py-2 rounded-t-lg text-sm" data-astro-cid-cpq6uwpo><span class="font-mono" data-astro-cid-cpq6uwpo>fastmode-validate-package-sitezip.txt</span><button class="copy-btn px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white rounded text-xs font-medium transition-colors" data-astro-cid-cpq6uwpo> Copy Code </button></div><pre class="bg-gray-900 text-gray-100 p-4 rounded-b-lg overflow-x-auto text-sm leading-relaxed" data-astro-cid-cpq6uwpo><code class="language-text" data-astro-cid-cpq6uwpo>- Template types: `custom_index` (collection listing), `custom_detail` (single item), `static_page` (fixed page). - `-c` specifies the collection slug (required for `custom_index` and `custom_detail`). - `-p` validates tokens against the actual project schema (reports missing fields). - All validation commands exit with code 1 on errors — safe for CI/CD pipelines. ### Documentation & Examples</code></pre></div></div><div class="code-example" data-astro-cid-cpq6uwpo><h3 class="text-lg font-semibold text-gray-900 mb-2" data-astro-cid-cpq6uwpo>fastmode generate-samples -c posts team # Specific collections only</h3><div class="relative" data-astro-cid-cpq6uwpo><div class="flex items-center justify-between bg-gray-800 text-gray-300 px-4 py-2 rounded-t-lg text-sm" data-astro-cid-cpq6uwpo><span class="font-mono" data-astro-cid-cpq6uwpo>fastmode-generate-samples--c-posts-team--specific-collections-only.txt</span><button class="copy-btn px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white rounded text-xs font-medium transition-colors" data-astro-cid-cpq6uwpo> Copy Code </button></div><pre class="bg-gray-900 text-gray-100 p-4 rounded-b-lg overflow-x-auto text-sm leading-relaxed" data-astro-cid-cpq6uwpo><code class="language-text" data-astro-cid-cpq6uwpo>Available example types: `manifest_basic`, `manifest_custom_paths`, `blog_index_template`, `blog_post_template`, `team_template`, `downloads_template`, `form_handling`, `asset_paths`, `data_edit_keys`, `each_loop`, `conditional_if`, `nested_fields`, `featured_posts`, `parent_context`, `equality_comparison`, `comparison_helpers`, `youtube_embed`, `nested_collection_loop`, `loop_variables`, `common_mistakes`. Available guide sections: `full`, `first_steps`, `analysis`, `structure`, `seo`, `manifest`, `templates`, `tokens`, `forms`, `assets`, `checklist`, `common_mistakes`. --- ## Project Resolution Every project-scoped command (schema, items, deploy, status, etc.) needs a project. Resolution order: 1. **`-p` / `--project` flag** — explicit on the command: `-p "My Project"` or `-p abc123-uuid` 2. **`FASTMODE_PROJECT` environment variable** — set in shell: `export FASTMODE_PROJECT="My Project"` 3. **Default project** — saved by `fastmode use "My Project"` in `~/.fastmode/config.json` If none is set, the command prints an error and exits with code 1:</code></pre></div></div></div></div> <!-- Configuration Table (if available) --> <!-- Requirements --> <!-- Code Example --> <!-- Testing Notes --> <!-- Tags --> <div class="card" data-astro-cid-jrlgpo3w> <h2 class="text-2xl font-bold text-gray-900 mb-4" data-astro-cid-jrlgpo3w>Tags</h2> <div class="flex flex-wrap gap-2" data-astro-cid-jrlgpo3w> <span class="px-3 py-1.5 text-sm text-gray-600 bg-gray-50 rounded-lg border border-gray-200" data-astro-cid-jrlgpo3w> #web_and-frontend-development </span><span class="px-3 py-1.5 text-sm text-gray-600 bg-gray-50 rounded-lg border border-gray-200" data-astro-cid-jrlgpo3w> #web </span> </div> </div> </div> <!-- Sidebar --> <div class="space-y-6" data-astro-cid-jrlgpo3w> <!-- Quick Info --> <div class="card" data-astro-cid-jrlgpo3w> <h3 class="font-semibold text-gray-900 mb-4" data-astro-cid-jrlgpo3w>Quick Info</h3> <div class="space-y-3 text-sm" data-astro-cid-jrlgpo3w> <div class="flex justify-between" data-astro-cid-jrlgpo3w> <span class="text-gray-600" data-astro-cid-jrlgpo3w>Category</span> <span class="font-medium text-gray-900" data-astro-cid-jrlgpo3w>Development</span> </div> <div class="flex justify-between" data-astro-cid-jrlgpo3w> <span class="text-gray-600" data-astro-cid-jrlgpo3w>Model</span> <span class="font-medium text-gray-900" data-astro-cid-jrlgpo3w>Claude 3.5</span> </div> <div class="flex justify-between" data-astro-cid-jrlgpo3w> <span class="text-gray-600" data-astro-cid-jrlgpo3w>Complexity</span> <span class="font-medium text-gray-900" data-astro-cid-jrlgpo3w>One-Click</span> </div> <div class="flex justify-between" data-astro-cid-jrlgpo3w> <span class="text-gray-600" data-astro-cid-jrlgpo3w>Author</span> <span class="font-medium text-gray-900" data-astro-cid-jrlgpo3w>arihgoldstein</span> </div> <div class="flex justify-between" data-astro-cid-jrlgpo3w> <span class="text-gray-600" data-astro-cid-jrlgpo3w>Last Updated</span> <span class="font-medium text-gray-900" data-astro-cid-jrlgpo3w>3/10/2026</span> </div> </div> </div> <!-- Model Badge --> <div class="card bg-gradient-to-br from-blue-50 to-indigo-50 border-blue-100" data-astro-cid-jrlgpo3w> <div class="flex items-center justify-between" data-astro-cid-jrlgpo3w> <div class="flex items-center space-x-3" data-astro-cid-jrlgpo3w> <div class="text-3xl" data-astro-cid-jrlgpo3w>🚀</div> <div data-astro-cid-jrlgpo3w> <div class="text-sm text-gray-600" data-astro-cid-jrlgpo3w>Optimized for</div> <div class="font-semibold text-gray-900" data-astro-cid-jrlgpo3w>Claude 3.5</div> </div> </div> <span class="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-lg bg-purple-50 text-purple-700 border border-purple-200 hover:bg-purple-100 transition-colors" title="Optimized for Claude 3.5 Sonnet" data-astro-cid-3xlfahoe> <span data-astro-cid-3xlfahoe>🧠</span> </span> </div> </div> <!-- Install CTA --> <div class="card bg-gradient-to-br from-primary-500 to-primary-600 text-white border-0" data-astro-cid-jrlgpo3w> <h3 class="font-semibold text-lg mb-2" data-astro-cid-jrlgpo3w>Ready to Install?</h3> <p class="text-primary-100 text-sm mb-4" data-astro-cid-jrlgpo3w> Get started with this skill in seconds </p> <div class="bg-white/20 backdrop-blur-sm rounded-lg p-3 font-mono text-sm" data-astro-cid-jrlgpo3w> openclaw install fastmode </div> </div> <!-- External Links (if available) --> <div class="card" data-astro-cid-jrlgpo3w> <h3 class="font-semibold text-gray-900 mb-4" data-astro-cid-jrlgpo3w>Resources</h3> <div class="space-y-3" data-astro-cid-jrlgpo3w> <a href="https://github.com/openclaw/skills/tree/main/skills/arihgoldstein/fastmode/SKILL.md" target="_blank" rel="noopener noreferrer" class="flex items-center justify-between p-3 rounded-lg border border-gray-200 hover:border-primary-300 hover:bg-primary-50 transition-colors" data-astro-cid-jrlgpo3w> <div class="flex items-center space-x-3" data-astro-cid-jrlgpo3w> <div class="text-2xl" data-astro-cid-jrlgpo3w>📂</div> <div data-astro-cid-jrlgpo3w> <div class="font-medium text-gray-900" data-astro-cid-jrlgpo3w>OpenClaw Skills</div> <div class="text-xs text-gray-500" data-astro-cid-jrlgpo3w>View on OpenClaw GitHub</div> </div> </div> <span class="text-primary-600" data-astro-cid-jrlgpo3w>→</span> </a> </div> </div> </div> </div> </div> </section> <section class="section bg-gray-50" data-astro-cid-jrlgpo3w> <div class="container" data-astro-cid-jrlgpo3w> <h2 class="text-2xl font-bold text-gray-900 mb-6" data-astro-cid-jrlgpo3w>Related Skills</h2> <div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6" data-astro-cid-jrlgpo3w> <a href="/skills/4claw/" class="skill-card group block" data-astro-cid-rwasicqo> <!-- Header --> <div class="flex items-start justify-between mb-4" data-astro-cid-rwasicqo> <div class="flex-1" data-astro-cid-rwasicqo> <div class="flex items-center space-x-2 mb-2" data-astro-cid-rwasicqo> <span class="inline-flex items-center px-2 py-0.5 text-xs font-semibold text-green-700 bg-green-50 rounded-full border border-green-200" data-astro-cid-rwasicqo> ✓ Verified </span> <span class="inline-flex items-center px-2 py-0.5 text-xs font-medium text-gray-600 bg-gray-100 rounded-full" data-astro-cid-rwasicqo> 💻 Development </span> </div> <h3 class="text-lg font-semibold text-gray-900 group-hover:text-primary-600 transition-colors" data-astro-cid-rwasicqo> 4claw </h3> </div> </div> <!-- Description --> <p class="text-sm text-gray-600 mb-4 line-clamp-2" data-astro-cid-rwasicqo> 4claw — a moderated imageboard for AI agents. </p> <!-- Badges --> <div class="flex flex-wrap gap-2 mb-4" data-astro-cid-rwasicqo> <span class="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-lg bg-purple-50 text-purple-700 border border-purple-200 hover:bg-purple-100 transition-colors" title="Optimized for Claude 3.5 Sonnet" data-astro-cid-3xlfahoe> <span data-astro-cid-3xlfahoe>🧠</span> <span data-astro-cid-3xlfahoe>Claude-Ready</span> </span> <span class="inline-flex items-center px-2.5 py-1 text-xs font-medium rounded-lg class={complexityInfo.level === 1 ? 'text-green-700 bg-green-50' : complexityInfo.level === 2 ? 'text-blue-700 bg-blue-50' : 'text-purple-700 bg-purple-50'}> {complexityInfo.level === 1 ? '⚡' : complexityInfo.level === 2 ? '🔗' : '🧠'} {complexityInfo.name} </span> </div> <!-- Tags --> {skill.tags.length > 0 && ( <div class=" flex flex-wrap gap-1.5 mb-4" data-astro-cid-rwasicqo> <span class="inline-block px-2 py-1 text-xs text-gray-500 bg-gray-50 rounded border border-gray-100" data-astro-cid-rwasicqo> #ai_and-llms </span> </span></div> )} <!-- Footer Stats --> <div class="flex items-center justify-between pt-4 border-t border-gray-100" data-astro-cid-rwasicqo> <div class="flex items-center space-x-4 text-sm text-gray-500" data-astro-cid-rwasicqo> <div class="flex items-center space-x-1" data-astro-cid-rwasicqo> <span class="text-yellow-500" data-astro-cid-rwasicqo>★</span> <span class="font-medium" data-astro-cid-rwasicqo>4.4</span> <span class="text-xs" data-astro-cid-rwasicqo>(118)</span> </div> <div class="flex items-center space-x-1" data-astro-cid-rwasicqo> <span data-astro-cid-rwasicqo>↓</span> <span class="font-medium" data-astro-cid-rwasicqo>4,990</span> </div> </div> <div class="text-xs text-gray-400" data-astro-cid-rwasicqo> v1.0.0 </div> </div> </a> <a href="/skills/aap-passport/" class="skill-card group block" data-astro-cid-rwasicqo> <!-- Header --> <div class="flex items-start justify-between mb-4" data-astro-cid-rwasicqo> <div class="flex-1" data-astro-cid-rwasicqo> <div class="flex items-center space-x-2 mb-2" data-astro-cid-rwasicqo> <span class="inline-flex items-center px-2 py-0.5 text-xs font-semibold text-green-700 bg-green-50 rounded-full border border-green-200" data-astro-cid-rwasicqo> ✓ Verified </span> <span class="inline-flex items-center px-2 py-0.5 text-xs font-medium text-gray-600 bg-gray-100 rounded-full" data-astro-cid-rwasicqo> 💻 Development </span> </div> <h3 class="text-lg font-semibold text-gray-900 group-hover:text-primary-600 transition-colors" data-astro-cid-rwasicqo> Aap Passport </h3> </div> </div> <!-- Description --> <p class="text-sm text-gray-600 mb-4 line-clamp-2" data-astro-cid-rwasicqo> Agent Attestation Protocol - The Reverse Turing Test. </p> <!-- Badges --> <div class="flex flex-wrap gap-2 mb-4" data-astro-cid-rwasicqo> <span class="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-lg bg-purple-50 text-purple-700 border border-purple-200 hover:bg-purple-100 transition-colors" title="Optimized for Claude 3.5 Sonnet" data-astro-cid-3xlfahoe> <span data-astro-cid-3xlfahoe>🧠</span> <span data-astro-cid-3xlfahoe>Claude-Ready</span> </span> <span class="inline-flex items-center px-2.5 py-1 text-xs font-medium rounded-lg class={complexityInfo.level === 1 ? 'text-green-700 bg-green-50' : complexityInfo.level === 2 ? 'text-blue-700 bg-blue-50' : 'text-purple-700 bg-purple-50'}> {complexityInfo.level === 1 ? '⚡' : complexityInfo.level === 2 ? '🔗' : '🧠'} {complexityInfo.name} </span> </div> <!-- Tags --> {skill.tags.length > 0 && ( <div class=" flex flex-wrap gap-1.5 mb-4" data-astro-cid-rwasicqo> <span class="inline-block px-2 py-1 text-xs text-gray-500 bg-gray-50 rounded border border-gray-100" data-astro-cid-rwasicqo> #ai_and-llms </span> </span></div> )} <!-- Footer Stats --> <div class="flex items-center justify-between pt-4 border-t border-gray-100" data-astro-cid-rwasicqo> <div class="flex items-center space-x-4 text-sm text-gray-500" data-astro-cid-rwasicqo> <div class="flex items-center space-x-1" data-astro-cid-rwasicqo> <span class="text-yellow-500" data-astro-cid-rwasicqo>★</span> <span class="font-medium" data-astro-cid-rwasicqo>4.3</span> <span class="text-xs" data-astro-cid-rwasicqo>(89)</span> </div> <div class="flex items-center space-x-1" data-astro-cid-rwasicqo> <span data-astro-cid-rwasicqo>↓</span> <span class="font-medium" data-astro-cid-rwasicqo>4,621</span> </div> </div> <div class="text-xs text-gray-400" data-astro-cid-rwasicqo> v1.0.0 </div> </div> </a> <a href="/skills/acestep-lyrics-transcription/" class="skill-card group block" data-astro-cid-rwasicqo> <!-- Header --> <div class="flex items-start justify-between mb-4" data-astro-cid-rwasicqo> <div class="flex-1" data-astro-cid-rwasicqo> <div class="flex items-center space-x-2 mb-2" data-astro-cid-rwasicqo> <span class="inline-flex items-center px-2 py-0.5 text-xs font-semibold text-green-700 bg-green-50 rounded-full border border-green-200" data-astro-cid-rwasicqo> ✓ Verified </span> <span class="inline-flex items-center px-2 py-0.5 text-xs font-medium text-gray-600 bg-gray-100 rounded-full" data-astro-cid-rwasicqo> 💻 Development </span> </div> <h3 class="text-lg font-semibold text-gray-900 group-hover:text-primary-600 transition-colors" data-astro-cid-rwasicqo> Acestep Lyrics Transcription </h3> </div> </div> <!-- Description --> <p class="text-sm text-gray-600 mb-4 line-clamp-2" data-astro-cid-rwasicqo> Transcribe audio to timestamped lyrics using OpenAI Whisper or ElevenLabs Scribe API. </p> <!-- Badges --> <div class="flex flex-wrap gap-2 mb-4" data-astro-cid-rwasicqo> <span class="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-lg bg-green-50 text-emerald-700 border border-emerald-200 hover:bg-green-100 transition-colors" title="Works best with GPT-4 and GPT-4 Turbo" data-astro-cid-3xlfahoe> <span data-astro-cid-3xlfahoe>⚡</span> <span data-astro-cid-3xlfahoe>GPT-Optimized</span> </span> <span class="inline-flex items-center px-2.5 py-1 text-xs font-medium rounded-lg class={complexityInfo.level === 1 ? 'text-green-700 bg-green-50' : complexityInfo.level === 2 ? 'text-blue-700 bg-blue-50' : 'text-purple-700 bg-purple-50'}> {complexityInfo.level === 1 ? '⚡' : complexityInfo.level === 2 ? '🔗' : '🧠'} {complexityInfo.name} </span> </div> <!-- Tags --> {skill.tags.length > 0 && ( <div class=" flex flex-wrap gap-1.5 mb-4" data-astro-cid-rwasicqo> <span class="inline-block px-2 py-1 text-xs text-gray-500 bg-gray-50 rounded border border-gray-100" data-astro-cid-rwasicqo> #ai_and-llms </span><span class="inline-block px-2 py-1 text-xs text-gray-500 bg-gray-50 rounded border border-gray-100" data-astro-cid-rwasicqo> #api </span><span class="inline-block px-2 py-1 text-xs text-gray-500 bg-gray-50 rounded border border-gray-100" data-astro-cid-rwasicqo> #script </span> </span></div> )} <!-- Footer Stats --> <div class="flex items-center justify-between pt-4 border-t border-gray-100" data-astro-cid-rwasicqo> <div class="flex items-center space-x-4 text-sm text-gray-500" data-astro-cid-rwasicqo> <div class="flex items-center space-x-1" data-astro-cid-rwasicqo> <span class="text-yellow-500" data-astro-cid-rwasicqo>★</span> <span class="font-medium" data-astro-cid-rwasicqo>3.8</span> <span class="text-xs" data-astro-cid-rwasicqo>(274)</span> </div> <div class="flex items-center space-x-1" data-astro-cid-rwasicqo> <span data-astro-cid-rwasicqo>↓</span> <span class="font-medium" data-astro-cid-rwasicqo>17,648</span> </div> </div> <div class="text-xs text-gray-400" data-astro-cid-rwasicqo> v1.0.0 </div> </div> </a> <a href="/skills/adaptive-suite/" class="skill-card group block" data-astro-cid-rwasicqo> <!-- Header --> <div class="flex items-start justify-between mb-4" data-astro-cid-rwasicqo> <div class="flex-1" data-astro-cid-rwasicqo> <div class="flex items-center space-x-2 mb-2" data-astro-cid-rwasicqo> <span class="inline-flex items-center px-2 py-0.5 text-xs font-semibold text-green-700 bg-green-50 rounded-full border border-green-200" data-astro-cid-rwasicqo> ✓ Verified </span> <span class="inline-flex items-center px-2 py-0.5 text-xs font-medium text-gray-600 bg-gray-100 rounded-full" data-astro-cid-rwasicqo> 💻 Development </span> </div> <h3 class="text-lg font-semibold text-gray-900 group-hover:text-primary-600 transition-colors" data-astro-cid-rwasicqo> Adaptive Suite </h3> </div> </div> <!-- Description --> <p class="text-sm text-gray-600 mb-4 line-clamp-2" data-astro-cid-rwasicqo> A continuously adaptive skill suite that empowers Clawdbot. </p> <!-- Badges --> <div class="flex flex-wrap gap-2 mb-4" data-astro-cid-rwasicqo> <span class="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-lg bg-purple-50 text-purple-700 border border-purple-200 hover:bg-purple-100 transition-colors" title="Optimized for Claude 3.5 Sonnet" data-astro-cid-3xlfahoe> <span data-astro-cid-3xlfahoe>🧠</span> <span data-astro-cid-3xlfahoe>Claude-Ready</span> </span> <span class="inline-flex items-center px-2.5 py-1 text-xs font-medium rounded-lg class={complexityInfo.level === 1 ? 'text-green-700 bg-green-50' : complexityInfo.level === 2 ? 'text-blue-700 bg-blue-50' : 'text-purple-700 bg-purple-50'}> {complexityInfo.level === 1 ? '⚡' : complexityInfo.level === 2 ? '🔗' : '🧠'} {complexityInfo.name} </span> </div> <!-- Tags --> {skill.tags.length > 0 && ( <div class=" flex flex-wrap gap-1.5 mb-4" data-astro-cid-rwasicqo> <span class="inline-block px-2 py-1 text-xs text-gray-500 bg-gray-50 rounded border border-gray-100" data-astro-cid-rwasicqo> #ai_and-llms </span><span class="inline-block px-2 py-1 text-xs text-gray-500 bg-gray-50 rounded border border-gray-100" data-astro-cid-rwasicqo> #bot </span> </span></div> )} <!-- Footer Stats --> <div class="flex items-center justify-between pt-4 border-t border-gray-100" data-astro-cid-rwasicqo> <div class="flex items-center space-x-4 text-sm text-gray-500" data-astro-cid-rwasicqo> <div class="flex items-center space-x-1" data-astro-cid-rwasicqo> <span class="text-yellow-500" data-astro-cid-rwasicqo>★</span> <span class="font-medium" data-astro-cid-rwasicqo>4.7</span> <span class="text-xs" data-astro-cid-rwasicqo>(88)</span> </div> <div class="flex items-center space-x-1" data-astro-cid-rwasicqo> <span data-astro-cid-rwasicqo>↓</span> <span class="font-medium" data-astro-cid-rwasicqo>1,625</span> </div> </div> <div class="text-xs text-gray-400" data-astro-cid-rwasicqo> v1.0.0 </div> </div> </a> </div> </div> </section> </main> <footer class="bg-gray-900 text-gray-300"> <div class="container py-16"> <div class="grid grid-cols-2 md:grid-cols-6 gap-8 mb-12"> <!-- Brand Column --> <div class="col-span-2"> <a href="/" class="flex items-center mb-4"> <!-- SVG Logo --> <img src="/logo.svg" alt="AICLawSkills Logo" class="h-10 w-auto rounded-lg"> </a> <p class="text-sm text-gray-400 mb-6 max-w-sm"> The comprehensive skill library for OpenClaw AI automation platform. Explore verified skills and boost your productivity. </p> <!-- Social Proof Stats --> <div class="mb-6 grid grid-cols-3 gap-4"> <div class="text-center"> <div class="text-2xl font-bold text-white">100%</div> <div class="text-xs text-gray-400">Verified Skills</div> </div> <div class="text-center"> <div class="text-2xl font-bold text-white">Free</div> <div class="text-xs text-gray-400">Open Source</div> </div> <div class="text-center"> <div class="text-2xl font-bold text-white">4.8★</div> <div class="text-xs text-gray-400">User Rating</div> </div> </div> <!-- Trust Badges --> <div class="flex flex-wrap gap-3 mb-6"> <div class="flex items-center gap-2 text-xs text-gray-400 bg-gray-800 px-3 py-1 rounded-full"> <span class="text-green-400">✓</span> 100% Verified </div> <div class="flex items-center gap-2 text-xs text-gray-400 bg-gray-800 px-3 py-1 rounded-full"> <span class="text-blue-400">🛡️</span> Security Audited </div> <div class="flex items-center gap-2 text-xs text-gray-400 bg-gray-800 px-3 py-1 rounded-full"> <span class="text-purple-400">⚡</span> Updated Weekly </div> </div> <div class="flex space-x-4"> <a href="https://github.com" class="text-gray-400 hover:text-white transition-colors" aria-label="GitHub"> <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"> <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"></path> </svg> </a> <a href="https://twitter.com" class="text-gray-400 hover:text-white transition-colors" aria-label="Twitter"> <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"> <path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84"></path> </svg> </a> </div> </div> <!-- Product Links --> <div> <h3 class="text-sm font-semibold text-white uppercase tracking-wider mb-4">Product</h3> <ul class="space-y-3"> <li> <a href="/skills/" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> All Skills </a> </li><li> <a href="/skills/#categories" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Browse by Category </a> </li><li> <a href="/skill-bundles/" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Skill Bundles </a> </li><li> <a href="/skills/category/web-scrapers" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Web Scrapers </a> </li><li> <a href="/skills/category/ecommerce" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> E-commerce </a> </li><li> <a href="/skills/category/social-media" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Social Media </a> </li><li> <a href="/skills/category/development" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Development </a> </li> </ul> </div> <!-- Resources Links --> <div> <h3 class="text-sm font-semibold text-white uppercase tracking-wider mb-4">Resources</h3> <ul class="space-y-3"> <li> <a href="/get-started/" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Documentation </a> </li><li> <a href="/get-started/installation" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Installation </a> </li><li> <a href="/get-started/configuration" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Configuration </a> </li><li> <a href="/get-started/troubleshooting" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Troubleshooting </a> </li> </ul> </div> <!-- Security Links --> <div> <h3 class="text-sm font-semibold text-white uppercase tracking-wider mb-4">🔒 Security</h3> <ul class="space-y-3"> <li> <a href="/security/" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Security Overview </a> </li><li> <a href="/security/5-step-hardening-guide" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> 5-Step Hardening Guide </a> </li><li> <a href="/security/auth-none-dangers" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Why auth:none is Dangerous </a> </li><li> <a href="/security/tailscale-guide" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Tailscale Setup Guide </a> </li> </ul> </div> <!-- Use Cases --> <div> <h3 class="text-sm font-semibold text-white uppercase tracking-wider mb-4">Use Cases</h3> <ul class="space-y-3"> <li> <a href="/use-cases/ecommerce" class="text-sm text-gray-400 hover:text-primary-400 transition-colors flex items-center"> <span class="mr-2">🛒</span> E-commerce </a> </li><li> <a href="/use-cases/development" class="text-sm text-gray-400 hover:text-primary-400 transition-colors flex items-center"> <span class="mr-2">💻</span> Development </a> </li><li> <a href="/use-cases/content-creation" class="text-sm text-gray-400 hover:text-primary-400 transition-colors flex items-center"> <span class="mr-2">📝</span> Content Creation </a> </li> </ul> </div> </div> <!-- Comparisons Section --> <div class="border-t border-gray-800 pt-8 mb-8"> <h3 class="text-sm font-semibold text-white uppercase tracking-wider mb-4">Comparisons</h3> <div class="flex flex-wrap gap-6"> <a href="/comparisons/" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Comparisons </a><a href="/comparisons/skill-comparison/" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Skill Comparison </a><a href="/comparisons/cost-comparison/" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Cost Analysis </a><a href="/comparisons/architecture-comparison/" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Architecture </a><a href="/tools/benchmarks/" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Benchmarks </a><a href="/tools/hardware/" class="text-sm text-gray-400 hover:text-primary-400 transition-colors"> Hardware </a> </div> </div> <!-- Bottom Bar --> <div class="border-t border-gray-800 pt-8 flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0"> <p class="text-sm text-gray-400"> © 2026 AICLawSkills. All rights reserved. </p> <div class="flex space-x-6"> <a href="/legal/about" class="text-sm text-gray-400 hover:text-white transition-colors"> About </a><a href="/legal/privacy" class="text-sm text-gray-400 hover:text-white transition-colors"> Privacy Policy </a><a href="/legal/terms" class="text-sm text-gray-400 hover:text-white transition-colors"> Terms of Service </a><a href="/legal/contact" class="text-sm text-gray-400 hover:text-white transition-colors"> Contact </a> </div> </div> </div> </footer> <div id="search-backdrop" class="search-backdrop hidden fixed inset-0 bg-black/50 z-50 transition-opacity" data-astro-cid-2eu6zh2g></div> <div id="search-modal" class="search-modal hidden fixed inset-0 z-50 flex items-start justify-center pt-[15vh] px-4" data-astro-cid-2eu6zh2g> <div class="relative w-full max-w-2xl bg-white rounded-xl shadow-2xl border border-gray-200 overflow-hidden" data-astro-cid-2eu6zh2g> <!-- Search Input --> <div class="flex items-center px-4 py-3 border-b border-gray-200" data-astro-cid-2eu6zh2g> <svg class="w-5 h-5 text-gray-400 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-2eu6zh2g> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" data-astro-cid-2eu6zh2g></path> </svg> <input id="search-input" type="text" placeholder="Search skills... (e.g., 'shopify', 'email', 'automation')" class="flex-1 outline-none text-gray-900 placeholder-gray-400" data-astro-cid-2eu6zh2g> <div class="flex items-center gap-2 ml-2" data-astro-cid-2eu6zh2g> <kbd class="hidden sm:inline-block px-2 py-1 text-xs font-semibold text-gray-400 bg-gray-100 border border-gray-200 rounded" data-astro-cid-2eu6zh2g>ESC</kbd> </div> </div> <!-- Search Results --> <div id="search-results" class="max-h-[50vh] overflow-y-auto" data-astro-cid-2eu6zh2g> <!-- Empty State --> <div id="search-empty" class="px-4 py-8 text-center text-gray-500" data-astro-cid-2eu6zh2g> <svg class="w-12 h-12 mx-auto mb-3 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-2eu6zh2g> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" data-astro-cid-2eu6zh2g></path> </svg> <p class="text-sm font-medium" data-astro-cid-2eu6zh2g>Start typing to search skills</p> <p class="text-xs mt-1 text-gray-400" data-astro-cid-2eu6zh2g>Search by name, category, or tags</p> </div> <!-- Results will be injected here --> <div id="search-results-list" class="py-2 hidden" data-astro-cid-2eu6zh2g></div> </div> <!-- Footer --> <div class="px-4 py-2 border-t border-gray-200 bg-gray-50 flex items-center justify-between text-xs text-gray-500" data-astro-cid-2eu6zh2g> <div class="flex items-center gap-3" data-astro-cid-2eu6zh2g> <span class="flex items-center gap-1" data-astro-cid-2eu6zh2g> <kbd data-astro-cid-2eu6zh2g>↑</kbd><kbd data-astro-cid-2eu6zh2g>↓</kbd> to navigate </span> <span class="flex items-center gap-1" data-astro-cid-2eu6zh2g> <kbd data-astro-cid-2eu6zh2g>↵</kbd> to select </span> </div> <span id="search-count" data-astro-cid-2eu6zh2g>0 results</span> </div> </div> </div> <script> // Skills data will be injected server-side window.SKILLS_DATA = []; </script> </body></html> <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>