Help

Query language

A query is a line of text that says which things to show and how: assignee:me is:open sort:due is your open tasks, soonest due first. The same language runs every query bar in the app:

This page covers task queries first, then what's different elsewhere.

#The query bar

In a task view, the query bar (f q) holds the whole view as text: filters, layout, grouping, sorting and display. Changing the chips updates the text and the other way round. It suggests fields and values as you type, applies the query as soon as it's complete, and says under the bar what it can't read, such as a field it doesn't know.

Its suggestions look like the filter chips' menus: a task shows its status, key, title, priority, project and type, a person their avatar, a Space its icon, and a status, priority, type or label its color, so two tasks with the same title are easy to tell apart. A project, milestone, Space or person shows its key on the right, and a label its folder.

They're in the same order as a filter chip's menu, too: the value the cursor is in comes first, ticked, then unset and any, then everything else, with a line between each part. Once you start typing, the best match comes first instead, so Enter picks it.

Wherever a new clause can start - as soon as you click or Tab into the bar, or after a space that ends a clause - the list of fields opens, so you can see what you can filter by without knowing the names. Nothing in it is picked until you press the arrows, so Enter still runs the query; Escape closes the list.

A query is a list of field:value clauses separated by spaces. Words without a field match task names and keys.

#How a clause is written

Every field is written the same way: lowercase, with a dash between words (started-before:, blocked-by:). A field of the task itself is plain (status:, due:); a field of something the task is linked to is the kind, a dot, then the field (milestone.target:, project.name:). project: on its own is the project, by its key - short for project.key:. Every kind has a .key and a .name. task. in front of a field is the task's own, so task.status: is status:. The same form is used across the app, on the Activity page and in the hubs' query bars.

You can also type or paste a query into search (⌘K / CtrlK), which shows its clauses as chips and suggests as you type, like this bar: Open as query opens it in a Query tab, and Save as view saves it as a new view. Search also finds projects, docs, milestones and the rest by their fields - see Searching across kinds.

#Filters

