One syntax for every surface: search, lists, boards, roadmaps, calendars, the Support Desk queue, reports, automation and dashboard widgets. History operators, relative date maths, positional validation — and an AI mode that hands you back a query, never a black box.
Written for people who already know a query language and want to know what changes.
WAS, WAS IN and CHANGED for yearsIN / NOT IN, IS EMPTY, ORDER BYcurrentUser()-style function for personal queriesfixVersion: Trakr has no project versions by designBETWEEN is refused, not guessedcurrentUser() is refused in an automation rule's filterClauses, boolean operators, grouping and an optional sort. There is nothing else to learn.
A query is a sequence of field operator value clauses joined by AND or OR, optionally grouped with parentheses, optionally negated with NOT, and optionally sorted.
field operator value [AND | OR] … [ORDER BY field [ASC | DESC]]
# my open work, most urgent first
project = OPS AND statusCategory != DONE AND assignee = currentUser()
ORDER BY priority DESC, updated DESC
# anything that went through review and closed last quarter
status WAS "In Review" AND resolution = DONE AND resolved > -1q
# tickets that were handed off — who did Luc give away?
assignee CHANGED FROM "luc.dupont" AND updated BETWEEN -14d AND now()
# unassigned and due before the week is out
project = SUP AND assignee IS EMPTY AND due < endOfWeek()
# full-text across summary and description
text ~ "certificate expired" AND created > -7d
# service-linked work with real time on it
service = "Payments" AND label IN (regression, hotfix) AND timeSpent > 2h
# everything that blew a first-response target
firstResponseBreached = true AND slaDue < now() ORDER BY slaDue ASC
# the backlog in the order the team actually ranked it
project = OPS AND statusCategory = TODO ORDER BY rank ASC
The complete list, grouped the way autocomplete groups it. Nothing hidden, nothing deprecated.
project · key (wildcards) · type · status · statusCategory · priority · resolution · summary · description · feature · requestKind · incidentFlag
requestKind is what makes service requests, incidents, problems and changes queryable side by side — they are all tickets, not separate record types.
assignee · reporter · watcher
All three accept currentUser(), a username, or a list. Negation reaches empty rows: assignee != ana returns unassigned tickets too, which is almost always what you meant.
created · updated · due · startDate · resolved
Every date field takes an absolute date, a date function, or relative date maths. A bare date means the whole day, not midnight — created = 2026-08-28 does what you expect.
component · service · label · parent
service is the ITSM services catalogue; service IS EMPTY finds work nobody has mapped to a service yet.
originalEstimate · timeSpent
Both take duration notation — 30m, 2h, 1d — where a day is eight hours, the same conversion the timesheets and budget reports use.
linkedTo · blocks · blockedBy
Query the dependency graph without opening it: blockedBy IS NOT EMPTY AND statusCategory = IN_PROGRESS is a standing list of work that cannot actually move.
text
Backed by a GIN full-text index over summary and description. Use ~ to match and !~ to exclude; summary and description remain separately queryable when you need to be precise.
slaStatus · slaDue · firstResponseBreached · resolutionBreached
SLA state is a first-class query target, not a report you have to run. See SLA management for how those values are produced.
Including the five historical operators, which read the activity log rather than the current row.
= !=assignee != ana includes unassigned tickets.> >= < <=priority uses your organisation's own priority rank, not alphabetical order.BETWEEN … AND …~ !~text this runs against the full-text index.IN NOT INlabel IN (regression, hotfix).IS EMPTY IS NOT EMPTY= null.WAS WAS NOTCHANGEDCHANGED FROM CHANGED TOAND OR NOT ( )Everything a saved filter needs to still be correct next quarter without being edited.
currentUser()now() today()startOfDay() endOfDay()startOfWeek() endOfWeek()startOfMonth() endOfMonth()startOfQuarter() endOfQuarter()startOfYear() endOfYear()-7d +3d -2w7d.-1m -1q -1yresolved > -1q is a rolling quarter that never needs maintenance.30m 2h 1doriginalEstimate and timeSpent. One day is eight hours, matching the working-day maths used in timesheets and budgets.Every query language has behaviours you only discover at 6pm on a Friday. Here are ours, upfront.
status matches workflow status names first, and only falls back to matching a category when no status carries that name. So status = "In Review" means the status your workflow actually defines, while status = DONE still works when nobody named a status "Done".
When you specifically want the category — across projects with different workflows — ask for it: statusCategory = IN_PROGRESS.
Comparisons like priority >= High use your organisation's own priority ordering — the position you assigned in settings. If you renamed the set, added a fifth level or reordered them, TQL follows.
This also drives ORDER BY priority DESC, so the top of the list is the top of your scale.
created = 2026-08-28 matches everything filed that day, not the single instant of midnight. It is the reading a human intends, and it removes the classic off-by-one-day bug from every saved filter.
When you want the edge instead, startOfDay() and endOfDay() are there.
assignee != ana returns unassigned tickets. In SQL terms that is a deliberate departure from three-valued logic, because "not Ana" in an operations review always means "including the ones nobody has picked up".
The same applies to service, component and the rest of the collection fields.
Writing created BETWEEN -30d and nothing else does not silently become an open-ended range. It is a validation error naming the missing bound. Guessing here produces a plausible, wrong answer — which is worse than no answer.
Sort by created, updated, due, startDate, resolved, priority, status, type, key, summary, assignee, reporter, cycle — and by rank, the project's own hand-ordered backlog position.
Every sort is tie-broken by key, so pagination is stable and page two never repeats a row from page one.
The failure mode that costs you money is a query that runs and quietly ignores half of what you asked.
Validation returns an error with a position in the query string, so the editor can put the caret where the problem is. The cases it names:
Autocomplete works against the same metadata the validator uses — field names and their values — so most of these never reach the point of being submitted.
Learn it once. It is the same parser on every one of these, which is the actual argument for TQL.
/ keyboard shortcut from anywhere in the product.requestKind = PROBLEM is an ordinary clause. See ITSM.SAVED_FILTER widget renders any saved query as a table with its own column manager and CSV export.A query you had to think about should only be written once.
Saved filters are the connective tissue: the same definition drives a dashboard widget, an automation rule's selection, and a scheduled report.
Not a natural-language search box. A query generator that shows its work.
The TQL badge on the search bar switches to AI. You ask a question in your own words; Trakr returns generated TQL — never results. The query appears under the bar, editable as ordinary TQL, and it is run through the same parser and validated before it is handed back. If the model produces something the parser refuses, you never see it.
This is the whole design argument. A natural-language search that returns rows asks you to trust an answer you cannot inspect. Returning the query means you can read it, correct it, save it, and re-run it tomorrow with identical semantics.
you type › high priority bugs Luc picked up this month that are still open
trakr returns ›
type = Bug AND priority >= High AND assignee = "luc.dupont"
AND statusCategory != DONE AND created >= startOfMonth()
Models are bad at usernames and good at names. A TqlPeopleResolver injects your organisation's own directory into the prompt in the form luc.dupont (Luc Vermeulen), then rewrites a loose assignee ~ "Luc" into an exact assignee = "luc.dupont".
currentUser() and lists Never rewrittenPast 200 accounts the roster is omitted rather than truncated — a half-directory would make the model confidently rewrite the wrong person, and a resolver that is sometimes wrong is worse than one that is sometimes absent.
AI features run against whichever provider your organisation configured, including self-hosted and OpenAI-compatible endpoints. See AI in Trakr.
No, and the honest comparison matters. JQL has had history operators for years — WAS, WAS IN, WAS NOT and CHANGED with its modifiers are long-standing Jira features, and anyone telling you otherwise is wrong.
What TQL offers is one syntax that behaves identically on every surface in Trakr — global search, ticket list, board, roadmap, calendar, Support Desk, Service Management, the report generator, automation rules and dashboard widgets — with live autocomplete on fields and values, and validation that returns an error with a character position rather than silently dropping a clause.
Yes. TQL has five historical operators — WAS, WAS NOT, CHANGED, CHANGED FROM and CHANGED TO — backed by the activity log and supported on status, assignee, priority, resolution and type.
They combine freely with ordinary clauses and with relative dates, so status WAS "In Review" AND resolved > -1q is a single query rather than a report.
Validation returns an error with a position in the query string. It names unknown fields and suggests the closest real one, catches unbalanced parentheses, unclosed quotes, an operator that is invalid for the field's type, a historical operator on a field that does not support one, and a missing value.
A clause is never silently dropped. A query either runs exactly as written, or it is refused with an explanation.
Yes. The TQL badge toggles to AI mode: you ask a question in plain language and Trakr returns generated TQL — never results. The query appears under the search bar, editable as ordinary TQL, and it is run through the same parser and validated before it is handed back.
A people resolver injects your organisation's own directory into the prompt so "assigned to Luc" becomes the real username. Only unambiguous names are rewritten, customers are excluded, and currentUser() and lists are left alone.
The global search bar with autocomplete, recent searches, a saved-filter dropdown and a / shortcut; the advanced search page with a scope selector for All, Projects or Support Desk; the ticket list, board, roadmap and calendar; the Support Desk queue and Service Management; the report generator and saved reports; automation rule selection; and SAVED_FILTER dashboard widgets.
Saved filters come in three flavours: personal, shared organisation-wide, and favourite. A saved filter can be picked from the search bar's dropdown, driven into a dashboard widget, used as the selection filter for an automation rule, or scheduled as a report with its figures delivered in the mail body.
TQL ships in every Trakr tier, on every surface, with no add-on and no query limits.