JQL Gaps for Jira: documentation
User documentation for the Marketplace listing. This file is the source of truth: it is published as is by toolooloo-site (npm run sync && npm run build), and that URL goes in the listing's Documentation field. Edit the file, never the published page.
What the app does
Jira's JQL search engine has a fixed vocabulary: it knows assignee, status, created, and a short list of others, and nothing you type teaches it a new one. JQL Gaps adds 26 functions to that engine — typed inline, in the same search bar, exactly like a native keyword — for questions the built-in engine cannot answer at all: business days instead of calendar days, one date field compared to another, a work item's full sprint history, a real regular expression on any field, and more.
What it does not do. It is not a visual query builder and does not replace JQL syntax — every function is JQL, typed the way any other clause is. It does not sync or index your instance in the background: each call answers from what Jira returns at the moment of the search.
Requirements
- Jira Cloud. There is no Data Center or Server version.
- No external account, no server, no configuration file. The app runs entirely on Atlassian infrastructure.
Installing
- Open the listing on the Atlassian Marketplace and choose Get it now, or in Jira go to Apps > Explore more apps and search for JQL Gaps for Jira.
- Pick the site to install it on and confirm the permissions.
- That's it. Every function is available in the search bar immediately — there is no index to build and no button to press first.
Installing requires Jira administrator rights. Using a function in a search does not.
Finding a function: the reference page
Jira's own autocomplete shows a function's name and nothing else — no signature, no arguments, no allowed values. Open Apps > JQL Gaps for Jira > Reference for the full list: each function's syntax, what it answers, its arguments with their allowed values, and a Try it on your data button that runs the example against your own site in one click. A free-text filter searches by name, category or keyword.
The function catalogue
| Category | Functions |
|---|---|
| Dates | businessDays, dateCompare, fieldCompare, duplicateField |
| Hierarchy | parentMatch, childMatch, hasChildren, descendantMatch, childrenCount, childrenAll |
| Sprints | sprintDate, sprintChanges, addedToSprintAfterStart |
| Attachments | attachmentMatch |
| Text | fieldMatch, projectMatch |
| People | inactiveUser, commentedBy, activityBy, loggedTimeBy |
| Links | linkedMatch, remoteLinkMatch |
| Projects & versions | versionDate |
| Comments | commentCount |
| Changelog | fieldWas, businessTimeInStatus |
The reference page groups these the same way, with the full signature and examples for each — this table is an index, not a substitute for it.
Two rules that shape how a function is called
Most functions need a starting search. A JQL function can return at most 1000 identifiers, and a function that scanned your whole instance on every keystroke would be slow at best. So a scanning function takes a subquery as its first argument — the search you would already narrow down to by hand — and answers only within it:
issue in businessDays("duedate", "<=", "3") issue in parentMatch("project = OPS AND labels = security")
Four functions can answer instantly for the whole site. sprintChanges, inactiveUser, hasChildren and attachmentMatch accept "*" in place of a subquery, because the fact they answer (a sprint entered or left, an account deactivated, whether children exist, a file extension) is a short, fixed vocabulary the app can answer from Jira's own index rather than a scan:
issue in sprintChanges("*", "removed", "Sprint 42") issue in inactiveUser("*", "assignee")
Passing "*" to any other function is refused by name, with a message explaining why — the fact it would need to precompute is not a fixed vocabulary (a regular expression, or a comparison between two fields chosen at query time, has no finite list of answers to look up in advance).
A JQL escaping detail worth knowing
JQL's escaping rules are not a regular expression's. Native JQL recognises only \', \", \t, \n, \\ and \uXXXX — so a pattern like \.pdf$, which reads correctly as "a literal dot" in most regex dialects, is invalid JQL and must be written with the backslash doubled:
issue in attachmentMatch("project = OPS", "\\.pdf$")
This is the first thing most people trip on with the two pattern-matching functions, fieldMatch and attachmentMatch.
Troubleshooting
A function returns nothing, and I expected a match. Check the subquery first: every scanning function only looks inside it, so a subquery that is narrower than intended silently narrows the answer with it. Second, check the JQL escaping note above if the function takes a pattern.
The reference page's "Try it" button opens an empty search. The example is run exactly as written, against your own data — an empty result means no work item on your site currently matches that example, not that the function failed.
A function that reads a sprint or work-item hierarchy needs the matching Jira setup: a Scrum board with active sprints for the sprint functions, and a work item type above the one you are searching (an Epic, for hierarchy functions that walk upward).