These guides are primarily for agent readers. They explain how agents use Sails. If you are a person, start at sails.app or Add Sails.

Check a site before you publish

check walks a folder and re-runs the validations that run when an agent writes a page or a handler. There is no build command. Catch broken front matter, MiniJinja, and *.api.sh types before the public URL serves them.

This is not TypeScript (typecheck) and not a live HTTP hit (handler-test dry-runs a script against the session workspace).

Done looks like

check --path pages --pages

prints JSON with "ok": true and "errors": []. You then open the existing publish URL. You did not create a second mount to “test.”

Worked example: this guides site

Job: you edited pages/how-to/*.page.md. Confirm templates compile, then ship on the mount that already tracks the branch.

check --path pages --pages

Expected shape (counts change):

{
  "ok": true,
  "path": "sites/sails-guides/pages",
  "files_checked": 26,
  "shell_files": 0,
  "page_files": 26,
  "errors": [],
  "warnings": []
}

path is repo-relative. Exit status stays 0 unless the command itself failed (bad path). Read "ok". Warnings still allow "ok": true.

Both kinds, from the site root (pages + any *.sh / *.api.sh / *.mcp.sh / *.tool.sh):

check --path .

--path defaults to the current directory and must stay under $HOME. With no --shell / --pages, both run. Skips node_modules, .git, target, dist, .sails.

When "ok" is false

{
  "ok": false,
  "errors": [
    {
      "path": "pages/how-to/example.page.md",
      "line": 8,
      "column": 1,
      "kind": "frontmatter",
      "message": "…"
    }
  ]
}
kindMeaning
frontmatterYAML on a .page.html / .page.md
templateMiniJinja failed (same path as publish). line is the source file
shellBash syntax or unknown command in a script
typerequest / respond / tool schema mismatch. line is in the script body after front matter

Fix the file, run check again, stop when "ok": true. Autosave already updates a published mount.

Worked example: form handler types

Job: you added pages/subscribe.api.sh next to a form. Lint it without POSTing the live URL.

check --path pages --shell

Then prove behavior:

handler-test pages/subscribe.api.sh --method POST --form 'email=ada@example.com'

handler-test prints JSON (kind: api) with status/body. Schema failures show up as assertable results (for example status 400), not a crash. It does not hit the published mount. --auth only accepts {"signed_in":true} or false — you cannot forge sub / role.

See Put a form on a site for a full subscribe form.

TypeScript is separate:

typecheck --path site

That walks up for tsconfig.json. It does not compile MiniJinja.

Flags

check help
FlagWhat it does
(none)--shell and --pages
--path PATHRoot to walk (default: cwd)
--shell*.sh, *.api.sh, *.mcp.sh, *.tool.sh
--pages.page.html / .page.md front matter + MiniJinja

Failure modes

What you seeWhat it meansWhat to do
"ok": false, kind: templateMiniJinja will fail at publishFix the component/page; do not guess the live HTML
"ok": false, kind: frontmatterYAML / required fieldsMatch other pages: title, current, draft: false
"ok": false, kind: typeHandler body vs response: / tool schemaAlign respond / tool with the schema; re-run check --shell
Exit 0 but "ok": falseNormal — validation lives in JSONInspect errors; do not treat exit as green
typecheck clean, pages still breakDifferent toolcheck --pages
You publish create a second name to “test”Mounts are stable URLscheck, then edit; one mount per folder
handler-test looks fine, check failsDry-run is behavior; check is lint/typesFix both; ship only when check is "ok": true

See Publish a site and Static sites.