A query fence renders a live list, table, or component from Sources or Blocks that match. Results respect the reader's access.
```query
from: .
type: reference
sort:
- by: meta.title
```
In a Quickstart project, create
paths/lessons/contrast.lesson.md:
---
level: beginner
---
# Contrast
Compare a dark heading with a pale one.
---
<!--
id: practice
type: exercise
-->
## Compare two headings
Choose the heading you can read more easily.
Create paths/lessons/spacing.lesson.md:
---
level: beginner
---
# Spacing
Give a heading room above and below it.
[Review contrast](./contrast.lesson.md).
Create paths/lessons/index.md:
# Design lessons
```query
from: .
type: lesson
sort:
- by: meta.title
```
Run bun run dev and open /lessons. The list contains Contrast, then
Spacing, each linked to its lesson. Change Spacing's heading to “Breathing
room”: the live list updates and sorts it first. Restore the heading for the
examples below. Core's standard Plugins provide queries; no package is needed.
Replace the query in paths/lessons/index.md with:
```query
from: .
type: lesson
where:
level: beginner
view:
type: table
columns: [meta.title, level]
```
The same two lessons appear with their title and beginner level. Change the
filter to advanced to get no results. Queries only return readable Sources;
a missing row may be an access boundary rather than an absent file.
| Key | Meaning |
|---|---|
query | sources (default), blocks, or a plugin query such as plugin.name. |
from | Folder to search. . is this folder; / is the root; ~/ is the Actor home. |
type | Source or Block type. |
where | Map of authored data fields to required values. |
sort | List of by fields with optional direction: asc or desc. meta.title sorts by title. |
limit | Maximum number of results. |
has | Registered prop name, or a list, that results must declare. |
recursive | false limits results to the from folder itself. |
links | to: or from: a Source path, this.source, or this.block. |
view | list (default) or type: table with columns. |
component | Imported Markdown tag or authored Plugin tag that renders each result. |
Create paths/lesson-cards.components.md:
<!-- componentName: lesson-entry -->
# Lesson entry
A compact link with the lesson's authored level.
```html
<article>
<a href="{{ href }}">{{ title }}</a>
<span>{{ level }}</span>
</article>
```
Replace paths/lessons/index.md with:
[@cards]: ../lesson-cards.components.md
# Design lessons
```query
from: .
type: lesson
sort:
- by: meta.title
component: lesson-entry
```
The two results now render as linked lesson titles with their beginner level.
The component and dataset are ordinary Sources you can inspect and edit. For a
wrapper with slotted query children, see the complete
bookcase and shelf components.
Use component: book-card for an imported Markdown component, or an installed
Plugin's authored tag such as component: x-books-card. Markdown result
components can contain Plugin components.
Each result supplies string attributes from its scalar data, top-level fields,
and metadata, in that order; later fields take precedence. For Source results,
href is the public route and title comes from metadata.
Source and Block results also supply source, an exact canonical reference
(including the fragment for a Block), and label, defaulting to the target's
title. These let the same component render an individual
rich reference or a query result. Relative target
images resolve beside their owning Source. Named Plugin query results keep
their own field meanings.
Query components prepare with each row's actual attributes, then render for the current viewer. Static export runs the same query and components anonymously. Actor-dependent results require a host that admits that Actor, including a local Actor in a browser publication.
Add these Blocks to paths/lessons/index.md after the previous example:
---
## Practice
```query
query: blocks
from: .
type: exercise
```
---
## Lessons that link to Contrast
```query
from: .
type: lesson
links:
to: ./contrast.lesson.md
```
Practice links to Compare two headings inside Contrast; the link query lists
Spacing, whose body links to Contrast. links.from instead selects targets
linked from its anchor. Use this.source or this.block when the authoring Source
or Block is the anchor. Keep exact Block ids stable when querying links to them.
Use a named Markdown reference to read one Source through the current View:
[profile]: ~/profile.profile.md
Hello, {{ $profile.display-name ?? "Guest" }}.
<x-source-read name="profile">
<p>{{ $profile.display-name }}</p>
<slot name="fallback"><p>Add your profile to introduce yourself.</p></slot>
</x-source-read>
~/ resolves within the current Actor's Home. Relative references resolve beside
their declaring Source; a fragment selects a Block. An unavailable or unreadable
target uses the literal default or fallback slot. Only the selected slot renders
and performs reads. A reference that is never consumed performs no read.
Bindings work in Markdown prose, literate HTML templates, and scalar HTML or
component attributes. Shared compilation keeps the instruction; each admitted
View resolves its own values and live dependencies. Returned scalar values are
HTML-escaped. Missing fields and non-scalar values render empty. ?? supplies a
string, number, or boolean only when the value is null or absent; false, 0, and
empty text are preserved. Code examples, comments, and scripts remain literal.
Bindings do not evaluate JavaScript, loop over arrays, or embed a Source body.
A typed query can be called directly:
{{ $input.responses(source=this.source, response="reflection").values.idea ?? "No saved idea" }}
Named arguments accept scalar literals, this.source, and this.block. A query
binding is singular: no rows means unavailable, one row supplies the value, and
multiple rows produce an authoring diagnostic. Binding declarations cannot use
limit to hide ambiguity. Query fences remain the collection presentation form.
For reuse or an availability wrapper, put the same request in Source topmatter:
reads:
answer:
query: input.responses
input:
source: this.source
response: reflection
{{ $answer.values.idea ?? "No saved idea" }}
<x-source-read name="answer">
<p>{{ $answer.values.idea }}</p>
<slot name="fallback"><p>Save your reflection first.</p></slot>
</x-source-read>
A Block inherits its Source's local reads. A Block entry replaces the whole
inherited definition; false disables it. Representation selectors follow the
represented Source or Block in layouts, query results, and rich references.
Projected slots retain their caller's scope. Undefined names, invalid query
inputs, duplicate declarations, and ambiguous results diagnose errors; they do
not silently become missing data.
An installed Plugin can export a Source or query descriptor:
import { definePlugin } from "@pathmx/core"
export default definePlugin({
id: "workshop",
bindings: {
profile: { source: "~/profile.profile.md" },
},
})
This makes $profile available throughout the repository without local references.
Exported names are unique and reserved: local reads and Markdown references
cannot shadow them, and a binding cannot use an installed Plugin's id. Plugins
supply declarative Source/query definitions, not callbacks or another state store.
Unused exports perform no reads. Operation identifiers consistently use
plugin.member for Queries, Actions, and Events; component tags retain their
x-plugin-member HTML form.
pmx lintreports an invalid fence, an unknown component, or alinkstarget that does not exist.pmx query sources|blocks|plugin.nameruns the same query from the terminal; see the CLI.
- Components · Blocks
- A bookcase from Markdown renders query results as book cards.
Server code passes a Plugin query's arguments inside input. With the Path
Plugin installed and a readable /course.path, use:
const steps = await view.query("path.steps", {
input: { path: "/course.path" },
})
Top-level request fields belong to Core's query envelope. Passing { path: ... }
at the top level is rejected. The admitted View still controls what the query
can read; changing input does not grant another Actor's authority.