# Queries

A query block lists the entities that match your query, live, right on the page.

A query is written in Fennick's formula language, the same one formulas use. For example, `#task.Where(Done = false).Sort(Due)` lists your open tasks, the soonest first. Fennick reads the query as a filter and a sort, the same filters and sorts a tag page's view uses, and shows the matching entities under the block. When the entities change, the results change too.

## Make a query block

1. On an empty block, type `??`. The formula builder opens under it (see [The builder](#builder)).
2. Pick a tag, such as `#task`, and press `Tab`. Type `.` for its fields and steps, then write the rest: `#task.Where(Done = false).Sort(Due)`. The first results show in the builder as you type.
3. Press `Enter`. The block becomes a query block, with its results under it.

- Or press `/` and pick *Query*, then type the query on the block.
- A query block has a **?** mark in place of its bullet.
- A `#` in a query block names a tag. It never tags the block.
- `Enter` at the end of a query block starts a plain block after it.

## The builder

`??` opens the builder anywhere in a block: at its start, after a space, or inside a word. It shows:

- **The formula**, at the top. A tag or an entity you pick shows as a chip in its tag's color, with its Type's icon.
- **The answer**, under it, after **=**: for a query, the first few names it lists and how many more.
- **What can come next**, on the left: `Related(ThisPage())`, your tags, most used first, your saved queries, this page's fields, entities once you type two letters, and functions. After a tag and a `.`, the tag's fields and the steps *Where*, *Sort*, *Limit*, *Without*, *Sum*, *Average*, *Count* and *List*. Inside a *Where*, after a field, the rules that fit its Type, each with what it does, then the field's own values, such as *Active* or *On Hold*. Picking a value closes the *Where*.
- **The one picked, explained**, on the right: what it is, with a preview of a tag's first entities, or a function's help and an example.

The keys:

- `↑` and `↓` move through the list, and `Tab` puts the one picked in.
- `Enter` puts the formula there. A query in an empty block makes it a query block. Anywhere else, it puts in the names it lists, kept up to date, or a value, such as a count (see [A formula in a block](fields.md#in-a-block)).
- `Esc` or **Cancel** leaves `??` and what you typed as letters in the block.
- With nothing typed yet, a space, a punctuation mark or a third `?` leaves the letters too, so `??` in your writing stays as you typed it.
- **Add name**, at the top, names the query block as it is made.
- **f** shows the formula as words in place of chips.

On a phone the builder opens as a sheet from the bottom, and the keyboard bar has a **??** key.

## A query's view

A query holds one view. Its results show as a list at first. The icon beside the count opens its panel:

- **Shows**: its tag, and *Or a tag* to add another.
- **Edit Query**: the query itself, to change as you read the results.
- **Layout**: List, Outline, Prose, Numbered list, Checklist, Table, Board, Calendar, Gallery, Chart or Canvas. See [Views](views.md).
- The layout's own settings, then **Filter**, **Sort**, **Group** and **Search**.
- **Total**: the sum or the average of a Number field (see [Sum and average](#sum-and-average)).
- **+ New when folded**: whether **New** stays beside the count while the query is folded.
- **Tag and filter bar**: whether the query's tag and filter chips show.
- **Duplicate the query**: for another look at the same results, duplicate it and change the copy's view.
- **Open full page**.

## Name a query, and change it with chips

- To add a filter or a sort, use the panel. While you set a filter, the query's tag and each of its filters show under it as chips: click a chip to change its rule or value, or to remove it. The chips go when you leave the page, and the panel's **Filter** row says how many filters it has. **Tag and filter bar** keeps them showing. A query Fennick can't read, or one naming a tag that isn't made yet, keeps them too, so you can fix it. A chip writes the query's words for you.
- Once you use a chip, the block waits for a name: until you type one, the query shows dimmed in its place. Click it and type the name, like a page title. Until then, the query goes by its words wherever it shows: as its page's title, dimmed, on its tab and in Recents.
- To change the query itself, right-click its **?** (or open its menu on a phone) and pick *Edit query*. The query is back on the block: edit it and press `Enter`. `Esc` leaves it as it was.
- A query Fennick can't read is never kept: the query before stays and keeps running, and the block under it says what it can't read.
- Chips, names and edits sync to your other devices, and `⌘Z` undoes them.

## Queries from before

Queries used to be written in words, such as `#task where Done is not checked sort Due`. Those words aren't read any more. A query block that holds them stays as it is and says *Can’t read: These query words are from before the new query language*. Make it again in the formula language: that one is `#task.Where(Done = false).Sort(Due)`. A query of only a tag, such as `#task`, or `Everything`, reads as before.

## The shape of a query

A query starts with what to list: most often a tag. Then come its steps, each after a `.`, and all of them optional:

`#tag.Without(#tag).Where(rule and rule).Sort(Column).ThenBy(Column).Limit(n)`

| Part | What it does | Example |
| --- | --- | --- |
| `#tag` | Which entities to list: every block tagged with that tag. Name more than one in brackets, with `or` (see [Several tags](#tags)). | `#task`, `(#task or #bug)` |
| `Everything` | In place of a tag: every page and every entity. | `Everything.Where(Status = Doing)` |
| `Under([[page]])` | In place of a tag: the pages and entities under that page, at any depth, and those shown on it. | `Under([[Projects]]).Sort(Edited, desc)` |
| `LinksTo([[page]])` | In place of a tag: every page and entity that links to that page, or that has a field pointing at it. | `LinksTo([[Kit]])` |
| `[[query]]` | Starts from another named query: what it lists, through its rules, and then this query's own steps. | `[[Open tasks]].Where(Due.In(ThisWeek()))` |
| `Related(ThisPage())` | In place of a tag: the pages and entities most related to the page the query is on, best first, as [Related](links.md#related) finds them. `Related([[page]])` does it for any page. See [Related](#related). | `Related(ThisPage()).Limit(3)` |
| `Search("…")` | In place of a tag: every block that holds each of the words in quotes. In *Start from* it is *Search…*. Query blocks are never in its results. | `Search("garden hose")` |
| `#day` | Your day pages, each by its date. In *Start from* it is *Day pages*. Sorted by Name, they go by date. `#week`, `#month`, `#quarter` and `#year` work the same way; *Other date pages* in *Start from* has them, with `#weekday` and the eternal ones. | `#day.Sort(Name, desc)` |
| `.Without(#tag)` | Leaves out the entities of that tag (see [Leave a tag out](#leave-a-tag-out)). | `#task.Without(#routine)` |
| `.Where(…)` | Only the entities that pass its rule are listed. `.Filter(…)` is the same. | `#task.Where(Done = false)` |
| `and` | Inside `Where`: one more rule. An entity must pass all of them. `&&` is the same. | `#task.Where(Done = false and Due.IsNotBlank())` |
| `or` | Inside `Where`: one rule of a field or another (see [One or another](#or)). `\|\|` is the same. | `#book.Where(Status.In(Reading, "To read"))` |
| `Link.Field` | In a rule: a field of what a Select from tag points at (see [Through a link](#through-a-link)). `›` works too. | `#task.Where(Project.Status = Doing)` |
| `.Sort(…)` | Puts the results in the order of a column (see [Sort](#sort)). | `#task.Sort(Due)` |
| `.Limit(n)` | Shows only the first so many results. | `#task.Sort(Due).Limit(5)` |
| `.Sum(Field)`, `.Average(Field)` | At the end: adds up a Number field over every result, and says the answer beside the count (see [Sum and average](#sum-and-average)). | `#book.Sum(Pages)` |

- Capitals don't matter in a query's own words: `.Where` is `.where`, `#Task` is `#task`, and `due` is `Due`.
- A tag with a space in its name works as it is: `#reading list.Sort(Name)`.
- A column with a space in its name goes in square brackets: `[Edited by]`, `[Blocks under it]`.
- Spaces between the parts don't matter: `Pages>=432` is `Pages >= 432`.
- With `Everything`, `Under`, `LinksTo` or `Search`, the columns are every field your tags have, plus the columns every entity has, such as Name and Mentions.

The examples below use `#task`, with its fields Due (a Date) and Done (a Checkbox), and a `#book` tag with these fields: Status (a Select: To read, Reading, Read), Pages (a Number), Author (a Text), Started (a Date), Owned (a Checkbox) and Shelf (a Select from tag, pointing at `#shelf` entities).

## Columns

A rule or a sort names a column. These are the columns a query knows. They are the same columns as on the tag's page.

| Column | What it holds | Example |
| --- | --- | --- |
| **Name** | The entity's own words. | `#book.Where(Name.Contains("pride"))` |
| Each of the tag's fields | That field's value, by the field's name. | `#book.Where(Status = Reading)` |
| **Mentions** | Every page it is on or named in: each page it shows on, and each page with a block that links to it, by those pages' names. A day reads like *Monday 12 October 2026*. | `#book.Where(Mentions.Contains("October"))` |
| **Edited** | The day it was last changed. | `#book.Where(Edited = Today())` |
| **Created** | The day it was made. | `#book.Sort(Created, desc)` |
| **Edited by** | Who changed it last. | `#book.Where([Edited by] = Me())` |
| **Created by** | Who made it. | `#book.Where([Created by] = "Maya")` |
| **Tags** | The tags it wears. Sorted by, it goes by the first tag's name, then the next, in the order they show; an entity with no tag comes last. | `#book.Where(Tags.Contains(#classic))`, `#book.Sort(Tags)` |

A name that is not one of these columns is not understood: `#book.Where(Color = "blue")` shows *Can’t read: #book has no field "Color"*.

## Rules for each field Type

A rule names a column, then what its value must be. Which rules fit depends on the column's field Type.

### Text, Name, and Select from tag

| Rule | Passes when | Example |
| --- | --- | --- |
| `.Contains("…")` | The value has these letters anywhere in it. Capitals do not matter. | `#book.Where(Author.Contains("austen"))` |
| `not` … `.Contains("…")` | The value does not have these letters. | `#book.Where(not Name.Contains("emma"))` |
| `=` | The value is exactly this, capitals too. | `#book.Where(Author = "George Eliot")` |
| `!=`, `≠` or `<>` | The value is not exactly this. | `#book.Where(Author != "George Eliot")` |
| `.IsBlank()` | The field has no value. | `#book.Where(Author.IsBlank())` |
| `.IsNotBlank()` | The field has a value. | `#book.Where(Shelf.IsNotBlank())` |

**Blocks under it** reads the same way: `#task.Where([Blocks under it].IsNotBlank())` lists the tasks with blocks under them, and `.IsBlank()` those with none.

A Select from tag field is matched by the name of the entity it points at: `#book.Where(Shelf.Contains("study"))`. `[[Name]]` names the entity itself: `#task.Where(Work = [[Kitchen]])`. Type `[[` in the query's words and a list offers the entities by that name. For **Mentions**, `.Contains` matches when any of its pages does. A query written with its old name, **Written on**, still works.

### Select

| Rule | Passes when | Example |
| --- | --- | --- |
| `=` | The choice is this one. Capitals do not matter: `reading` finds *Reading*. | `#book.Where(Status = Reading)` |
| `!=`, `≠` or `<>` | The choice is another one, or none. | `#book.Where(Status != Read)` |
| `.In(…)` | The choice is any one of these. | `#book.Where(Status.In(Reading, "To read"))` |
| `.Contains(…)` | The choice's name has these letters. | `#book.Where(Status.Contains(read))` finds all three. |
| `not` … `.Contains(…)` | The choice's name does not have these letters. | `#book.Where(not Status.Contains(to))` |
| `.IsBlank()`, `.IsNotBlank()` | No choice is made, or one is. | `#book.Where(Status.IsBlank())` |

A choice with a space in its name goes in quotes: `#book.Where(Status = "To read")`. A one-word choice needs none.

### Number

| Rule | Passes when | Example |
| --- | --- | --- |
| `=` | The number is this. | `#book.Where(Pages = 432)` |
| `!=`, `≠` or `<>` | The number is not this. | `#book.Where(Pages != 432)` |
| `>` | The number is more than this. | `#book.Where(Pages > 450)` |
| `<` | The number is less than this. | `#book.Where(Pages < 500)` |
| `>=` or `≥` | The number is this or more (at least). | `#book.Where(Pages >= 432)` |
| `<=` or `≤` | The number is this or less (at most). | `#book.Where(Pages <= 432)` |
| `.Between(…, …)` | The number is either of them, or between. It is the same as `>=` one and `<=` the other, which is how a chip writes it. | `#book.Where(Pages.Between(100, 300))` |
| `.IsBlank()`, `.IsNotBlank()` | The field has no number, or has one. | `#book.Where(Pages.IsBlank())` |

### Date, Edited and Created

| Rule | Passes when | Example |
| --- | --- | --- |
| `=` | The day is this day. | `#task.Where(Due = Tomorrow())` |
| `.In(…)` this, last or next week, month or year | The day is in that whole week, month or year (see [This, last and next](#this-last-next)). | `#task.Where(Due.In(ThisWeek()))` |
| `<` | The day is earlier than this day. | `#book.Where(Started < Date("next week"))` |
| `>` | The day is later than this day. | `#book.Where(Started > Today())` |
| `<=` | The day is this day or earlier. | `#task.Where(Due <= Today())` |
| `>=` | The day is this day or later. | `#task.Where(Due >= Date(2026, 11, 1))` |
| `.Between(…, …)` | The day is either of them, or between. | `#task.Where(Due.Between(Date(2026, 11, 1), Date(2026, 11, 5)))` |
| `.InLast(`a number, a unit`)` | The day is from that long ago up to today. | `#task.Where(Edited.InLast(3, days))` |
| `.InNext(`a number, a unit`)` | The day is from today up to that long from now. | `#task.Where(Due.InNext(2, weeks))` |
| `.IsBlank()`, `.IsNotBlank()` | The field has no day, or has one. | `#task.Where(Due.IsNotBlank())` |

The day can be written in any of these ways:

- `Today()`, `Tomorrow()`, `Yesterday()`
- `Date(2026, 11, 1)`: the year, the month and the day
- `Date("…")` with words, in any of these ways:
   - `2026-11-01`, `11/1`, `11/1/2026`, `Nov 1`, `1 Nov`, `Nov 1 2026`
   - a weekday: `friday`, `next friday`, `this friday`, `last friday`
   - `next week`, `last week`: a week from today, or a week ago
   - `in 3 days`, `in 2 weeks`, `3 days ago`, `2 weeks ago`

“Is not” a day is not understood: `Due != Today()` shows *Can’t read*.

### This, last and next week, month and year

`.In(ThisWeek())` means that whole week on the calendar. There are nine: `ThisWeek()`, `LastWeek()`, `NextWeek()`, and the same for `Month` and `Year`.

| Query, on Thursday, October 29, 2026 | Lists |
| --- | --- |
| `#task.Where(Due.In(ThisWeek()))` | Tasks due Monday, October 26 to Sunday, November 1. |
| `#task.Where(Due.In(NextWeek()))` | Tasks due November 2 to 8. |
| `#task.Where(Due.In(LastMonth()))` | Tasks due September 1 to 30. |
| `#task.Where(Due.In(ThisMonth()))` | Tasks due October 1 to 31. |
| `#book.Where(Started.In(LastYear()))` | Books started in 2025. |

- A week starts on the day you pick in *Settings*, *Week starts on*: Monday, or Sunday. From Sunday, `ThisWeek()` on October 29 is October 25 to 31.
- These are whole periods. `.InLast(1, months)` is different: on October 29, it is September 29 up to today.
- In a chip, pick *is*, then one of the nine: *This week*, *Last month*, *Next year* and the rest. Pick more than one for an “or”.
- New in a query fills the first day: under `Due.In(LastMonth())`, the new entity is due September 1.

### In the last, in the next

`.InLast` and `.InNext` take a whole number and one of five units: `days`, `weeks`, `months`, `quarters` or `years`. The unit can be singular or plural: `.InLast(1, week)` is fine.

| Query | Lists |
| --- | --- |
| `#task.Where(Edited.InLast(3, days))` | Tasks changed from 3 days ago up to today. |
| `#task.Where(Due.InNext(2, weeks))` | Tasks due from today up to 14 days from now. |
| `#book.Where(Started.InLast(6, months))` | Books started from the same date 6 months ago up to today. |
| `#event.Where(When.InNext(1, quarters))` | Events from today up to the same date 3 months on. |
| `#trip.Where(When.InLast(2, years))` | Trips from the same date 2 years ago up to today. |

How the days are counted:

- Today always counts, in both. So `.InLast(7, days)` is today and the 7 days before it, and `.InLast(1, day)` is yesterday and today.
- A week is 7 days. Months, quarters (3 months) and years (12 months) count by the calendar, to the same date: from October 26, `.InNext(2, months)` runs to December 26.
- When that month has no such date, it is the month’s last day: from January 31, `.InNext(1, month)` runs to February 28 (February 29 in a leap year). From February 29, `.InNext(1, year)` runs to February 28.
- The number is a whole number, 1 or more. `0`, `-2` or `2.5` shows *Can’t read*, and says why.
- The most is 1,000 years (12,000 months, 365,000 days). More shows *Can’t read: that is too far*.

The filter on a tag page has the same rules: pick *in the last* or *in the next*, type how many, then pick the unit. It starts at 7 days.

### A date that repeats

A date that repeats answers a rule on each of its turns, so `#routine.Where(When = Today())` lists the routines whose day it is, however long ago they began. A date that doesn't repeat answers by its first day, as above.

- `=`, `.InLast`, `.InNext`, `.In(ThisWeek())` and the rest: a turn falls on that day or in those days.
- `>`, `>=`: a turn comes then. A repeat with no last day always has one.
- `<`, `<=`: it has begun by then.
- `.IsBlank()`: never, as it holds a date.
- Each rule is read on its own. For a stretch of days, use one rule such as `.InNext(7, days)`, not `>=` with `<=`, which two different turns can answer.
- A sort goes by the turn that is due. Agents' queries read the same way.

### Related

The builder offers `Related(ThisPage())` to start from, and after its `.` its steps, `Where(Similarity >= Close)` first. `Related(ThisPage())` lists the pages and entities most related to the page the query sits on, up to 30, best first: by links, by tags few others wear, and in the Mac app by meaning too (see [Related](links.md#related)). `Related([[Garden plans]])` lists those of any page.

| Query | Lists |
| --- | --- |
| `Related(ThisPage()).Limit(3)` | The three most related. |
| `Related(ThisPage()).Where(Similarity >= Close)` | Only the close ones. |
| `Related(ThisPage()).Where(#book)` | Only the related books. |

- **Similarity** is one of three words, from least to most: `Related`, `Close` and `"Very close"`. Its rule goes in a `Where` of its own.
- They come best first. `.Sort(Similarity)` or `.Sort(Similarity, asc)` puts the least related first.
- `.Where(#book)` is short for `.Where(Tags.Contains(#book))` here.
- After the start, the steps are the same as for `Everything`.
- Shown as a Table, it has a **Similarity** column: each row's word drawn as a bar, as in the Related panel, with no number.

### Several tags

Put tags in brackets with `or` to list the entities of each: `(#task or #bug).Where(Status = Doing)`.

- Each entity is listed once, with the entities of the tags that build on each.
- The columns are the first tag's. A filter or a sort on a field reads each entity's own field of that name: a bug's Status for a bug, a task's for a task. A tag with no such field reads as empty.
- New in the query makes an entity with the first tag.
- Under the query, *Or a tag* adds one, and the **×** beside a tag takes it off.

### Leave a tag out

Use `.Without` and the tag after what to list, or the column **Tags**.

| Query | Lists |
| --- | --- |
| `#task.Without(#routine)` | Tasks that aren't routines. The same as `#task.Where(not Tags.Contains(#routine))`. |
| `#task.Without(#routine, #chore).Where(Done = false)` | Open tasks, with two tags left out. |
| `#task.Where(Tags.Contains(#urgent))` | Tasks that also wear #urgent: both tags. |
| `Everything.Where(Tags.IsBlank())` | Pages and entities with no tag at all. |
| `Everything.Where(Tags.IsNotBlank())` | Only those with a tag. |

- A tag counts with the tags that build on it: when #chore builds on #routine, `.Without(#routine)` leaves out chores as well.
- Under a query, *+ Filter* offers Tags: pick the rule, then the tag.
- When you rename a tag, the query says the new name.
- *New* in a query puts on a tag named in Tags: under `Tags.Contains(#urgent)`, the new task wears #urgent as well.

### Through a link

Follow a Select from tag field to a field of the entity it points at, one step, with a `.`:

| Query | Lists |
| --- | --- |
| `#task.Where(Project.Status = Doing)` | Tasks whose project is Doing. |
| `#task.Where(Project.Owner = Me() and Done = false)` | Your projects' open tasks. |
| `#task.Where(Project.Name.Contains("garden"))` | Tasks of any project with garden in its name. |
| `#task.Where(Project.Due.IsBlank())` | Tasks whose project has no Due, and tasks with no project. |

- The rule is the one for the field behind the link, so it reads as it does on that tag.
- A field that holds several entities passes when any of them does.
- A link that can point at any page has only what every entity has behind it: Name, Created, Edited and the like.
- Its chip says it, with a **×** to take it off. To change it, use *Edit query*.
- When you rename either field, the query says the new name.
- You can't sort through a link yet.

### Sum and average

A query block can add up a Number field over everything it lists, and say the answer beside the count. Each total shows as a chip with the query's filters, such as *Sum of Pages*, and its **×** takes it off.

- To add one, click the icon beside the count, which opens the query's View settings, and pick **Total**, then *Sum of* or *Average of* a Number field. Pick it again to take it off. **Total** says how many totals the query has.
- Or write it at the end of the query: `#book.Sum(Pages)`, or `#book.Pages.Sum()`. The old words, such as `#book sum Pages`, no longer read.

| Query | Says |
| --- | --- |
| `#book.Sum(Pages)` | *Sum of Pages: 4,320* |
| `#book.Where(Status = Read).Average(Pages)` | *Average of Pages: 360* |
| `#book.Sum(Pages).Average(Pages)` | Both. |
| `#task.Sort(Due).Limit(5).Sum(Hours)` | The sum for those first five only. |

- A total ends the query: only another total comes after it.
- The total is kept with the query block, as its chips are, not in its words.
- It reads every entity the query lists, not only the rows on the screen, and changes when they do.
- An entity with no value is left out of an average. An average with no values says *no value*.
- It shows the number in the field's own format.
- While the query's Search box holds words, the answer isn't shown.
- Agents get the same answer when they read the query.

For one number in your writing, with no rows, use a formula: `#book.Pages.Sum()` after `??` in a sentence (see [A formula in a block](fields.md#in-a-block)).

### One or another

`or` joins rules of one column: an entity passes when it passes any of them.

| Query | Lists |
| --- | --- |
| `#book.Where(Status.In(Reading, "To read"))` | Books being read, and books to read. |
| `#task.Where(Due.In(ThisWeek()) or Due.In(NextWeek()))` | Tasks due this week or next week. |
| `#task.Where(Due = Today() or Due.IsBlank())` | Tasks due today, and tasks with no day. |
| `#book.Where(Author.Contains("Le Guin") or Author.Contains("Tolkien"))` | Books by either. |
| `#task.Where(Done = false and (Due = Today() or Due.IsBlank()))` | Open tasks due today or with no day. |

- With other rules beside it, put the `or` in brackets, as in the last example.
- An `or` across two columns, such as `Due = Today() or Done = false`, can't be read yet.
- Words in quotes stay whole: `Name.Contains("rock or roll")`.
- To leave out more than one, use `and`: `Status != Read and Status != "To read"`. `Status != Read or Status != "To read"` shows *Can’t read*.
- In a chip, pick more than one option of a Select, or more than one of this, last and next: the query gets an `.In(…)` or an `or`.
- New in a query fills the first value that fits: under `Status.In(Reading, "To read")`, the new book is Reading.

### Checkbox

| Rule | Passes when | Example |
| --- | --- | --- |
| `= true` | The box is ticked. | `#task.Where(Done = true)` |
| `= false` | The box is not ticked. | `#task.Where(Done = false)` |

`!= true` is the same as `= false`.

### Edited by and Created by

| Rule | Passes when | Example |
| --- | --- | --- |
| `=` | The person is the one named. Write the name you see, capitals or not. | `#book.Where([Created by] = "Maya")` |
| `!=` | Anyone else. | `#task.Where([Edited by] != "Maya")` |
| `= Me()` | The person is you. Whoever reads the query sees their own blocks. | `#task.Where([Created by] = Me())` |

An agent is found by the name it shows, too. You can sort by these two: `#book.Sort([Edited by])`.

## Quotes and brackets

- A value with a space goes in quotes: `"…"`, `“…”` or `'…'`. `#book.Where(Name = "Pride and Prejudice")` finds *Pride and Prejudice*. Without the quotes it shows *Can’t read*.
- A value of one word needs no quotes: `Status = Reading`.
- A column with a space, or named like a word of the language such as *and*, goes in square brackets: `[Edited by]`.
- A pick in the builder writes the quotes and brackets for you.

## Sort

| Step | Order | Example |
| --- | --- | --- |
| `.Sort(Column)` | Lowest or earliest first (A to Z, 1 to 9, old to new). Empty values go last. `.Sort(Column, asc)` is the same. | `#task.Sort(Due)` |
| `.Sort(Column, desc)` | Highest or latest first. | `#book.Sort(Pages, desc)` |
| `.ThenBy(Column)` | After a sort: sorts entities with the same first value by a second column. It takes `desc` too. | `#book.Sort(Status).ThenBy(Pages)` |

A Select sorts in the order of its choices (for Status: To read, Reading, Read), not A to Z. With no sort, the newest entities come first.

## Limit

`.Limit` and a whole number shows only the first so many results: `#book.Sort(Pages).Limit(2)`. The count then says how many of all: *2 of 3*. `.Limit(0)` or `.Limit(two)` shows *Can’t read*, and says that Limit takes a whole number.

## What you see

- **The results**, under the block: one row for each entity, with its tag, its name and up to three of its field values. Click a row to open that entity's own page. Back returns to the query.
- **The count**, at the end of the block: how many entities match, then a list icon. With a limit: *2 of 3*.
- **Show more**: a query without a limit shows 100 results at first. *Show more (n)* under them shows 100 more.
- **Folded**: fold a query block with its arrow and it stops running. It keeps the count it last had.
- The query block itself is never one of its own results.

Under the block you may also see one of these:

| Message | What it means |
| --- | --- |
| *Can’t read: …* | A part of the query is not understood, and the message says which part or what is missing, such as *A ) is missing*. No results show until it is fixed, because results that skip part of a query would be wrong. Common causes: a column the tag does not have, a rule that does not fit the column's field Type (`#task.Where(Done > 1)` says *Done is a Checkbox field: this rule doesn’t work on it. Try Done = true or Done = false*), a missing value, a missing `.` before a step (`#book Pages > 450`), a step Fennick doesn't know, or a value with a space that isn't in quotes. |
| *No tag named #… yet.* | There is no tag with that name. Check the spelling, or make the tag first. |
| *Nothing matches.* | The query is understood, and no entity passes it. |
| *Reading…* | Fennick is still counting the results. It goes away in a moment. |
| *Couldn’t load, retrying…* | The results could not be read just now. Fennick tries again by itself. |

## More examples

| Query | Lists |
| --- | --- |
| `#task.Where(Done = false).Sort(Due)` | Open tasks, the soonest first. |
| `#task.Where(Due < Today() and Done = false)` | Tasks that are late. |
| `#book.Where(Status = Reading and Pages > 300).Sort(Started, desc).Limit(5)` | Up to 5 long books you are reading, the latest started first. |
| `#task.Where(Edited.InLast(1, weeks)).Sort(Edited, desc)` | Tasks changed in the last week, the newest change first. |
| `#task.Where(Due.InNext(3, days) and Done = false)` | Open tasks due in the next 3 days. |
| `#book.Where(Mentions.Contains("October"))` | Books on, or named on, a day page in October. |

Agents ask for entities through the Fennick connector, with a query in the same formula language. See [People and agents](agents.md).