FieldAlso acceptsMatches tasks…
status:state:in that status
priority:p:with that priority
type:tasktype:of that type
label:labels:, tag:, tags:with that label (any of the ones listed)
assignee:assigned:, owner:assigned to that person
mentions:mention:that mention that person
project:project.key:in that project
milestone:milestone.key:, ms:in that milestone (by key or name)
space:space.key:kept in that Space (by key or name); space:unset is the workspace-wide ones
parent:parent.key:, subtaskof:that are direct sub-tasks of that task
root:root.key:that are that task, or reachable from it through sub-tasks and Blocks / Blocked by links (Related links don't count)
task:task.key:, id:that are that exact task
blocks:blocksTaskKey:that block that task; blocks:any blocks something, blocks:unset blocks nothing
blocked-by:blockedByTaskKey:, blockedby:that are blocked by that task; blocked-by:any has a blocker (finished or not), blocked-by:unset has none, and blocked-by:open is still waiting on a blocker that's neither completed nor canceled (see Stuck work)
related:relatedTaskKey:related to that task; related:any has a related task, related:unset has none
child:children:that have that task as a sub-task; child:any has sub-tasks, child:unset has none
estimate:with that estimate: estimate:5, more or less (estimate:>3, estimate:<=2) or a range (estimate:3..8, both ends included); estimate:unset has none. When the workspace's estimates are time, a number is hours, as when you type an estimate, and a length of time works too: estimate:>2h, estimate:30m..1d, estimate:1h30m (a day is 8 hours)
comments:with that many comments, compared the same way: comments:>5, comments:any has some, comments:unset has none
creator:created-by:, author:made by that person: creator:me is the ones you made
comment.by:commenter:that person has commented on: comment.by:me
follower:followers:, followed-by:that person follows: follower:me is the ones you follow, follower:unset the ones no one follows
due: / start:due / starting on that day
created: / updated: / completed:created / last updated / completed on that day
started:started on that day: when it first moved into a started status (started:unset is never started)
name:task.name:, title:, text:, search:whose title or key contains the text
description:desc:whose description contains the text: description:"cat scan"
internal:internal:yes is internal tasks, hidden from guests; internal:no is the rest
project.name:project.title:whose project's name contains the text
milestone.name:milestone.title:whose milestone's name contains the text
space.name:space.title:whose Space's name contains the text
label.name:label.title:with a label whose name contains the text
assignee.name:assignee.title:assigned to someone whose name or email contains the text
project.folder:whose project is in that folder, or a folder inside it - see Folders
milestone.folder:whose milestone is in that folder, or a folder inside it
label.folder:with a label in that folder, or a folder inside it
custom.<name>:by one of your custom fields: custom.points:>3, custom.client:Acme
checklist:checklists:by their checklists: any (has one), unset (has none), open (something left to tick), done (every item ticked), or a checklist's name - checklist:"After deploy" has something left to tick in a list of that name

kind:task says what a query finds, and every query bar starts with it as a chip with a lock, since it can't be edited: kind:task in Tasks and on dashboards, kind:activity on the Activity page, kind:project in the Projects hub. Typing it changes nothing; any other kind is an error. kind: is what comes back, while project: only narrows it: kind:task project:P-0003 is the tasks in that project, not the project.

A page that always shows part of the workspace shows that part locked after kind:task, inside the same locked chip, the same as its locked filter chips: project:P-0003 on a project's page, milestone:R-0046 on a milestone's, and space:S-0002 when it's kept in a Space (a saved view or dashboard in a Space too). They can't be removed and aren't saved with the query. Inside a Space, the filter menus and the bar's suggestions offer only that Space's projects and milestones, since another Space's could never match.

The names the bar wrote before still work and mean what they did - projectKey:, taskParentKey:, taskRootKey:, taskKey:, taskTitle:, blocksTaskKey:, blockedByTaskKey:, relatedTaskKey:, taskStarted: and milestoneTarget: and the like - so saved views, dashboards and links keep working. When the bar writes a query out, it uses the names above.

#Folders

project.folder:, milestone.folder: and label.folder: find tasks by the hub folder their project, milestone or labels are filed in. Write a folder as its path, top folder first, with / between the levels, in quotes when it has spaces: project.folder:"Plan Things Better / Web". The spaces around / don't matter, and neither does case.

  • A folder takes in everything inside it, however deep: project.folder:"Plan Things Better" finds the tasks of every project in that folder and in the folders inside it.
  • - cuts a branch out: project.folder:"Plan Things Better" -project.folder:"Plan Things Better / Obsidian" leaves out the Obsidian folder and everything inside it.
  • A folder's name alone finds every folder with that name, at any depth: project.folder:Web finds both Plan Things Better / Web and Abundant Life / Web. The suggestions show each folder's full path, so picking one writes the path that finds just it.
  • unset and any: project.folder:unset is tasks whose project isn't in a folder, or that have no project; project.folder:any is tasks whose project is in one.

They're also in the Filter menu, as Project folder, Milestone folder and Label folder, each once that hub has a folder (and Milestone folder once there are milestones). Each lists the hub's folders by their full path, then No folder; picking a folder takes in the ones inside it, as in a query.

The folder: of projects, milestones, docs, views, dashboards and labels, in their hubs' query bars and in search, works the same way.

#Stuck work

blocked-by:open finds tasks still waiting on unfinished work: at least one task blocking them is neither completed nor canceled (an archived blocker counts as finished). A task whose blockers are all done or canceled doesn't match, though blocked-by:any still does. -blocked-by:open is the other way round: nothing left to wait on. Add is:open to leave out tasks that are finished themselves: is:open blocked-by:open sort:due.

#Combining and excluding

  • Several values - separate them with commas: status:Todo,"In Progress" matches either. Different fields must all match. A field written twice is the same as one with both values: -status:Done -status:Canceled is -status:Done,Canceled, and the query bar merges them into one chip once the query runs. A custom field is the exception - each of its clauses has to match on its own.
  • Spaces in a name - put it in quotes: project:"Website redesign".
  • Excluding - put - before the field: -status:Done hides Done tasks, -root:T-0042 hides that task and everything connected to it.
  • You - me means whoever is looking: assignee:me, mentions:me.
  • Not set, or set - unset matches a task with no value (assignee:unset, due:unset), and any a task with one (project:any, custom.points:any). Every field that takes one takes the other, and - turns one into the other: -project:any is the same as project:unset. Every task has a status, a creation date and a last change, so status:unset, created:unset and updated:unset never match, and the bar warns you. A custom field kept to some Spaces or task types counts only the tasks it applies to (more).
  • Has or holds - anything a task has is a field like the rest (project:any, checklist:open); there's no has:, and the bar says which field to use instead (has:project → project:any). is: is only for the task as a whole: is:open, is:unscheduled, is:recurring.
  • Text that looks like a clause - put it in quotes: "status:todo" searches titles for those words.
  • Exactly as stored - a value with an equals sign in front (label:="q3-launch") skips me, unset, any and name matching - label:=any is a label named "any", checklist:=open a checklist named "open". The bar writes a value this way when it can't put a name to it.

Tasks, projects, milestones and Spaces are named by their key (parent:T-0042, project:P-0003, space:S-0002), which is how the bar writes them. A project's, milestone's or Space's name works too (project:Website, space:"Client work"); if two share a name, the bar says so - use the key.

Labels are written by name. The suggestions show the folder each label is in, and when two labels share a name, picking one writes it by its id, so the query finds just that one.

#Dates

Every date clause takes a day, written YYYY-MM-DD, or words for one that move with the calendar:

  • A day near today: today, yesterday, tomorrow, or today moved by days, weeks, months or years: today-28d (28 days ago), today+2w, today-1m, today+1y.
  • A stretch of days: this-week, last-week, next-week, the same for month, quarter and year (last-month, this-year), and last-7-days, next-30-days and the like. Weeks run Monday to Sunday.
  • A range: two of either with .. between them, both ends included: due:2026-10-01..2026-10-31, created:today-7d..today.

A word is saved as you wrote it, so a view or dashboard of due-before:today shows what's past due every day, without being changed. It's read by the date where you are (your profile's time zone), and an open view moves on by itself at midnight. A shared link reads it by the date of whoever made the link.

On a stretch of days, due:this-week is a day in it, due-before:this-week is before its first day and due-after:this-week after its last.

While you type, the suggestions offer these words with the days they mean beside them, and a date typed the way your workspace writes dates becomes that day. The Filter menu's date filters offer the same words as quick picks beside the calendar, and Filter → Overdue is is:overdue.

ClauseMatches tasks…
due-before: / due-after:due before / after that day (not including it)
start-before: / start-after:starting before / after that day
created-before: / created-after:created before / after that day
updated-before: / updated-after:last updated before / after that day
started-before: / started-after:started before / after that day
completed-before: / completed-after:completed before / after that day

The same words work for a task's milestone and project dates (below), date custom fields (custom.follow-up:<today), the Activity page's activity.after: and activity.before:, and the dates in every hub and in search.

#Milestone and project dates

A task can be found by its milestone's or project's dates too: tasks in milestones due this month, or in projects made before the summer. Each takes a day, unset (no milestone or project, or that date isn't set on it) or any, and has a -before: and -after: form, like the task's own dates: milestone.target-before:2026-11-01. They're also in Filter → Milestone dates and Filter → Project dates.

ClauseMatches tasks whose…
milestone.start:milestone starts that day
milestone.target:milestone is due that day
milestone.completed:milestone was completed that day
milestone.created: / milestone.updated:milestone was made / last changed that day
project.created: / project.updated:project was made / last changed that day

#Open, unscheduled and archived

ClauseMatches tasks…
is:openwhose status isn't in the Completed or Canceled category
is:unscheduledwith no start or due date
is:overduethat are open and due before today - the same as due-before:today is:open
is:recurringthat repeat
show:archivedincluding archived tasks (include: works too)
show:archived-onlyonly archived tasks
show:recurringCalendar and Timeline: upcoming repeats too, like Show upcoming repeats

#Layout and display

ClauseValues
layout:list, board, timeline, calendar, canvas, graph
group:none, status, priority, type, assignee, project, milestone, label, space, or a custom field that's a choice, choices or a person (group:custom.client)
sort:rank (manual), name, id, priority, status, due, start, estimate, created, updated, started (never-started tasks last), completed (when it was finished; never-finished tasks last: sort:-completed lists the last ones finished), type, project, milestone, assignee, labels, progress, relations, comments, subtasks, or a custom field (custom.points) - put - first for descending: sort:-due
subtasks:nested, flat, hidden
empty:show-normal, auto-collapse, auto-hide (or show, collapse, hide) - what empty groups or columns do
hide:properties to hide: type, project, milestone, priority, assignee, labels, estimate, start, due, progress, relations, checklists, or a custom field (custom.points)
zoom:Timeline: day, week, month, quarter, year, all
calendar:Calendar: month, week, 2weeks, 4weeks, schedule
date:Calendar: which date places a task - due, start, created, updated, completed, or two for a span: date:start,due
canvas-layout:Canvas: flow or tree
canvas-direction:Canvas: right or down
relations:Canvas: kinds of line to hide - blocks, parent, related

The query bar always shows layout:, group: and sort:, even when nothing is filtered, so you can see which layout you're in. Pick another layout and its layout: takes the old one's place. A query without layout: shows a list.

#Examples

QueryShows
assignee:me is:open sort:dueYour open tasks, soonest due first
label:Bug -status:Done group:priorityUnfinished bugs, grouped by priority
project:"Website redesign" layout:boardOne project as a board
due-before:2026-11-01 is:open layout:calendarOpen work due before November, on a calendar
is:overdue sort:dueEverything past due, oldest first - every day
creator:me created:this-weekWhat you've made this week
estimate:>5 -estimate:unsetBig tasks, by their estimate
root:T-0042 layout:canvasA task and everything connected to it, as a graph
project:P-0003 layout:graphOne project's tasks on the Graph

#Searching across kinds

Search (⌘K / CtrlK) reads the same language, across everything it finds: tasks, projects, milestones, docs, views, dashboards, Spaces, chat channels, labels, templates and members. Templates show for people who can use them, as on the Templates page.

  • kind: picks what comes back: kind:project,doc. The chip beside the search box shows it - All kinds without one - and picking kinds there writes kind: for you.
  • A plain field is each item's own: status:todo finds tasks and projects in Todo, status:draft docs in Draft. Something without that field (a label has no status) doesn't match.
  • {kind}.{field} is that kind's field, and finds those items and everything linked to them: project.name:website finds the Website project, its tasks and the docs attached to it.
  • {kind}: on its own is that item by key or name: project:P-0003, space:"Client work".
  • Words beside them narrow it by name, as in any search: kind:doc owner:me brief. They match an item's description (or a member's email) too.
KindIts own fields
Every kindkey, name, created, updated
Taskstatus, priority, type, label, assignee, project, milestone, space, parent, due, start, started, completed, archived
Projectstatus, space, folder
Milestonestate (status works too), space, folder, start, target, completed
Docstatus, type, owner, space, folder, shared, project, milestone, task
Viewlayout, owner, space, folder, shared
Dashboardowner, space, folder, shared
Labelcolor, folder
Spacevisibility
Channelspace
Templateowner
Memberemail, role, status

Dates take a day, words like today or this-week (see Dates), unset or any, with -before and -after (project.created-after:2026-09-01). A query that's also a task query (status:todo) still offers Open as query for its tasks.

#Other query bars

Every other query bar is written the same way - field:value, commas for several values, - to exclude, unset and any, quotes around spaces - with fields of its own. Each one suggests them as you type.

  • Activity - activity.by:, activity.action:, activity.kind:, activity.field:, activity.to:, activity.from:, activity.after: and activity.before:, alongside the task filters above.
  • Projects, Milestones and Docs - each hub's page lists its fields.
  • Shared links - who made a link, its name and what it shares, its access and status, and its dates.
  • A form's rules - the form's questions as fields.

#Databases

A Database's views take a query written with the table's own column names: each column's name in lower case, with a dash for each space. A table with Status, Due date and Owner columns reads status:Doing due-date:<today owner:me sort:-due-date group:status.

ColumnValues
Text and linkswords the cell contains
Numbers5, >5, <=5, or a range: 3..8
Datesthe same, as days (2026-11-01, <2026-11-01) or words (today)
Selectsan option's name; several, separated by commas, match any
Peopleme, a member's key, name or email
Checkboxesyes or no
Any columnany (or set) and unset

sort: takes a column (- first for descending), group: a column, and - in front of a column excludes. Words without a field search every cell.

Search help

Find a help topic

Query language - Plan Things Better help