Filenames carry meaning. A file's name gives its route, and its last dotted segment gives its type, so a directory listing already explains the site.
This puts the methodology's explicit file types into practice. Choose roles that make sense in your project.
Look at what pmx init created:
my-site/
├── package.json pins Core and defines dev, start, check scripts
├── tsconfig.json types for actions/ and plugins/
├── .gitignore node_modules, .pathmx, dist, .env
└── paths/
├── index.md the home page and default layout declaration
├── site.layout.md content, reference sidebar, and overlay destinations
└── site.css the layout's stylesheet
paths/ is the Source root. Every Markdown file in it is a Source.
The starter layout supports opening Sources alongside a page.
Create paths/notes/energy.note.md:
# Energy notes
Compare how a falling ball and a stretched spring store energy.
Its name follows this pattern:
name[.qualifier...].type.md
energy.note.md name "energy", type "note"
week-1.draft.lab.md name "week-1", qualifier "draft", type "lab"
about.md name "about", type "page"
The last segment before .md is the type. Files with a single segment
are the default type, page. Types are open: any word works, and
Plugins give particular types behavior.
Run bun run pmx tree to see routes and types together:
paths/
├── index.md (page · 1 block)
├── site.layout.md (layout · 1 block)
└── notes/
└── energy.note.md (note · 1 block)
The page is served at /notes/energy.note. Rendered routes include the Source
type: about.md has the default type page and renders at /about.page. Requesting /notes/energy.note.md returns the authored
Markdown itself.
Create paths/notes/index.md:
# Notes
Read the [energy notes](./energy.note.md).
A folder's index.md is that folder's page, served at /notes.
Breadcrumbs and generated links use it automatically.
A project can organize its resources like this:
my-site/
├── package.json dependencies and pathmx.plugins activation
├── paths/ Sources, assets, stylesheets
├── plugins/ custom or configured Plugins: name.plugin.ts
├── actions/ optional modules imported by Plugins
├── .env project environment, loaded by the CLI
├── db/ runtime state owned by Plugins, not committed
└── dist/ output of pmx export
The CLI finds package.json from any nested directory and resolves project
resources beside it. actions/ is only an organizational choice: register custom
Actions explicitly in a repository plugin.
Ready-to-use package Plugins activate through pmx plugins add, which records
them in package.json#pathmx.plugins. See
package setup.
Do not add id to Source frontmatter. Identity comes from the filename, and
pmx lint warns when it finds an ignored override.
The generated tsconfig.json extends Core's public configuration:
{
"extends": "@pathmx/core/tsconfig",
"include": ["actions/**/*", "plugins/**/*"]
}
Run bun run typecheck from the project directory. The configuration enables
strict checking, Bun and DOM types, bundler module resolution, TypeScript import
extensions, and React JSX. It also includes PathMX's asset module declarations.
It checks code without emitting JavaScript; PathMX builds browser clients itself.
Extend include when code lives elsewhere, such as paths/**/*.tsx for literate
components. Keep the inherited files entry so PathMX's declarations remain
available, including in a project that has no TypeScript files yet.
Choose a host with How PathMX runs, then Publish.