CLI
The @pracht/cli package covers development, production builds, inspection, verification, evaluation, scaffolding, previews, and agent integrations.
create-pracht
create-pracht bootstraps a new application, interactively or fully non-interactively for agents and CI.
# Interactive
pnpm create pracht my-app
# Non-interactive manifest app for Node.js
pnpm create pracht my-app --adapter=node --router=manifest --yes
# Pages router, Cloudflare adapter, no install step
pnpm create pracht my-app --adapter=cf --router=pages --skip-install --yes
# Tailwind starter for Vercel
pnpm create pracht my-app --adapter=vercel --template=tailwind --yesOptions:
--adapter=node|cf|netlify|vercel|static— Node.js, Cloudflare Workers, Netlify, Vercel, or pure static output.--router=manifest|pages— explicitsrc/routes.tsrouting or file-systemsrc/pages/routing.--template=minimal|tailwind,--tailwind,--no-tailwind— Tailwind setup.--agent-tools[=core|full],--no-agent-tools— seed or skip the pracht Claude Code skills,.mcp.json, andAGENTS.md/CLAUDE.md.core(the default) seeds five skills;fullseeds the whole catalog. Add more later withpracht skills add.--yes— skip the prompts and use the defaults for anything not passed: apracht-appdirectory, Node, manifest router, no Tailwind, core agent tools.--skip-install— write files without installing dependencies.--no-git— skipgit initand the initial commit.--json— print a machine-readable summary.--dry-run— list files without writing them.
Generated apps include dev, build, and typecheck scripts. Node and Cloudflare starters also include preview; Node starters include start; Cloudflare and Vercel starters include deploy.
pracht dev
Starts the Vite dev server with SSR and HMR.
pracht dev
# Custom port (default: $PORT or 3000)
pracht dev --port 4000
# Isolate Vite's optimizer cache for concurrent dev servers
pracht dev --cache-dir /tmp/pracht-vite-cacheRoutes render server-side on each request. Changes to routes, shells, loaders, and components apply via HMR.
A failing loader, middleware, or render prints one terminal line — phase, route id, request path, and message — next to the browser error overlay. Failures that name none of your files also print their stack; set DEBUG to print it for every failure.
When several dev servers share one checkout, give each its own --cache-dir so they do not race on Vite's optimizer cache (default node_modules/.vite).
The startup banner prints the resolved app graph: routes with render mode, shell, and middleware; API endpoints with methods; and any capabilities with effect class, exposure, and dispatch path.
pracht build
Runs a production build: client bundle, server bundle, and SSG/ISG prerendering.
pracht build
pracht build --analyze # per-route client JS report
pracht build --json # the same report as JSON (implies --analyze)
pracht build --no-budget-fail # warn instead of failing on an exceeded budgetOutput:
dist/client/— static assets with hashed filenames, plus prerendered SSG HTMLdist/server/server.js— server entry module
Node targets run the build with node dist/server/server.js. Cloudflare and Vercel targets use their platform tooling against the build output. Per-route client JS limits are set with budgets.
pracht preview
Builds and serves the production target locally. --skip-build reuses an
existing build for a faster smoke test:
pracht preview
pracht preview --port 4000
pracht preview --skip-build- Node runs
dist/server/server.jswith the host environment. Static servesdist/client/. - Cloudflare runs
wrangler dev. It needs Wrangler and a Wrangler config whosemainisdist/server/worker.js. Put local Worker secrets in a gitignored.dev.vars; shell environment variables are not Worker bindings. - Netlify and Vercel have no faithful local runtime. The command exits 1
and points you to
netlify dev, orvercel buildandvercel dev.
The command stays attached to the preview process and exits with its status.
pracht generate
Scaffolds routes, shells, middleware, API routes, and capabilities using the framework's own conventions.
pracht generate shell --name app
pracht generate middleware --name auth
pracht generate route --path /dashboard --render ssr --shell app --middleware auth
pracht generate api --path /health --methods GET,POST
pracht generate capability --name notes.search --expose http --description "Find notes matching a query."| Subcommand | Flags |
|---|---|
route |
--path (required), --render (ssr default, spa, ssg, isg), --shell, --middleware (comma-separated), --loader, --error-boundary, --static-paths, --title, --revalidate <seconds> (ISG only), --test / --no-test |
shell |
--name (required) |
middleware |
--name (required) |
api |
--path (required), --methods (comma-separated, default GET) |
capability |
--name (required, e.g. notes.search), --effect (read default, write, destructive), --expose (comma-separated http, webmcp, mcp; omit to keep it private), --title, --description (required with --expose) |
Every subcommand accepts --json for machine-readable output.
- Manifest apps register routes, shells, middleware, and capabilities in
src/routes.ts. - Pages-router apps get route files in
src/pages/. Capabilities are auto-discovered fromsrc/capabilities/, so the module declares its ownname. - In pages mode,
generate middleware --name _middlewarescaffolds the rootsrc/pages/_middleware.ts, the only middleware seam; it needs a serverful adapter.generate shellis manifest-only; pages apps add an_app.tsxto the directory it should wrap.
generate route also writes a Playwright smoke test to e2e/<route-id>.spec.ts when the app has a Playwright setup. --test forces it and --no-test skips it. See Generated Smoke Tests.
Git Bash/MSYS on Windows may rewrite a leading / in --path /dashboard into a Windows path. Use PowerShell or CMD, or set MSYS_NO_PATHCONV=1 when invoking the pracht binary directly.
pracht typegen
Generates typed declarations from the resolved app graph, so navigation, API calls, and capability calls check at compile time.
pracht typegen
pracht typegen --check # fail instead of writing when a file is stale (CI)It writes up to three files:
| File | Contents |
|---|---|
src/pracht.d.ts |
route ids, params, loader data, and typed apiFetch() calls |
src/pracht-routes.ts |
the runtime href() helper |
src/pracht-capabilities.d.ts |
each capability's input/output types, effect class, and exposure — written only when the app registers capabilities |
Override any path with --out, --runtime-out, and --capabilities-out; add --json for machine-readable output.
--check compares declarations, not bytes, so reformatting the generated files never fails it. Regenerating leaves a correct file untouched, so pracht typegen and your formatter do not undo each other.
After the first run, pracht dev refreshes the types when route files, the manifest, or an imported definition module change. Re-run pracht typegen after upgrading pracht to pick up newer checks.
pracht doctor
Validates app wiring and reports missing files or configuration drift.
pracht doctor
pracht doctor --jsonIt checks:
vite.config.*exists and registerspracht()- The app manifest or pages-router directory wiring
- Referenced shell, middleware, and route modules
- CLI and adapter package dependencies
- A
tsconfig.jsonwhosemoduleResolutionpredates packageexports("node","node10","classic"), which breaks@pracht/coreimports undertscwhile Vite still builds
pracht inspect
Prints the resolved app graph instead of inferring structure from file names:
pracht inspect # all targets
pracht inspect routes
pracht inspect api
pracht inspect capabilities
pracht inspect agents
pracht inspect build
pracht inspect all --json| Target | Reports |
|---|---|
routes |
Page routes: render and hydration mode, shell, middleware, loader |
api |
API endpoints and their methods |
capabilities |
Capabilities: effect class, exposure, HTTP path, middleware, remote MCP status |
agents |
The agent surface: Web Bot Auth policy and keys, confirmation mode, remote MCP, llms.txt, and per-transport exposure counts |
build |
Adapter, client entry, and CSS/JS manifests, including CSS for routes that ship no JavaScript. Run it after pracht build |
all |
Everything (the default) |
The agents target also flags capabilities that set expose.mcp while
agents.mcp is unconfigured, so nothing serves them.
For remote MCP, the JSON output includes mcpEndpoint, mcpDestructive,
mcpRuntimeStatus, and mcpUnavailableReasons. Text output marks an exposure
mcp(unserved) when a requirement is verifiably missing and mcp(unverified)
when inspection cannot confirm it. See Remote
MCP.
Use --json for stable machine-readable output. Unknown targets and
graph-loading errors exit non-zero. If a registered API or capability module
fails to load, inspect, plan, verify, and the MCP inspection tools fail
and name it rather than report partial metadata.
On Cloudflare, read bindings inside a handler or run(), never at module top
level. Graph commands load your modules without real bindings, so a top-level
binding read or Workers runtime-class construction fails with the API named.
Importing env is fine. See Accessing Cloudflare
bindings.
pracht plan
Semantic app-graph diff against a base git ref. Prints added, removed, and changed routes, API endpoints, capabilities, and constraints — an intent-level changelog for reviewers.
# Snapshot the resolved app graph to .pracht/app-graph.json (commit it)
pracht plan --write
# Diff the live graph against the snapshot committed at origin/main
pracht plan
# Custom base ref, machine-readable, or PR-comment output
pracht plan --base origin/release
pracht plan --json
pracht plan --markdownpracht verify fails when the committed snapshot is stale; run pracht plan --write to refresh it. A ! marks a capability change that widens what agents can reach. See The Route-Graph Lockfile for the workflow.
pracht verify
Runs deterministic checks over adapter wiring, route and API modules, capability contracts, declared constraints, environment safety, and app-graph snapshot freshness:
pracht verify
pracht verify --changed
pracht verify --json--changed narrows file-oriented checks to changed files for a fast local
loop; run the full scope before committing. The command exits 1 when a blocking
check fails. --json emits the checks, scope, and final ok value.
pracht verify webmcp checks the live browser against the capability graph:
pracht verify webmcp --url http://localhost:3000
pracht verify webmcp --start "pracht preview" --json
pracht verify webmcp --start "pracht preview" --scenario evals/notes-webmcp.eval.jsonIt launches an installed Chrome 150+ with WebMCP testing enabled, visits each
route that activates page tools, and exits 1 on startup failure, unsupported
APIs, registration failure, or drift — including tools left behind after
navigation. The dev-only pracht_* tools are ignored. Pracht never downloads a
browser; pin one in CI with --browser.
--url— the running app (defaulthttp://localhost:3000).--start "<command>"— start the app, verify, then stop it, as inpracht eval.--browser <path>— Chrome/Chromium executable; auto-detected when omitted.--timeout <ms>— browser, navigation, and startup timeout (default 10000).--scenario <files>— comma-separated WebMCP eval scenarios whose listed steps also run.--json— machine-readable report.
pracht report
Assembles a PR-ready markdown report from machine truth: the pracht plan diff, pracht verify results, and per-route client JS budgets from the last build.
pracht report
pracht report --base origin/release --out report.md--base sets the git ref (default origin/main); --out writes to a file instead of stdout. See PR Reports from Machine Truth.
pracht eval
Runs scripted agent-task scenarios against a live app's agent surface and exits 1 when any scenario or expectation fails:
pracht eval # evals/**/*.eval.json
pracht eval evals/notes.eval.json
pracht eval --url http://localhost:3000
pracht eval --start "pracht preview" --url http://localhost:3000
pracht eval evals/notes-webmcp.eval.json --browser /pinned/path/to/chrome
pracht eval --jsonA scenario calls the capability HTTP projection by default, the app's remote
MCP endpoint
with "transport": "mcp", or the browser's page tools with "transport": "webmcp" and a "webmcpRoute". See pracht
eval for the scenario
format.
--url overrides every scenario's own URL. --start launches one server for
the run, waits for it to answer, and stops it afterward. pracht preview works
for Node, Cloudflare, and static; Netlify and Vercel need a deployed URL or your
own netlify dev / vercel dev.
--browser pins Chrome for WebMCP scenarios, and --json reports every
scenario and step.
pracht llms
Prints an embedded authoring guide for coding agents: project layout, conventions, constraints, and the verify/plan/report loop.
pracht llms
# Write the guide to llms.txt in the app root
pracht llms --write
# Write it somewhere else (implies --write)
pracht llms --out docs/pracht-guide.mdThe get_docs tool of pracht dev-mcp serves the same guide.
pracht dev-mcp
Starts the authoring Model Context Protocol server over stdio for coding agents:
pracht dev-mcpIt gives the agent writing your code your app's graph: docs, inspection,
doctor, verify, plan, report, typegen, eval, and generators. Register it as a
local MCP server in your client instead of running it by hand; it runs until
the client disconnects. pracht mcp is a deprecated alias that behaves
identically and prints a notice to stderr.
This is not your app's own remote MCP endpoint, which serves your app's operations to end-user agents in production. See The Authoring MCP Server for client registration and the tool reference.
pracht skills
Lists and installs the pracht Claude Code skills from the published agent-skills index:
# The catalog, with a marker on the ones this app already has
pracht skills list
# Install into .claude/skills/
pracht skills add audit-loaders add-dbcreate-pracht seeds five core skills; pracht skills add installs others one
at a time. See Context Cost for why the
default set is small.
add treats the index as untrusted:
- It verifies every download against the index's SHA-256 digest, and rejects the whole index if any entry lacks one.
- The index and skill URLs must use
https;httpis allowed only forlocalhost, e.g. an offline mirror. - It refuses to write through a symlinked
.claude/skillsor skill directory.--forceallows a link that stays inside the project; one that leaves it is always refused.
An installed skill is skipped unless you pass --force. --index <url> points
either subcommand at a different catalog. --json gives machine-readable
output; add --json reports installed, skipped, and failed, and exits
non-zero if anything failed.
Installation
The CLI is included in scaffolded projects. For existing projects, add it as a dev dependency:
pnpm add -D @pracht/cliThen add scripts to your package.json:
{
"scripts": {
"dev": "pracht dev",
"build": "pracht build",
"doctor": "pracht doctor"
}
}