CLI

The pathmx command manages, serves, and inspects a project from its package.json root. pmx is the short alias.

pmx [--root <path>] [--no-progress] <command>
OptionMeaning
-r, --root <path>Source root. Defaults to ./paths beside package.json
--no-progressDisable animated progress

The global launcher owns init and update. Project commands delegate to the @pathmx/core version pinned by the selected project's package.json, so pmx --version reports the project release. A positional Source root or --root selects that project consistently for Core, .env, Plugins, and command execution. If both roots are supplied, they must resolve to the same directory.

Inside a repo, prefer its package scripts for everyday work: bun run dev, bun run check, and bun run start. For the commands below, bun run pmx uses the installed project CLI without requiring a global launcher. Complete Install and Quickstart first.

Leave pmx dev or pmx serve running while you use other commands. Commands that write Sources, admit Events, retry jobs, or drain jobs hand that work to the running host for the same Source root. The host applies it through its own write queue and worker and updates the running site. Without a running host, the command owns the repository until it finishes. Read-only commands inspect the repository directly. Do not start a second writer against the same state directory to bypass its lock.

The CLI runs with Bun on macOS, Linux, and Windows. Bun may load .env files from the calling directory before PathMX starts. PathMX then loads the selected project's .env without overwriting variables already in the process, including those loaded by Bun. When selecting another project with --root, values from the calling directory therefore take precedence over that project's .env.

To let only PathMX load the selected project's .env, invoke the installed entry with Bun's --no-env-file flag:

bun --no-env-file ./node_modules/@pathmx/core/dist/pathmx.js --root /path/to/project/paths lint

Use the same flag before the TypeScript entrypoint when running Core from source.

Run pmx for a short getting-started workflow, or pmx --help for the full command list. Core command help, such as pmx dev --help, remains available when Plugins are broken or Core dependencies are missing. Top-level help reports unavailable Plugin help separately. pmx help plugins add shows nested command help.

init

Creates a minimal project with pinned PathMX, TypeScript tooling, and dev, start, check, and typecheck package scripts.

pmx init [directory] [--no-install]
OptionMeaning
directoryProject directory. Defaults to .
--no-installWrite files without running bun install

The completion message prints the commands to enter your new project and start it:

pmx init my-course --no-install
cd my-course
bun install
bun run dev

If installation fails after files are created, follow the recovery commands in the error message to finish installing in that directory.

dev

Starts the development server. It watches Sources, rebuilds affected browser bundles, and restarts for engine, Plugin, or Action code changes.

The CLI supervises a separate Bun --watch server process. Explicit Bun runtime arguments are preserved through project-package delegation and server restarts. Imported component modules using moduleRef are also watched, including modules in linked Plugin packages. Correcting a broken module or restoring a deleted import recovers the failed start. Source edits continue through live updates. For example, run a test preload in both the CLI and the server:

bun --preload ./mock.ts node_modules/.bin/pmx dev paths --port 3012

Relative preload paths resolve from the original working directory. Keep preloads safe to run in each process and again after a restart. PathMX still controls the server's watch mode and environment-file loading; a preload is not a browser script.

Editing a .js or .mjs file under the Source root reloads connected pages in that development app. This refreshes the entire browser module graph, including dynamically imported helpers, and resets in-memory page state. Markdown and CSS edits continue to update in place. This script-reload policy does not apply to serve or static publications.

pmx dev [root] [--port <port>] [--verbose] [--admin <actor-source>] [--admin-origin <origin>]
OptionMeaning
-p, --port <port>Port to listen on
--verboseShow detailed development logs
--admin <actor-source>Admit one Actor Source as the loopback repository admin
--admin-origin <origin>Admit the admin only on this HTTPS proxy origin; replaces localhost admission

After starting an admin session, the compact development strip lets you select a repository user and choose Switch. Switching opens that user's home with their normal permissions and saved state. Repository-admin authority is suspended until you select Repository admin and switch back. End session ends the whole development admin session, including while viewing as another user. The selected user persists across page reloads, Source edits, and automatic code restarts. Stopping the dev command ends its sessions; starting it again requires a new admin session.

The switcher uses the existing loopback or explicitly trusted HTTPS origin and requires an active development admin session. It is available with dev --admin; production serve does not enable it. Actions performed while viewing as a user apply to that user's local data.

serve

Starts the production server and keeps connected browsers in sync as authored Markdown and CSS change.

pmx serve [root] [--port <port>] [--host <hostname>]
OptionMeaning
-p, --port <port>Port. Falls back to PATHMX_PORT, then PORT, then 3000
--host <hostname>Bind address. Falls back to PATHMX_HOST, then 0.0.0.0

