CLI
Detailed reference for the webstir CLI. This expands the high-level overview in solution.md and focuses on concrete behavior, options, and outputs.
Overview
- Single entrypoint:
webstir <command> [options]. - Default command is
watchwhen no command is provided. - Works from the project root created by
init. - Orchestrates builds, the dev web server, the Node API server, and generators.
Usage
webstir <command> [options]
webstir help [command]
Common patterns:
webstir init my-appwebstir init --client-only my-clientwebstir build --cleanwebstir watchwebstir testwebstir installwebstir publishwebstir add-page aboutwebstir add-test auth/loginwebstir add-route userswebstir add-job cleanupwebstir backend-inspectwebstir smoke
Commands
init
Usage: webstir init [--client-only|--server-only] [--project-name|-p <name>] [directory]
What it does:
- Creates a new project from embedded templates (frontend, backend, shared, and types).
- Layout includes
src/frontend/app,src/frontend/pages/<page>,src/backend,src/shared, andtypes/. - Initializes a working dev setup that builds and runs with
webstir watch.
Notes:
- Choose one of
--client-onlyor--server-onlyto limit what is scaffolded. - Without options, generates a full-stack project.
build
Usage: webstir build [--clean]
What it does:
- Compiles TypeScript via
tsc --buildusing the embedded base config. - Processes CSS imports; copies app assets.
- Merges page HTML fragments with
src/frontend/app/app.htmland writes tobuild/frontend/. - Compiles backend code to
build/backend/.
Notes:
--cleanremoves previousbuild/before compiling.--runtime <frontend|backend|all>(or-r) runs only the selected workers. By default the CLI inspectssrc/frontend/src/backendand builds everything that exists.
watch (default)
Usage: webstir watch
What it does:
- Runs an initial
buildandtest(delegating test execution to the Webstir test host). - Starts the dev web server (serves
build/frontend/**) and the Node API server (runsbuild/backend/index.js). - Watches
src/**for changes and performs targeted, incremental rebuilds. - Restarts the Node server on backend changes; notifies browsers via SSE to reload on frontend changes.
- Stops early with an actionable message if framework packages drift, pointing to
webstir install.
Node server readiness and health
- Waits for the
API server runningline on startup and then probes/api/healthbefore declaring ready. - Tuning flags (environment variables):
WEBSTIR_BACKEND_WAIT_FOR_READY=skip— skip waiting for the readiness log lineWEBSTIR_BACKEND_READY_TIMEOUT_SECONDS— readiness wait timeout (default 30)WEBSTIR_BACKEND_HEALTHCHECK=skip— skip the health probe entirelyWEBSTIR_BACKEND_HEALTH_TIMEOUT_SECONDS— per-attempt probe timeout (default 5)WEBSTIR_BACKEND_HEALTH_ATTEMPTS— retries before failing (default 5)WEBSTIR_BACKEND_HEALTH_DELAY_MILLISECONDS— delay between retries (default 250)WEBSTIR_BACKEND_HEALTH_PATH— override the probe path (default/api/health)
- Automatically detects whether frontend and/or backend directories exist and only enables the relevant workers. Override with
--runtime <frontend|backend|all>orWEBSTIR_TEST_RUNTIMEwhen you need to force a mode (e.g., backend-only loops in a full-stack workspace). - Pass
--runtime <frontend|backend|all>(or-r) to limit the tests triggered during watch to a single runtime. The CLI forwards the same value viaWEBSTIR_TEST_RUNTIME, so scripting the behavior is as simple asWEBSTIR_TEST_RUNTIME=backend webstir watch.
test
Usage: webstir test
- Builds the project, ensures the configured test provider is installed (defaults to
@webstir-io/webstir-testing, overridable viaWEBSTIR_TESTING_PROVIDERorwebstir.providers.json), then invokes the Webstir test host. - Executes compiled frontend and backend tests, emitting structured events the .NET bridge relays.
- Prints a pass/fail summary; integrates with CI using standard exit codes.
- Fails fast if recorded package versions drift and directs you to
webstir install. - Automatically skips frontend or backend phases when the workspace lacks those directories. Use
--runtime <frontend|backend|all>(or-r) /WEBSTIR_TEST_RUNTIMEto force a specific scope.
Notes:
- Override the provider with
WEBSTIR_TESTING_PROVIDER=<package>; setWEBSTIR_TESTING_PROVIDER_SPECif you are testing an unpublished build or local checkout. - Add or edit
webstir.providers.jsonin the workspace root to persist provider choices alongside your code. - Provider overrides apply across the manifest run; mixed providers per module are not supported.
- Use
--runtime <frontend|backend|all>(or-r) to override the automatic detection. The same behavior is available viaWEBSTIR_TEST_RUNTIME=<value>if you need to script it.
install
Usage: webstir install [--dry-run|--clean] [--package-manager <npm|pnpm|yarn[@version]>]
What it does:
- Ensures the pinned
@webstir-io/webstir-frontend,@webstir-io/webstir-testing, and@webstir-io/webstir-backendpackages recorded inframework-packages.jsonare installed from the registry and present innode_modules. - Updates the workspace
package.jsonentries to align withframework-packages.json, installs providers referenced inwebstir.providers.json, and runs the selected package manager when drift is detected. - Verifies installed versions against the embedded manifest and exits with guidance if mismatches remain.
Notes:
- Run after upgrading the CLI or whenever your package manager has modified pinned dependencies.
- Safe to run repeatedly; skips work when packages are already in sync.
- Use
--dry-runto preview which packages would be installed or updated without running a package install (non-zero exit code means action is required). - Use
--cleanto remove the cached.webstir/workspace directory before reinstalling (cannot be combined with--dry-run). - Override the tool for a single run with
--package-manager pnpm@8(or-m pnpm@8); omit@versionto use the default Corepack-discovered binary. - Set
WEBSTIR_PACKAGE_MANAGER=pnpm@8 webstir installto persist the override for the current process; leave unset to fall back onpackage.jsonmetadata or lockfiles. - Ensure
.npmrcis configured with credentials (for GitHub Packages, exportGH_PACKAGES_TOKEN) so registry installs succeed.
publish
Usage: webstir publish
What it does:
- Produces optimized assets in
dist/for each page. - Rewrites HTML to reference fingerprinted assets and emits a per-page
manifest.json. - Minifies HTML/CSS/JS and removes comments and source maps.
- Honors
--runtime <frontend|backend|all>(or-r) so you can publish just the backend artifacts when frontend assets are unchanged.
backend-inspect
Usage: webstir backend-inspect [project] [--project-name <name>]
What it does:
- Runs the backend worker (server-only) to refresh
.webstir/backend-manifest.json. - Prints module metadata (contract version, capabilities, routes, jobs) so you can confirm manifest hydration without starting
watch.
Notes:
- Accepts the positional
[project]or--project-nameflag when multiple projects exist in the current directory. - Skips frontend work entirely; run
webstir build --runtime backendfirst if you only want to inspect the last build output without rebuilding.
add-page
Usage: webstir add-page <name>
What it does:
- Scaffolds
index.html,index.css, andindex.tsinsrc/frontend/pages/<name>/. - Ready to build and serve without extra configuration.
- Delegates to the
@webstir-io/webstir-frontendCLI so the scaffold matches the current framework templates.
add-test
Usage: webstir add-test <name-or-path>
What it does:
- Creates a
.test.tsfile under the nearesttests/folder relative to the path provided. - Works for both frontend and backend test locations.
- Uses the
@webstir-io/webstir-testingCLI to write the template and keep dependencies pinned.
add-route
Usage: webstir add-route <name> [--method <METHOD>] [--path <path>] [--fastify] [--project-name <project>]
What it does:
- Adds a backend route entry to
webstir.module.routesinpackage.json. - Defaults to
GET /api/<name>when flags are omitted. - Populates manifest metadata (
summary,description,tags) plus request/response schema references supplied via CLI flags. Schema references follow thekind:name@sourceformat described in the@webstir-io/module-contractschema guidance (kinddefaults tozod,@sourceoptional). - With
--fastify, also scaffoldssrc/backend/server/routes/<name>.tsand attempts to import/register it insrc/backend/server/fastify.tswhen present.
Options:
--methodHTTP method (e.g., GET, POST). Default: GET--pathRoute path (e.g., /api/users). Default:/api/<name>--project-name <project>Target a specific workspace project when multiple exist.--fastifyAlso scaffold a Fastify handler and register it if possible--summary <text>Adds a short human-readable summary to the manifest entry.--description <text>Adds a longer description to the manifest entry.--tags tag1,tag2Comma-separated tags (trimmed and deduped case-insensitively).--params-schema <ref>Reference for route params.--query-schema <ref>Reference for query params.--body-schema <ref>Reference for request bodies.--headers-schema <ref>Reference for request headers.--response-schema <ref>Reference for the success response body.--response-status <code>Overrides the success status code (must be 100-599).--response-headers-schema <ref>Reference for response headers.
Schema flags (--*-schema) expect the kind:name@source string noted above. Omit kind: for Zod schemas and skip @source when the schema lives beside the generator output. Invalid kind values or missing name segments cause CLI validation errors before any files are written.
add-job
Usage: webstir add-job <name> [--schedule <expression>] [--project-name <project>]
What it does:
- Creates
src/backend/jobs/<name>/index.tsand adds an entry towebstir.module.jobsinpackage.json. - The job stub exports a
run()function and is directly executable during development. - Accepts optional metadata so manifest entries stay self-documenting (
description,priority). Priority accepts either integers or arbitrary strings; numeric values are stored as numbers.
Options:
--scheduleOptional schedule string (free-form, often cron-like, e.g.,0 0 * * *). Stored as-is in the manifest.--project-name <project>Target a specific workspace project when multiple exist.--description <text>Adds a longer explanation for the job alongside the manifest entry.--priority <number|string>Stores a numeric priority when parsable or falls back to the provided string unchanged.- After scaffolding, run
node build/backend/jobs/scheduler.js --list|--job <name>|--watch(or the TypeScript equivalent viatsx) to inspect and execute jobs locally. The embedded watcher supports@hourly,@daily,@weekly,@reboot, andrate(n units)expressions; other cron strings are recorded for your production scheduler.
smoke
Usage: webstir smoke [workspace]
What it does:
- Copies the embedded Accounts backend example into
CLI/out/smoke/accounts(unless a workspace path is provided). - Installs dependencies, runs the standard build workflow, and loads
.webstir/backend-manifest.json. - Prints the manifest location, capabilities, and route definitions; exits non-zero when no routes are present.
Notes:
- Provide a workspace path to reuse an existing project instead of copying the example.
- Requires local access to the framework packages; configure
.npmrcor setGH_PACKAGES_TOKENwhen registry installs are needed.
Dev Server & Watch
- Serves
build/over ASP.NET Core with an SSE endpoint for live reload. - Proxies API requests from
/api/*to the Node server. - Clean URLs and sensible cache headers for dev vs. prod.
- File watching uses a buffered queue to avoid thrashing on burst changes.
- Collects client errors at
POST /client-errors(expects JSON, up to 32KB). Responds with204on success; forwards to the error tracking hook.
Change impact:
- Frontend change → rebuild affected page/assets → broadcast reload via SSE.
- Backend change → rebuild backend → restart Node process.
- Shared change → rebuild both sides that depend on shared modules.
Build & Publish Pipelines
HTML:
- Page HTML merges into
src/frontend/app/app.html(requires a<main>element) and is written tobuild/frontend/pages/<page>/index.htmlin dev. - In publish, HTML is minified and rewritten to reference fingerprinted assets listed in a per-page manifest.
CSS:
- Resolves
@importand URL references; copies assets. - In publish, supports optional CSS Modules, autoprefixing, and minification.
JavaScript/TypeScript:
- Uses
tsc --buildwith an embeddedbase.tsconfig.json. - ESM-only module graph.
- Tree-shakes and minifies in publish.
Outputs:
- Dev:
build/frontend/**,build/backend/**with readable output and live-reload. - Prod:
dist/frontend/pages/<page>/index.<timestamp>.{css|js}, HTML with rewritten links, and a per-pagemanifest.json.
Project Layout
- Base HTML:
src/frontend/app/app.htmlcontains a<main>used for page composition. - Pages:
src/frontend/pages/<page>/index.html|css|ts. - App assets:
src/frontend/app/*(copied as-is tobuild/). - Shared types/modules:
src/shared/. - Backend entry:
src/backend/index.ts→build/backend/index.js.
Examples
- Create a full-stack app:
webstir init my-app && cd my-app && webstir watch - Frontend-only app:
webstir init --client-only my-client && cd my-client && webstir watch - Clean build:
webstir build --clean - Add a page:
webstir add-page about && webstir watch - Publish for production:
webstir publish - Refresh framework packages:
webstir install --clean - Run tests with Vitest:
WEBSTIR_TESTING_PROVIDER=@webstir-io/vitest-testing webstir test - Verify backend manifest ingestion:
webstir smoke
Help Output (Sample)
$ webstir --help
webstir - Modern web development build tool
Usage: webstir [command] [options] [path]
Commands:
add-job Add a backend job stub and manifest entry. Metadata flags are documented at https://github.com/webstir-io/webstir-portal/blob/main/docs/reference/cli.md#add-job
add-page Add a new page (frontend only)
add-route Add a backend route entry to the module manifest (package.json). Metadata and schema flags are documented at https://github.com/webstir-io/webstir-portal/blob/main/docs/reference/cli.md#add-route
add-test Scaffold a starter test
build Build the project once
help Show help information
init Initialize a new webstir project
install Synchronize framework package dependencies from the registry
publish Create production build
smoke Run the accounts example through the CLI and report backend manifest routes
test Run tests through the configured provider (defaults to @webstir-io/webstir-testing)
watch Build and watch for changes (default)
Run 'webstir help <command>' for more information on a specific command.
Path parameter:
You can specify a path as the last argument to run commands in a different directory.
Notes:
Workers are injected (IWorkflowWorker); 'add-page' targets the frontend worker.
Examples:
webstir build ./my-project # Build project in ./my-project directory
webstir watch /path/to/project # Watch project at absolute path
webstir init new-app # Initialize new project in new-app directory
WEBSTIR_TESTING_PROVIDER=@webstir-io/vitest-testing webstir test # Run tests with the Vitest provider
webstir install # Sync registry packages and providers
webstir test --help # See provider override guidance
webstir smoke # Run the accounts smoke check and report manifest routes
$ webstir help build
Build the project once
Usage: webstir build [options]
Options:
--clean Clean build directory before building
Examples:
webstir build # Build the project
webstir build --clean # Clean build (removes build directory first)
webstir build ./my-app # Build project in ./my-app directory
Exit Codes
0: Success- Non-zero: Error (build failure, test failure, invalid arguments, or runtime error)
Contributing Notes
- Commands live in
CLI/; workflows and services live inEngine/. Engine/Workflows/orchestratesinit,build,watch,test,publish,add-page,add-test.- Use
AppWorkspaceandEngine/Constants.csfor paths. Avoid manual string manipulation; prefer helpers inEngine.Extensions. - Keep changes minimal and behavior-preserving. Follow .codex/style.md and
.editorconfigwhen editing C#. - Framework packaging commands live in
Framework/Framework.csproj; rundotnet run --project Framework/Framework.csproj -- packages ...when rebuilding bundles.
Related Docs
- High-level solution overview — solution
- Templates — templates
- Testing — orchestrator testing guide, tests
- Workspace and paths — workspace