sarde <command> [flags] [project-dir]Every command accepts an optional project directory as the first positional argument. If omitted, the current working directory is used.
build, dev, check-links, and validate stop with not a Sarde site when the project directory has neither the config file (sarde.yaml, or the file named by --config) nor a content/ folder. Passing --content skips this check. When a subfolder holds a site, the error names it and prints the commands to run it. See Troubleshooting.
Global flags
These flags are inherited by all commands.
| Flag | Type | Default | Description |
|---|---|---|---|
--config, -c |
string | sarde.yaml |
Path to the site config file. |
--baseURL |
string | "" |
Override the site base URL. |
--drafts, -D |
bool | false |
Include draft content. |
--future |
bool | false |
Include future-dated content. |
--verbose, -v |
bool | false |
Enable verbose output. sarde build adds phase timings, plugin messages, and the slowest pages. See Build output. |
--quiet, -q |
bool | false |
Suppress informational output. sarde build still prints warnings and errors. |
build
Build the static site from content/ to the output directory.
sarde build [flags] [project-dir]| Flag | Type | Default | Description |
|---|---|---|---|
--output, -o |
string | "" |
Override the output directory. Defaults to build.output. |
--base-path |
string | "" |
Override the URL base path (for subdirectory hosting). |
--content |
string | "" |
Override the content directory path. |
--strict-i18n |
bool | false |
Warn on missing translation keys per language. |
--format |
string | pretty |
Output format: pretty or json. With json, the build result (page counts, duration, per-phase timings, warnings with their source line and column, link check counts, and the slowest pages) is printed to stdout as a single JSON object and the human-readable summary is suppressed. Failures are also machine-readable. See JSON error envelope. |
sarde buildsarde build --output public --draftssarde build /path/to/projectBuild output
sarde build prints a header, the link check result, a table of page counts, and the list of warnings, then a final line that counts every warning. A build with one link warning and two content warnings prints:
Building site with sarde v1.4.0 (linux/amd64)14:02:11 [links] checked 642 links across 3 lanes: 1 warning WARN content/docs/guides/setup.md:42:5 broken anchor ./install.md#prereqs | Total-------------------+------- Pages | 143 Paginator pages | 0 Collections | 2 Bundle assets | 0 Public files | 5 Processed images | 0 Aliases | 4 Sitemaps | 12 warnings: WARN content/docs/reference/route-data.md:603 [lint] heading exceeds 60 characters (62) WARN content/docs/reference/template-api.md [alert] unclosed shortcode "alert"Built 143 pages in 1501 ms, 3 warnings (1 in the log above) Output: /path/to/my-site/dist- Each warning starts with its location,
path:line:colwhen the line is known, relative to the current directory. Terminals that link file paths open the file at that line. - Identical warnings appear once, followed by a count such as
(x3). - Some warnings print while the build runs, such as the link check finding in the example or a missing logo file. The final line counts them as
in the log aboveinstead of repeating them in the list. - In an interactive terminal, one line at the bottom shows the phase in progress and disappears when the build ends. When the output goes to a file, a pipe, or a CI log, the build writes no progress line and no cursor-control characters.
--verboseprints each phase with its duration as the phase finishes, the messages plugins report (such asGenerated sitemap.xml), and the five slowest pages by render time.--quietprints only warnings and errors. A build without warnings prints nothing.
A build lock prevents concurrent sarde build, sarde dev or sarde deploy processes from using the same output directory. The second process exits with another sarde process (pid N, ...) is already writing to output directory. See Troubleshooting if no such process is running.
JSON error envelope
With --format json (on build, dev, and validate), a fatal error is emitted to stdout as a single JSON document before the process exits non-zero:
{"error": { "kind": "config_validation", "message": "config validation failed", "details": [ { "path": "plugins.enabled[0]", "value": "serch", "message": "must be one of: announcements, atom, ...", "allowed": ["announcements", "atom", "..."], "suggestion": "search" } ]}}kind:config_validationfor configuration validation failures (carries per-fielddetails), otherwisebuild_failed/dev_failed/validate_failedwithmessageonly.details[].allowed: present when the failed check was an enumeration, sorted and without duplicates.details[].suggestion: the allowed value closest tovalue, present whenvaluelooks like a typo of one (two edits or fewer). The human-readable error adds it asdid you mean "search"?.
Human-readable error text still goes to stderr in both formats. This envelope is consumed by Sarde Studio; the field names are stable.
dev
Start a local development server with live reload.
sarde dev [flags] [project-dir]| Flag | Type | Default | Description |
|---|---|---|---|
--port, -p |
int | 0 |
Server port. Defaults to server.port or 4727. |
--host |
string | "" |
Host to bind to. Defaults to 127.0.0.1. Use 0.0.0.0 for LAN access. |
--no-drafts |
bool | false |
Exclude draft content. By default, drafts are included in dev mode. |
--base-path |
string | "" |
Override the URL base path. |
--content |
string | "" |
Override the content directory path. |
--watch-stdin |
bool | false |
Exit when stdin closes (for child-process mode). |
--theme-dev |
string | "" |
Path to a theme source directory for live-reload during framework development. |
--check-syntax |
bool | false |
Enable syntax checking for unclosed fenced blocks during rebuilds. |
--format |
string | pretty |
Error output format: pretty or json. With json, a fatal startup error (bad config, port bind) is emitted as a JSON error envelope on stdout before exiting. Normal server logs are unaffected. |
sarde devsarde dev --port 3000 --host 0.0.0.0Draft and expired content are included by default in dev mode. Pass --no-drafts to exclude drafts.
If the requested port is taken, the server tries up to 10 consecutive ports before giving up, and prints the one it bound to. sarde dev takes the same output-directory build lock as sarde build.
check-links
Run link validation without building the site. Checks internal links and optionally probes external URLs.
sarde check-links [flags] [project-dir]| Flag | Type | Default | Description |
|---|---|---|---|
--strict |
bool | false |
Treat all link issues as errors (exit code 1). |
--external |
bool | false |
Also probe external URLs. |
--report |
string | "" |
Report format. pretty, json, or github-actions. |
--base-path |
string | "" |
Override the URL base path. |
--content |
string | "" |
Override the content directory path. |
sarde check-linkssarde check-links --external --report github-actionssarde check-links --report json # findings on stderr; a *failure* is an {"error": {kind, message}} envelope on stdoutAliased as sarde check for backward compatibility.
check-syntax
Scan Markdown files for unclosed, mismatched, or malformed ::: fenced block tags. It follows the renderer's rules: a block closed implicitly by an outer :::/name fence is reported as a warning at its opening line, a :::/name fence that matches no open block is an error and leaves the block open, and a closer with text after the name, such as :::/ note, is reported as malformed.
sarde check-syntax [flags] [project-dir]| Flag | Type | Default | Description |
|---|---|---|---|
--content |
string | "" |
Override the content directory path. |
--format |
string | "pretty" |
Output format. pretty or json. |
sarde check-syntaxsarde check-syntax --format jsonPiping Markdown via stdin activates a single-file mode that outputs JSON diagnostics (used for editor/tooling integration).
validate
Validate site configuration and content without rendering or writing output. Runs discovery, parsing, schema validation, and optionally content linting.
sarde validate [flags] [project-dir]| Flag | Type | Default | Description |
|---|---|---|---|
--lint |
bool | true |
Run content lint rules after validation. Pass --lint=false to disable. |
--strict |
bool | false |
Exit with code 1 if any warnings exist. |
--format |
string | pretty |
Output format: pretty or json. |
sarde validatesarde validate --strict --lint=falseWith --format json, stdout carries one JSON object and nothing else:
{"ok":true,"pages":12,"collections":2,"durationMs":41,"warnings":[ {"file":"docs/start.md","field":"layout","message":"must be one of: default, docs, splash, wide, full, centered, split, presentation (got \"wiki\")","level":"warning"}]}warnings is always present, sorted by file and line. level is warning or error, and line and col are left out when unknown. With --strict and at least one warning, ok is false and the command exits with status 1. A fatal error, such as invalid configuration, prints the JSON error envelope instead.
deploy
Deploy the built site to a hosting provider. Run sarde build first, or pass --build to build and deploy in one run.
sarde deploy [flags] [project-dir]| Flag | Type | Default | Description |
|---|---|---|---|
--provider |
string | "" |
Override the deploy provider. github, netlify, cloudflare, vercel, or custom. |
--output, -o |
string | "" |
Override the output directory. |
--check |
bool | false |
Verify the credentials and access to the configured site or project, then exit without uploading. Not available for custom. |
--build |
bool | false |
Build the site, then deploy it. Cannot be combined with --check. |
--format |
string | pretty |
Output format: pretty or json. |
sarde buildsarde deploy --provider githubsarde deploy --build --provider netlifyWithout --build, the output directory must exist. If it does not, an error prompts to run sarde build first. --check does not need it. With --build, the build sees the --provider override, so the redirect files are written for that host.
The deploy takes the same output-directory build lock as sarde build, and holds it until the upload ends. It fails while sarde dev or another build is writing to the same directory.
Provider tokens come from environment variables: NETLIFY_AUTH_TOKEN, CLOUDFLARE_API_TOKEN and VERCEL_TOKEN. CLOUDFLARE_ACCOUNT_ID and VERCEL_ORG_ID override deploy.account_id and deploy.team_id. See Deployment for each platform.
The command exits with status 0 on success and 1 on any failure.
JSON output
With --format json, stdout carries one JSON object per line and nothing else; diagnostics go to stderr. Every event has "v": 1 and an event field:
| Event | Fields | Sent |
|---|---|---|
start |
provider |
Once, before the deploy begins |
step |
step, message |
At each phase: collect, hash, prepare, upload, finalize, wait |
progress |
step, done, total, bytes, bytes_total |
During hashing and upload, at most every 100 ms, always at completion |
log |
level (info or warn), message |
Warnings, and output of the github and custom providers |
result |
ok, provider, url, deploy_url, deploy_id, admin_url, files_total, files_uploaded, bytes_uploaded, duration_ms |
Last line of a successful deploy |
check |
ok, provider, target_id, target, url, account |
Last line of a successful --check |
With --build, the build prints nothing to stdout. url is the live production address, and deploy_url the permalink of this particular deploy. A failure ends with the error envelope shared by the other commands, with kind deploy_failed (or deploy_check_failed, or build_failed when the --build build fails) and a code:
{"error":{"kind":"deploy_failed","message":"netlify: GET /sites/{site_id} returned HTTP 401: Access Denied","code":"auth"}}| Code | Meaning |
|---|---|
auth |
The token is missing permissions, rejected or expired |
not_found |
The site or project does not exist, or the token cannot see it |
rate_limited |
The provider kept throttling after several retries |
limit |
The site exceeds a provider limit (file count or file size) |
network |
The provider could not be reached |
canceled |
The deploy was interrupted |
config |
A required setting or environment variable is missing |
provider |
Any other provider error |
Fields may be added to events in later releases; a renamed or removed field raises v.
version
Print version, Go runtime, and OS/architecture information.
sarde versionOutput:
sarde v0.1.0Go: go1.21.0OS/Arch: linux/amd64update
Check for and install the latest version from GitHub Releases. For the full update workflow, see Updating Sarde.
sarde update [flags]| Flag | Type | Default | Description |
|---|---|---|---|
--check |
bool | false |
Only check for updates without installing. |
--yes, -y |
bool | false |
Skip the confirmation prompt. |
sarde updatesarde update --checksarde update --yesShows the release notes and release page, then prompts for confirmation before installing. When stdin is not a terminal (scripts, CI), the prompt cannot be answered, so sarde update fails with an error unless --yes is passed.
Releases are cryptographically signed. Every downloaded artifact is verified against the release checksums, and the checksums file itself is verified against an ed25519 signature before the binary is replaced. A release that fails verification is never installed.
If the binary was installed through a package manager, sarde update does not replace it. Instead it suggests the matching upgrade command:
| Install method | Suggested command |
|---|---|
| Homebrew | brew upgrade sarde |
| Scoop | scoop update sarde |
| Chocolatey | choco upgrade sarde |
| winget | winget upgrade sarde |
System package manager (binary under /usr/bin or /usr/lib) |
your distribution's package manager |
Passive update notice
sarde build and sarde dev show a one-line notice when a newer release is available. The lookup runs at most once per 24 hours and caches its result in ~/.sarde/update-check.json. On build, the lookup runs alongside the build and the notice appears after the build summary in the same run. On dev, the notice appears at startup from the previous lookup's cache while a background refresh updates it for next time. Each release is announced only once.
The notice and the background lookup are skipped entirely when any of these apply:
- the
CIenvironment variable is set - the
SARDE_NO_UPDATE_CHECKenvironment variable is set (permanent opt-out) --quietis passed- stderr is not a terminal
- the binary is a dev build
new
Create new content and project scaffolding.
new <collection> <title>
Create a new content file in the specified collection.
sarde new docs "Getting Started"sarde new blog "My First Post"Creates content/<collection>/<slugified-title>.md with frontmatter.
new site [path]
Scaffold a new Sarde project with starter files and example content.
sarde new site mysitesarde new site .Creates the following structure:
mysite/ sarde.yaml kazari.config.yaml .gitignore content/ _index.md blog/ _index.md hello-world.md docs/ _index.md getting-started.md public/ .gitkeep images/ hero-light.svg hero-dark.svg| Flag | Type | Default | Description |
|---|---|---|---|
--template, -t |
string | "" |
Start from a site template instead of the default starter files. A name (course), owner/repo[/path][#ref] for a folder of any public GitHub repository, or a github.com URL. See Template sources. |
Course template
--template course creates a course site: courses with lessons, assignments, and their own announcements and schedule pages, hands-on labs grouped by course, a site-wide announcements page, and a homepage. A sample banner from the announcements plugin appears only on one course's lessons and labs, the Telescope plugin is enabled for quick page navigation, and Scroll to Top, Reading Progress, and Focus Mode help with long pages. /courses/ is a catalog of the courses. The deploy.yml workflow publishes the site to GitHub Pages on every push to main, once the repository's Settings > Pages uses GitHub Actions as its source. Delete it if you host the site elsewhere. Course Template walks through the site and how to customize it. The sample pages use Markdown extensions such as tabs, steps, and collapsible panels. The template is the course/ folder of the sarde-templates repository.
sarde new site my-college --template coursemy-college/ sarde.yaml kazari.config.yaml .gitignore .github/ workflows/ deploy.yml # builds and publishes the site to GitHub Pages content/ _index.md announcements.md courses/ python-essentials/ # one course: _index.md, announcements.md, schedule.md, lessons, assignments/ web-fundamentals/ labs/ python-essentials/ # labs grouped by course, one directory per lab web-fundamentals/ public/ images/ hero-light.svg hero-dark.svgAn unknown template name stops with unknown template "<name>"; available templates: course, and nothing is written. A download that fails also leaves the directory untouched. Like the default scaffold, new site refuses to run where a sarde.yaml already exists.
Template sources
Templates are downloaded from GitHub as an archive, so git is not required. Named templates live in getsarde/sarde-templates, one folder per template. A release of Sarde fetches the tag of that repository that matches its own minor version (v1.5 for Sarde 1.5.x), so a template never relies on an engine feature the installed version lacks. When that tag does not exist yet, the download falls back to main and says so. Development builds use main.
Other forms:
| Value | Fetches |
|---|---|
course#main |
The named template at a branch, tag, or commit instead of the pinned tag. |
owner/repo |
The root of any public GitHub repository, at main. |
owner/repo/path/to/folder#v2 |
A folder of that repository at a ref. |
https://github.com/owner/repo/tree/dev/folder |
The same, as a URL. |
A template's README.md and LICENSE at the folder root are not copied into the site. Everything else is, including a .github/workflows/deploy.yml when the template ships one.
Downloaded archives are cached under ~/.sarde/templates/. A pinned tag is served from the cache without a network request. main and explicit refs are fetched again on every run; when GitHub is unreachable, the cached copy is used and a warning names its date. With no network and no cached copy, the command fails and prints the repository's clone URL.
When the site is created in a subfolder, new site ends with Run 'cd <path>' then 'sarde dev' to start the dev server. Run sarde dev from inside the new folder, not from the folder you ran new site in.
new course <name>
Scaffold a new course directory under content/courses/.
sarde new course web-developmentCreates content/courses/web-development/ with config.yaml and _index.md.
new lesson <course> <name>
Create a new auto-numbered lesson inside a course.
sarde new lesson web-development "Introduction"Creates content/courses/web-development/01-introduction.md. The numeric prefix is automatically incremented based on existing lessons.
new directive <name>
Scaffold a custom ::: block directive.
sarde new directive pullquoteCreates directives/pullquote.yaml (schema), directives/pullquote.html (template), and directives/pullquote.css (styles, bundled into the site stylesheet automatically). Names must be lowercase letters, digits, and hyphens starting with a letter; names that collide with a built-in directive are rejected.
See Custom Directives for the schema and template data.
import
Import content from external sources.
import obsidian <vault-path>
Convert an Obsidian vault to Sarde content. Converts wikilinks, callouts, image embeds, and strips comments.
sarde import obsidian ~/Documents/MyVaultsarde import obsidian ~/Documents/MyVault --collection notes| Flag | Type | Default | Description |
|---|---|---|---|
--collection, -c |
string | "" |
Target collection name. Defaults to the vault folder name. |
--content |
string | "content" |
Content directory path. |
Obsidian allows two images in different folders to share a filename, while Sarde copies them into one flat assets/ directory. When two files share a name but differ in content, the second is saved as <name>-2.<ext>, the third as <name>-3.<ext>, and so on. Each rename prints a warning naming both source files. Markdown references to that name resolve to the first copy, so check the warnings and repoint any embed that should have used the renamed file.
theme
Manage themes.
theme eject
Copy files from the embedded default theme into themes/<name>/ for customization. With no paths, the whole theme is copied. With paths, only those files or directories are copied; everything else keeps falling back to the embedded theme.
sarde theme ejectsarde theme eject layouts/_blog/single.htmlsarde theme eject layouts/components css/blog.csssarde theme eject --name magazine layouts/_blogsarde theme eject --listsarde theme eject --force layouts/_blog/single.htmlPaths use the ejected layout: template directories (_default, _docs, _blog, _slides, _presentation, _labs, _taxonomy, components, partials, shortcodes) live under layouts/; css/, assets/, and theme.yaml sit at the theme root. The embedded form (_blog/single.html) is accepted as well.
assets can only be ejected as a whole directory, because a theme assets/ directory replaces the embedded fonts, vendor scripts, and JS entirely. theme.yaml is copied whenever the destination has none, so the bundled presets stay selectable; with --name, its slug is set to the name.
| Flag | Type | Default | Description |
|---|---|---|---|
--name |
string | default |
Destination directory under themes/. |
--force |
bool | false |
Overwrite the requested files. Without paths, overwrite the whole themes/<name>/ directory. |
--list |
bool | false |
Print every ejectable path and exit. |
theme list
List all available themes: the built-in default theme and any themes installed in themes/.
sarde theme listThe active theme is marked with *.
theme add <source>
Install a theme from a GitHub repository, a URL, or a local directory.
sarde theme add github.com/user/sarde-theme-oceansarde theme add https://example.com/theme.tar.gzsarde theme add ./my-local-theme| Flag | Type | Default | Description |
|---|---|---|---|
--name |
string | "" |
Override the theme directory name. |
Supported sources: GitHub repositories, direct zip/tar.gz URLs, and local directories.
theme remove <name>
Remove an installed theme.
sarde theme remove oceansarde theme remove ocean --force| Flag | Type | Default | Description |
|---|---|---|---|
--force |
bool | false |
Remove even if the theme is currently active. |
The embedded default theme cannot be removed.
theme info <name>
Show details about a theme (name, version, author, license, description, token counts, presets).
sarde theme info defaultsarde theme info oceantheme chromastyles
Generate CSS for a Chroma syntax highlighting style.
sarde theme chromastyles --listsarde theme chromastyles --style monokai --darksarde theme chromastyles --style dracula --output styles.css| Flag | Type | Default | Description |
|---|---|---|---|
--style |
string | "" |
Chroma style name. Defaults to the configured light or dark theme. |
--dark |
bool | false |
Wrap output in [data-theme="dark"] { } scoping. |
--list |
bool | false |
List all available Chroma style names. |
--output, -o |
string | "" |
Write CSS to a file instead of stdout. |
icons
Manage icon sets.
icons add <prefix> [prefix...]
Download Iconify icon sets from the npm registry.
sarde icons add mdisarde icons add mdi lucide tablersarde icons add mdi --dest icons/sets| Flag | Type | Default | Description |
|---|---|---|---|
--dest, -d |
string | "" |
Destination directory. Defaults to icons.sets_dir or icon-sets. |
After downloading, reference icons as :icon[prefix:name] in content.
icons list
List all Iconify icon sets available for download, with local download status.
sarde icons listsarde icons list --search materialsarde icons list --page-size 50| Flag | Type | Default | Description |
|---|---|---|---|
--search, -s |
string | "" |
Filter by prefix, name, or category. |
--page-size, -n |
int | 30 |
Rows per page. Set to 0 to disable pagination. |
Downloaded sets are marked with * in the DL column.
i18n
Manage internationalization: languages and translation files.
The i18n add-language, i18n remove-language, i18n scaffold, i18n status, and i18n strings commands output a single JSON line to stdout instead of human-readable text, for integration with the desktop app.
i18n add-language <project-dir> <code>
Add a language to the project.
sarde i18n add-language . frsarde i18n add-language . zh-hans --name "Chinese (Simplified)" --weight 2| Flag | Type | Default | Description |
|---|---|---|---|
--name |
string | "" |
Display name for the language. |
--weight |
int | 0 |
Sort weight. Lower values sort first. |
--dir |
string | "ltr" |
Text direction. ltr or rtl. |
The language code must match [a-z]{2,3}(-[a-z0-9]+)* (e.g., fr, es, zh-hans). Adds the language to i18n.languages in sarde.yaml. If this is the first language added, sets i18n.default_language to the existing site.language value, or en if unset.
i18n remove-language <project-dir> <code>
Remove a language from the project.
sarde i18n remove-language . frsarde i18n remove-language . fr --delete-content| Flag | Type | Default | Description |
|---|---|---|---|
--delete-content |
bool | false |
Also delete content/<code>/. |
The default language cannot be removed.
i18n scaffold <project-dir> <code>
Scaffold content directories and a translation file for a language.
sarde i18n scaffold . frCreates content/<code>/<collection>/ for each collection of the default language, with a stub _index.md in each. The other languages' folders are not collections, and content.dir is honored. Creates i18n/<code>.yaml, seeded from the default language's translation file if one exists.
The default language has no folder of its own. When content/<default>/ exists, scaffold and status print a warning to stderr: the build reads that folder as a collection named after the language, so its pages never pair with their translations. Move its pages up to content/.
i18n status <project-dir>
Show translation coverage across all languages and collections.
sarde i18n status .Reports, per collection and language, the number of pages in the default language and how many of them have a translation. A page counts as translated when the language has a page at the same path, as the build pairs them: fr/docs/setup.md translates docs/setup.md. A translated page with no default-language source does not count.
i18n strings <project-dir>
List the translation strings of every layer, without merging them.
sarde i18n strings .Prints the default language, the configured languages in weight order, and one entry per layer in load order: the built-in English strings, the active theme's i18n/ folder, and the site's i18n/ folder. Each layer maps a language code to its keys, in dot notation, and their values. Later layers override earlier ones per key.
{ "ok": true, "defaultLanguage": "en", "languages": ["en", "fr"], "layers": [ { "source": "builtin", "strings": { "en": { "nav.toc": "On this page" } } }, { "source": "theme", "dir": "themes/default/i18n", "strings": {} }, { "source": "project", "dir": "i18n", "strings": { "fr": { "nav.toc": "Sur cette page" } } } ], "problems": []}A file that cannot be parsed is listed under problems with its source, file, and message, and its strings are left out. sarde build fails on the same file.
doc-version
Manage docs versioning for a collection.
doc-version create <project-dir> <collection> <version-id>
Cut a new version for a collection. Takes a trailing <label> argument, the human-readable name shown in the version switcher.
sarde doc-version create . docs v1 "Version 1.0"Enables versioning for the collection if not already enabled. Archives the collection's current content into content/<collection>/<old-version>/ (the previous last_version, if any), appends the new version entry, and sets last_version to the new version ID. The version ID cannot contain /, \, or ...
doc-version delete <project-dir> <collection> <version-id>
Delete a version from a collection.
sarde doc-version delete . docs v1Removes the version entry from sarde.yaml and deletes content/<collection>/<version-id>/. The current latest version (last_version) cannot be deleted.
doc-version update <project-dir> <collection> <version-id>
Update a version entry's label, banner, or redirect behavior.
sarde doc-version update . docs v1 --label "Version 1.0 (EOL)" --banner unmaintained| Flag | Type | Default | Description |
|---|---|---|---|
--label |
string | "" |
New display label. |
--banner |
string | "" |
Version banner type. none, unmaintained, or unreleased. |
--redirect |
string | "" |
Redirect behavior. same-page or root. |
Only the flags explicitly passed are updated; omitted flags leave the existing value unchanged.
plugin
Manage external plugins installed in the project's plugins/ directory.
plugin install <source>
Install a plugin from a local zip file, a local directory, a GitHub repository, or a direct zip/tar.gz URL.
sarde plugin install cohort-banner.zipsarde plugin install ./local-plugins/cohort-bannersarde plugin install github.com/example-org/grade-syncsarde plugin install https://example.com/downloads/grade-sync.tar.gzGitHub sources accept a branch and subdirectory: github.com/example-org/plugin-monorepo/tree/main/plugins/grade-sync.
The destination directory always takes the slug declared in the plugin's manifest; there is no rename flag. Installing a premium plugin prints its purchase URL and the license file locations. Installation fails if the plugin is already installed, the manifest is invalid, or the slug collides with a built-in plugin name.
plugin list
List installed external plugins with version, license status, and enabled state.
sarde plugin listSLUG VERSION LICENSE STATUScohort-banner 1.0.0 free enabledgrade-sync 2.1.0 premium (licensed) enabledplugin info <slug>
Show a plugin's manifest details: name, version, author, premium status, license state, injection condition, assets, and output prefix.
sarde plugin info grade-syncplugin remove <slug>
Delete plugins/<slug>/ from the project. License files live outside the plugin directory and are kept.
sarde plugin remove cohort-bannerlicense
Manage licenses for premium plugins.
license install <license-file>
Copy a license file into the license directory and verify it.
sarde license install grade-sync.licensesarde license install grade-sync.license --project| Flag | Type | Default | Description |
|---|---|---|---|
--project |
bool | false |
Install into the project's .sarde/licenses/ instead of the user home directory (~/.sarde/licenses/). |
A license that fails verification is still installed, with a warning that the plugin stays inactive until a valid license is present.
license list
List installed licenses from both the project and user home locations, with validity status.
sarde license listPLUGIN LICENSEE EXPIRES STATUSgrade-sync jane@school.edu never validquiz-widgets jane@school.edu 2026-06-30 license expired on 2026-06-30catalog
Print the frontmatter field catalog: every frontmatter field Sarde recognizes, grouped by category, with the layout-to-category mapping. Used by Sarde Studio to offer field pickers.
sarde catalog [--format pretty|json]| Flag | Type | Default | Description |
|---|---|---|---|
--format |
string | "pretty" |
Output format. pretty or json. |
sarde catalogsarde catalog --format jsonThe pretty format prints fields grouped by category with their type and description, followed by a layout-to-category mapping. The json format outputs the raw catalog structure. This command does not take a project directory argument; the catalog is embedded in the binary.
directives
Print the catalog of ::: block directives Sarde recognizes, grouped by category, with syntax templates and key fields. Used by Sarde Studio to offer a directive picker.
sarde directives [project-dir] [--format pretty|json] [--check]| Flag | Type | Default | Description |
|---|---|---|---|
--format |
string | "pretty" |
Output format. pretty or json. |
--check |
bool | false |
Validate directive definitions only. Prints warnings and exits 1 if any are found. |
The built-in directives are embedded in the binary. Any custom directives in the project's directives/ folder are merged into the output, and every entry carries a source field: builtin for the embedded catalog, site for the project's own. Theme-provided directives are resolved at build time and are not listed here.
--check is a fast lint: it loads and validates the definitions without running a build, so it fits an edit-save loop or a pre-commit hook.
effective-config
Print each content collection's fully resolved configuration, after zero-config inference and any sarde.yaml overrides. Every field is labeled with where its value came from: inferred from the collection directory's name, or sarde_yaml when set explicitly.
sarde effective-config [project-dir] [--format pretty|json]| Flag | Type | Default | Description |
|---|---|---|---|
--format |
string | "pretty" |
Output format. pretty or json. |
Use it to see what a collection is actually doing before overriding anything, which is the quickest way to answer why a directory sorted or laid itself out the way it did.
plugins
Print every plugin that plugins.enabled accepts: the built-in server and client plugins, then the external plugins under the project's plugins/ folder, with their descriptions, default state, and configurable fields. Used by Sarde Studio to render plugin settings.
sarde plugins [project-dir] [--format pretty|json]| Flag | Type | Default | Description |
|---|---|---|---|
--format |
string | "pretty" |
Output format. pretty or json. |
The pretty format prints one line per plugin: id, kind, group, default state, and description.
atom server content on Generate Atom feed per collectionThe json format prints the catalog. Plugins are sorted by kind (server, client, external), then by id. requires lists the ids of plugins a plugin needs enabled, and is left out when empty:
{ "version": 1, "plugins": [ { "id": "rss", "label": "RSS Feed", "kind": "server", "group": "content", "description": "Generate RSS feed per collection", "defaultEnabled": true, "fields": [ { "name": "collections", "type": "list", "label": "Collections", "hint": "Only these collections get a feed (empty means every collection with feed on)", "default": [] }, { "name": "limit", "type": "number", "label": "Item Limit", "hint": "Maximum number of entries per feed", "default": 20, "min": 1, "max": 500 } ] } ]}The output is metadata only: plugins.disabled and premium license checks are not applied, and a build enforces both.
schema
Print the resolved frontmatter schema of one collection: every catalog field that applies to its layout and type, merged with the custom frontmatter_schema from content/<collection>/config.yaml. Used by Sarde Studio to prefill its schema editor.
sarde schema <collection> [project-dir] [--format pretty|json]The collection comes first, before the optional project directory.
| Flag | Type | Default | Description |
|---|---|---|---|
--format |
string | "pretty" |
Output format. pretty or json. |
sarde schema docssarde schema courses ./my-site --format jsonThe pretty format prints a header with the collection's type and layout, then the custom fields and the catalog fields, with nested fields indented. The json format prints collection, layout, type, and a fields map. Each field has its type and a source of catalog or custom, plus whichever of label, description, required, default, min, max, maxLength, options, fields, and items apply.
A collection with neither a content/<collection>/ folder nor a sarde.yaml entry exits with status 1. With --format json, stdout carries the message as {"error":"unknown collection \"guides\": no content/guides directory and no sarde.yaml entry"}.
sarde effective-configsarde effective-config ./my-site --format jsonsidecar
Start the IPC API server for the desktop app. This is an internal command used by the Tauri-based desktop application.
sarde sidecar [flags]| Flag | Type | Default | Description |
|---|---|---|---|
--port, -p |
int | 0 |
Server port. 0 auto-assigns an available port. |
Outputs a JSON line to stdout with ready, port, and token fields for the host process.
render
Render Markdown from stdin to HTML. This is an internal command used for editor preview integration.
echo "# Hello" | sarde renderOutputs JSON with html and headings fields.
Environment variables
Environment variables override all other configuration layers. See the Environment variables section of the Configuration Reference for the full list of supported SARDE_* variables.