Set PATHMX_ORIGIN to the one canonical public origin in production. GET /api/runtime/health reports whether the watched Sources are still valid.

export

Writes the anonymous static publication and its route manifest.

pmx export [root] --origin <url> [--base-path <path>] [--out <path>]
OptionMeaning
--origin <url>Canonical public origin. Required
--base-path <path>Public mount path. Defaults to /
-o, --out <path>Output directory. Defaults to dist/ in the project root

The output must not overlap the Source root, including through symlinked parent directories. Files and symlinks cannot be output directories. Export accepts a new or empty directory, or replaces a recognized prior PathMX publication identified by .pathmx/manifest.json. Treat a publication directory as generated output: replacement removes all of its previous contents.

An unrelated nonempty directory is refused. Choose a new or empty directory with --out. The adapter contract lands in .pathmx/manifest.json inside the output.

lint

Lint checks indexed links, declared schemas, compiled Components, and installed Plugin diagnostics. It does not exercise sign-in, Actions, persistence, browser interaction, or a deployment's proxy configuration. Verify those journeys in the running application after authoring checks pass.

Validates Sources, links, compilation, foundation rules, and repository Plugin rules without starting a server. Malformed Source YAML is reported with file coordinates when available; lint continues checking other Sources and exits nonzero when errors remain. Invalid dependencies also identify pages that cannot finish compilation. See Source recovery for development and live-server behavior.

pmx lint [root] [--format text|json]

Run it after every edit. Package and repository Plugins add their own rules to the same report. Text is the default; use JSON for scripts and editors:

pmx lint --format json > lint.json

JSON is a deterministically sorted array of issue records. A clean project returns []. Every record has type and source; the remaining fields depend on the issue:

TypeAdditional fields
link.unresolvedhref, optional label
source.invalidplugin, message
source.warningmessage, optional plugin
[
  {
    "type": "link.unresolved",
    "source": "/index.md",
    "href": "./missing.md",
    "label": "Missing lesson"
  }
]

Lint exits 0 when clean or when only warnings are present, and 1 for unresolved links or authoring errors. If the project cannot load or the command is invalid, stdout has no report; the error goes to stderr with exit code 1.

Plugin authoring issues identify the owning Plugin and Source. Error and warning records may also include code, hint, block, line, and column. Codes are scoped to their Plugin; use (plugin, code) to identify a rule rather than matching message text. block is the Block id. Line and column, when available, are one-based positions in the complete Source file; column requires line. Missing location fields mean the producer does not know an exact location.

Text output includes these details and prints hints as Fix: instructions. Warnings alone exit 0; errors exit 1. Redundant stored Completion keys for derived targets are warnings because the owning Plugin computes their completion.

Schema and expected compilation failures are collected across Sources, including invalid component attributes, unknown components, and malformed query fences or requests. An unexpected Plugin exception names the failing lint hook when applicable, exits 1, and aborts without a JSON report. Treat this as an incomplete check, rather than a clean repository.

Plugin authors can contribute diagnostics with exact locations and recovery hints. This command reads those contributions. Local authoring commands use development setup, so checking a project with Auth does not require production email credentials. serve and export keep their explicit production runtime.

tree

Prints the Source tree with each file's type, Block count, and outgoing and incoming link counts.

pmx tree [root] [--all]
OptionMeaning
--allInclude non-Markdown files

For example, after Quickstart, bun run pmx tree lists index.md, about.md, and the generated layout/navigation Sources with their types and Block counts. Add --all to include CSS, JavaScript, and image files too.

query

Runs the same access-controlled query as a query fence and writes JSON, JSON Lines, or a table.

pmx query <sources|blocks|plugin.name> [options]
OptionMeaning
--from <scope>Canonical or Actor-relative folder scope
--type <type>Source or Block type
--where <field=value>Scalar equality filter. Repeatable
--has <prop>Required registered data prop. Repeatable
--sort <field[:asc|desc]>Result ordering. Repeatable
--limit <number>Maximum result count
--links-to <source-or-block>Sources linking to a Source or Block
--links-from <source>Sources linked from a Source
--no-recursiveExclude nested folders
--input <json>Input for a named plugin.name query
--request <file>Complete request as JSON or YAML, or - for stdin
--as <actor>Inspect through an Actor's effective access
--format <format>json (default), jsonl, or table
pmx query sources --from /docs --type reference --format table

perms

Shows effective read, write, and execute capabilities for one Source, or every Source one Actor can read.

