A Source is one Markdown file under paths/. Its filename gives it a name, a type, and a route; frontmatter adds metadata.
paths/index.md / type page
paths/syllabus.md /syllabus.page type page
paths/week-1.lab.md /week-1.lab type lab
paths/week-1.draft.lab.md /week-1.draft.lab type lab, qualifier draft
paths/labs/index.md /labs folder page
Create paths/week-1.lab.md:
---
title: Week 1 lab
description: Set up the toolchain.
toc:
maxDepth: 2
---
# Week 1
Install the project dependencies and open the welcome page.
- [ ] Run `bun install`
- [ ] Run `bun run dev`
A course can query type: lab to list practical work separately from
lesson explanations. The filename supplies that vocabulary; a
Map adds its label/icon, and a Plugin can add domain
validation or behavior. Open /week-1.lab to read this example.
| Filename part | Meaning |
|---|---|
name | First stem segment. index makes the file its folder's page. |
.qualifier | Middle segments. Kept as qualifiers, no built-in meaning. |
.type | Last stem segment when there are two or more. Default is page. |
.md | Source-file extension. /x.md serves authored Markdown; an untyped x.md renders at /x.page. |
| Frontmatter | Meaning |
|---|---|
title | Overrides the first heading as the page title. |
icon | A supported built-in icon name (such as pencil) or one emoji (such as ☕); defaults to the Source-type icon. |
schedule | Event start/end, independent due, and timezone; available on Sources and Blocks. |
location | Physical place Source/section and/or HTTPS online destination. |
description | Overrides the first paragraph as the page description. |
image | Overrides the first Markdown image as the preview image; relative paths resolve from this Source's folder. |
type | Source type when the filename has no type hint. |
layout: false | Renders without any Layout. |
theme | Theme tokens or a preset name for this page. |
toc | false, or minDepth and maxDepth for the table of contents. |
| any other key | Authored data, available to queries as where fields. |
Top-level keys are shared with installed Plugins. Core uses the metadata above; access, account, Input, Completion and other Plugins also validate their declared props. Keep domain data under a domain key to avoid collisions, for example:
profile:
location: San Antonio, Texas
biography: I mentor first-year students.
Here profile.location is domain text; top-level location is the structured
Location contract. Arbitrary frontmatter path strings are not automatically graph
relations and are not rewritten by pmx mv. Use Markdown links or a Plugin's
relation contribution for references that must
participate in moves and discovery.
The Core Meta plugin validates icon. It can also vary by instance:
[Afternoon break](./break.event.md?iid=afternoon&icon=☕).
Consumers read the resolved value from source.meta.icon; source.sourceType.icon
remains the type's default, including icons supplied by the active authored Map.
A Source or instance override does not change that Map definition. Icons are presentation metadata, not site favicons.
The built-in Schedule plugin describes event times and deadlines on Sources or Blocks. Dates and local times use an explicit IANA timezone:
---
schedule:
start: 2026-09-18T14:00
end: 2026-09-18T14:15
due: 2026-09-20T17:00
timezone: America/New_York
---
# Workshop
<x-schedule-time />
<x-schedule-time field="due" format="relative" />
<x-schedule-status live="Live now" />
<x-schedule-progress />
start begins an event, end ends it, and due is an independent deadline.
At least start or due is required; end requires a later start. A due-only
schedule does not become an event. Elapsed event progress does not mark work
complete. Authored metadata adds no controls by itself; Path task rows include
available schedule times automatically.
Use ISO dates (2026-09-18) for all-day values. A date-only end or deadline
includes that entire local day. Local datetimes require a timezone; ambiguous or
missing daylight-saving times are rejected. An explicit offset or Z identifies
an instant without a timezone. For events, date: 2026-09-18 also permits
start: "14:00" and end: "14:15".
Time components accept field="start", "end", or "due". Relative format
requires a field, uses the viewer's language, and falls back to an exact date for
distant times. Without JavaScript, the exact authored time remains available.
Status and progress update from the real clock. Use source="./event.event.md"
or source="./event.event.md#session" to present another Source or Block.
Instance overrides retain other schedule fields:
[Retry](./assignment.project.md?iid=retry&schedule.due=2026-09-20T17:00)
The assignment's timezone and other defaults remain in effect. Run pmx lint
(or pmx lint --format json for an agent) to diagnose invalid ranges, missing
timezones, daylight-saving ambiguity, unsupported fields, and missing component
targets. Use pmx query sources --has schedule to inspect scheduled Sources. Calendar feeds and
external calendar synchronization are separate from these time presentations.
The built-in Location plugin describes where an activity happens. Use a local Source or section for a physical place, an HTTPS URL for an online meeting, or both:
---
location:
place: ../locations/venue.page.md#courtyard
online: https://example.org/join/workshop
---
# Workshop
<x-location-details />
<x-location-details /> renders the place's heading or title as a link, followed
by “Join online” when supplied. The linked place Source owns directions and other
venue details. Unreadable places are omitted for the current viewer. An online
URL authored on a public Source is public; use Source access rules for private
meeting details.
Place references resolve relative to the activity Source. Instance fields override individual values while retaining other defaults:
[Afternoon workshop](./workshop.event.md?iid=afternoon&location.place=/locations/venue.page.md%23courtyard)
Use root-relative place references in instance arguments so they remain stable
when the activity moves. A move that would rebase a relative instance place is
rejected with a diagnostic. Ordinary frontmatter place references follow Source
moves. pmx lint checks missing places and sections, malformed local references, and
non-HTTPS online URLs. pmx query sources --has location lists Sources with locations. Calendar feed generation is
not provided by Location.
pmx lintwarns on a frontmatterid; ids come from the file path.- A filename type hint wins over a frontmatter
type. indexis a name, not a type, soindex.lectures.mdis still a folder page.
The page title, description, and image also supply the metadata used when people share a link in Messages or social apps. Set them explicitly when the opening content does not make a useful preview:
---
title: Learning to see type
description: Practice hierarchy, spacing, and contrast.
image: ./images/type-study.jpg
---
# Learning to see type
Start by comparing these two compositions.
PathMX emits an absolute rel="canonical" link and Open Graph metadata in the
initial HTML, including the canonical
page URL, website type, and the home Source's title as the site name when that
Source is public and visible in the current View. Site-name metadata updates at
rendering time without recompiling unrelated pages. Local
image URLs become absolute when served or published, including a publication's
configured base path. Pages with images request a large social card; pages
without images request a summary. The receiving app chooses the final layout.
Use an accessible JPEG or PNG with meaningful imagery and little embedded text. Apple's rich-link guidance explains why concise titles and imagery work across preview sizes. Authored images keep their original composition; PathMX does not inspect their dimensions.
The optional @pathmx/share package provides an explicit command to generate a
1200 × 630 PNG and set the page's image: metadata in the same step:
bun run pmx plugins add share
bunx playwright install chromium
bun run pmx share generate /week-1.lab
Replace the route with a public page in your site. By default, the image is saved
beside its Source as week-1.lab.share.png, and the command sets:
image: ./week-1.lab.share.png
Other metadata values and the Markdown body are retained. The command replaces
any previous image: value; the previous image file is left in place. Rerun the
command to refresh the generated file after editing the title or theme. To choose
another PNG location inside your Paths folder, use --output with a path relative
to the current directory. Use URL-safe filenames without spaces:
bun run pmx share generate / --output ./paths/images/home-share.png
bun run pmx share preview / --no-open
The preview command uses the page's current image and writes an approximate
light/dark card preview under .pathmx/share/. Omit --no-open to open it.
Messages and social apps control the actual card layout and image cropping.
Generated images use the page title and site name with the same root → folder indexes → page theme settings and theme: false
resets as the rendered page. An authored color scheme wins, then a preset's fixed scheme,
then light. Reader preferences do not change the image.
Generation requires Bun and Chromium only on the machine running the command.
On Linux, install Chromium's system dependencies with
bunx playwright install --with-deps chromium. Use the project's installed
Playwright version so its browser and renderer match. If rendering fails, the
command leaves the page's metadata unchanged.
The PNG is an ordinary authored asset: keep it with the Source in version control, and it is served and included in static publication through the normal image metadata flow. Page requests, live edits, previews, and builds never generate images. A page without an image uses a summary social card.
Quote YAML text containing : , for example status: "built: shell ready".
Malformed frontmatter or Block topmatter produces a Source diagnostic with file
coordinates when available. pmx lint --format json reports the error, checks
other Sources, and exits unsuccessfully until errors are fixed.
Development and live servers keep running when an authored Source is invalid. The affected Source is unavailable; a page depending on its Layout, Component, or include is also unavailable. Unrelated pages keep working. These requests return an uncached 503 response without exposing the invalid file's contents. Repair the file to restore availability through the normal watcher.
An invalid folder index.md blocks its subtree, including authored assets,
because its access policy cannot be trusted. An invalid root index blocks all
content and makes server readiness fail, while the process stays alive to detect
repairs. An invalid Actor loses admission, and affected Actions cannot commit.
Invalid content is never treated as a missing access policy or permission grant.
Static publication requires valid Sources. Storage failures and conflicting writer ownership can still prevent startup or writes; those are host failures, not recoverable authored-content diagnostics.