[@layout]: ../docs.layout.md

# Sources

A Source is one Markdown file under `paths/`. Its filename gives it a name, a type, and a route; frontmatter adds metadata.

```text
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`:

```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](./maps.reference.md) adds its label/icon, and a Plugin can add domain
validation or behavior. Open `/week-1.lab` to read this example.

---

## Contract

| 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:

```yaml
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](../extend/plugins.reference.md) 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.

## Schedules

The built-in Schedule plugin describes event times and deadlines on Sources or
Blocks. Dates and local times use an explicit IANA timezone:

```md
---
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:

```md
[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.

## Locations

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:

```md
---
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:

```md
[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.

## Notes

- `pmx lint` warns on a frontmatter `id`; ids come from the file path.
- A filename type hint wins over a frontmatter `type`.
- `index` is a name, not a type, so `index.lectures.md` is still a folder page.

---

## Link previews

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:

```md
---
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](https://developer.apple.com/videos/play/tech-talks/205/)
explains why concise titles and imagery work across preview sizes. Authored images
keep their original composition; PathMX does not inspect their dimensions.

---

## Generate a share image

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:

```sh
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:

```yaml
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:

```sh
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.

## Related

- [Blocks](./blocks.reference.md) · [Links](./links.reference.md) · [Queries](./queries.reference.md)
- [Source journey demo](../../examples/pathmx-source-journey.demo.md)


---

## Invalid Sources and recovery

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.