pmx perms [source] [--as <actor>] [--format text|json]
OptionMeaning
sourceSource id or path
--as <actor>Actor id, such as /users/alice.user
--format <format>text (default) or json

Try bun run pmx perms /about.page in the Quickstart project: it reports the page's effective capabilities. After Ada's account setup, compare bun run pmx perms /ada --as /ada.user with the same command without --as. The Home's owner can read/write personal work; anonymous access is denied.

--as is trusted local inspection. It creates no session and does not impersonate the Actor over HTTP.

mv

Moves a Source, an individual asset, or an entire folder and rewrites authored references.

pmx mv lesson.md lessons/lesson.md --dry-run
pmx mv resources/codex codex --dry-run
pmx mv resources/codex codex
pmx mv work.css studio.css --dry-run

Paths are relative to the configured Source root. A Source destination must end in .md; an asset destination must remain a non-Markdown file path. A folder destination must be a new directory location. Existing destinations, overlapping trees, and paths escaping the Source root are rejected. A folder containing an index.md still moves as a folder; name the file explicitly to move only that Source.

An asset move preserves the file's exact bytes and updates indexed references, including Markdown links/images, [@styles] imports, and writable Plugin relations. Relative versus absolute paths, query strings and fragments are preserved. The asset's own contents are unchanged: relative URLs inside CSS or JavaScript imports are not rewritten. The Bun host supports asset moves, including automatic handoff to a running dev or production host. Other adapters must implement storage.moveFile.

A folder move carries all authored files, including binary assets, hidden files, and empty directories. Relative links between moved files retain their spelling. Inbound Markdown links, reference definitions (including typed layouts), HTML anchor hrefs, and writable Plugin relations retarget to the new tree. Relative outbound links to files outside the tree rebase. External URLs stay unchanged. The query Plugin rewrites explicit from: scopes; omitted scopes continue to follow the query's containing directory.

--dry-run lists each file move, shows reference diffs and public URL warnings, and validates the complete plan without writing. --format json includes a tree inventory for folders and move entries with from and destination path for folders and individual assets. Asset preview content is null; bytes are not embedded in the receipt. Apply rechecks the inventory or asset digest, destination, and Source contents before writing.

When durable storage is active, Bun journals individual asset moves with their reference edits and recovers interrupted work before normal access resumes. Conflicting asset bytes or Source edits stop recovery for inspection. Durable folder moves remain unsupported.

The Bun adapter renames the tree and restores text edits and the original tree if a write fails. This provides recovery from handled I/O failures, not a power-loss journal or a lock against another process editing simultaneously. The browser adapter uses one IndexedDB transaction. Custom storage adapters must provide the folder-move capability.

Symbolic links and trees containing excluded control directories such as .git, .pathmx, or node_modules are rejected. Scripts and stylesheets travel unchanged; arbitrary strings in code, frontmatter without a relation contribution, and dynamically interpolated query scopes are outside the rewrite contract.

rm

Removes a Source and unlinks every reference to it.

pmx rm <path> [--dry-run] [--format text|json]

Preview and apply Source edits

Leave pmx dev or pmx serve running while using mv or rm. The CLI contacts that host on the same machine; the same preview and receipt format applies with or without a host. This local handoff does not require browser sign-in and is not exposed through the site's HTTP routes. The host must use the same PathMX release and state directory as the command; otherwise the command asks you to restart the host or use its PATHMX_DB_DIR. If a handoff fails, the CLI reports the error without retrying as a standalone writer. A lost response can follow a completed write: inspect the files before retrying. Restart the host if its local endpoint is no longer reachable.

For both mv and rm, --dry-run shows the proposed file changes as unified diffs and confirms that no files changed. Each diff includes three surrounding context lines and one hunk spanning the changed region. A successful operation reports the distinct changed-file count. Failed operations do not print a completion message.

pmx mv lesson.md lessons/lesson.md --dry-run
pmx rm lesson.md --dry-run --format json
pmx mv lesson.md lessons/lesson.md --format json

JSON output is one object with version: 1, type, changes, and warnings. Changes are ordered by Source-root-relative path, with a leading /.

ResulttypeEach change
Dry runpreviewtype, path, before, after
Successful writeappliedtype, path

Change types are create, replace, delete, and move. A move also includes from. Preview content is the complete file text: before is null for creation, and after is null for deletion. Warnings are strings in the JSON object. Actual writes omit content from their receipt. A Source move reports deletion of the old path and creation of the new path; folder and asset moves use move entries. Reference edits use replace.

