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": "…"
}
]
}
kind | Meaning |
|---|---|
frontmatter | YAML on a .page.html / .page.md |
template | MiniJinja failed (same path as publish). line is the source file |
shell | Bash syntax or unknown command in a script |
type | request / 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
| Flag | What it does |
|---|---|
| (none) | --shell and --pages |
--path PATH | Root to walk (default: cwd) |
--shell | *.sh, *.api.sh, *.mcp.sh, *.tool.sh |
--pages | .page.html / .page.md front matter + MiniJinja |
Failure modes
| What you see | What it means | What to do |
|---|---|---|
"ok": false, kind: template | MiniJinja will fail at publish | Fix the component/page; do not guess the live HTML |
"ok": false, kind: frontmatter | YAML / required fields | Match other pages: title, current, draft: false |
"ok": false, kind: type | Handler body vs response: / tool schema | Align respond / tool with the schema; re-run check --shell |
Exit 0 but "ok": false | Normal — validation lives in JSON | Inspect errors; do not treat exit as green |
typecheck clean, pages still break | Different tool | check --pages |
You publish create a second name to “test” | Mounts are stable URLs | check, then edit; one mount per folder |
handler-test looks fine, check fails | Dry-run is behavior; check is lint/types | Fix both; ship only when check is "ok": true |
See Publish a site and Static sites.