A preview is informational; rerunning the command recomputes the plan from the current repository. There is no saved-plan apply command. Failures write an error to stderr, exit 1, and emit no JSON receipt. A filesystem failure during a multi-file write can leave some changes applied; inspect the files before retrying.

plugins

Manages official @pathmx/* package Plugins. Names accept player or @pathmx/player.

pmx plugins list
pmx plugins add <name...>
pmx plugins remove <name...>
pmx plugins update [name...]

add installs from the CLI's release channel and activates the package in package.json#pathmx.plugins. update with no names updates every installed package.

New activations append after existing Plugins. Repeating add preserves their order and configuration. Already-installed packages are checked for activation support before any missing packages are installed. remove changes activation only after Bun succeeds, preserving other configuration and Bun's manifest edits.

If a package operation or activation fails after installation starts, the error reports the observed package state and points to pmx plugins list. A dependency can remain installed when activation fails; inspect that state before retrying.

list shows activated Plugins as active, available but unselected Plugins as inactive, and supporting packages such as Core, React, and UI as installed. Supporting packages do not require Plugin activation.

update

Checks for or installs a newer global CLI from the release channel.

pmx update [--check]

With the optional global launcher installed, run pmx update --check to see whether the channel matches your installed version or offers a newer release. This check does not install anything. pmx update installs the newer global CLI and prints a version-verification step; it does not update a project's pinned packages. Use bun run pmx plugins update for that project workflow.

Plugin commands

Installed Plugins can mount trusted administrator commands beneath their id, such as pmx auth setup, pmx auth doctor, and pmx search <words...>. They appear in pmx --help only when the owning package or repository Plugin is active in the current project.

Search and Auth commands include their own examples. With those Plugins active:

pmx search learning --format json
pmx auth users list --format json

Both commands accept --format table|json|jsonl. JSON returns an array; Auth user records contain name and email, ordered by email. Empty JSON results are [], and empty JSON Lines results write nothing. Table output gives an explicit empty-result message; Auth tables include Email and Name headers.

Output and errors

Inspection results and Source-edit plans go to stdout. CLI logs, export progress, and operation warnings go to stderr, so redirecting output keeps those diagnostics separate. Plugins should use their command context logger for diagnostics and reserve stdout for results.

pmx tree > source-tree.txt
pmx query sources --format json > sources.json
pmx export --origin https://example.com > export.txt 2> export.log

Core command help includes examples and global options. Invalid format flags list the supported choices; ports must be whole numbers from 1 to 65535, and query limits must be nonnegative whole numbers. Missing Source directories report the selected path and commands to select or create a project.

Terminal presentation

Interactive terminals use a cyan accent for headings and the server URL, with text labels for status. pmx dev shows the listening URL, version, Source count, and selected directory. Use pmx dev --verbose for detailed development logs.

Exports show a subtle activity indicator after 350 ms. Fast exports finish without animation. The indicator uses stderr and clears when the operation finishes or fails; warnings remain in scrollback.

pmx export --origin https://example.com --no-progress
NO_COLOR=1 pmx dev

--no-progress disables animation. A nonempty NO_COLOR disables color; combine both for plain, stationary output. CI, dumb terminals, and redirected streams receive no color or animation. Each output stream is checked separately, so redirecting results does not prevent feedback in an interactive stderr.

Image optimization

pmx image optimize --dry-run
pmx image optimize

Inspect authored image uses and generate the sizes those uses request. Dry-run reports planned widths without writing variants. Normal runs reuse the content cache, report byte sizes and failures, and preserve original files. Development and static publishing also generate variants automatically. See Images for supported formats and presentation parameters.

deploy

Install @pathmx/deploy to configure and deploy sites to existing SSH/launchd servers sharing the project's Git repository:

pmx plugins add deploy
pmx deploy init --host user@server --directory /absolute/checkout
pmx deploy --dry-run
pmx deploy

init saves local target configuration. --dry-run checks prerequisites without changing the server. Deployment coordinates live writers, backs up durable state, updates the selected revision, and verifies the restarted site. See Server deployment for setup, maintenance, checkpoint coordination, and recovery requirements.

Durable jobs and Email

Use bun run pmx jobs list, jobs inspect <id>, and jobs operation <id> to inspect saved work. jobs drain --limit 32 runs due jobs now and jobs retry <id> requeues compatible blocked or failed work. With pmx dev or pmx serve running, both go through that host's worker and its effect policy. Without a host, add --production to drain using production effect policy; with a host, --production must match the host's mode. See durable jobs.

When Email is installed, email preview, email send, email list, email inspect, email retry, and email prune manage messages. Sending captures by default; email send --live explicitly requests one real submission. See Email for template arguments and credentials.