ArtUp Query documentation
In short: type issue in and a function in the Jira search, a filter, a board or a dashboard — for example issue in subtasksOf("project = DEMO AND status = Done"). There are 24 functions in seven groups. They work with in and not in, and the app only reads your work items. You get the full result or an error with the numbers, never a cut-off list.
1. Install and first search
- A Jira administrator installs ArtUp Query from the Atlassian Marketplace (Apps → Explore more apps).
- Sites with up to 10 users use it free; larger sites start a trial or a subscription in Manage apps. Without an active licence the functions answer “ArtUp Query license is not active”.
- Open Apps → ArtUp Query. The Functions tab lists every function with its arguments and a copyable example; the Status tab shows the update queue, the index and recent errors.
- In the Jira search, switch to JQL and type a query such as
project = DEMO AND issue in hasSubtasks().
The first time on a site the index is filled once. Until it is ready, the sprint, comment and attachment functions answer “Index is building: n of m issues”.
2. How to write a function
- Write
issue in functionName(…)orissue not in functionName(…). Withnot inthe result is the exact complement ofin. - Arguments are strings in double quotes. A subquery is any JQL, a saved filter (
filter = 10001) or a list of keys. - Functions nest:
issue in subtasksOf("issue in linkedIssuesOf(\"key = DEMO-1\", \"blocks\")"). Escape inner quotes with a backslash. - Optional arguments can be left out.
currentUser()inside an argument is refused: the answer is shared by all users and computed as the app. - Combine with ordinary JQL:
project = DEMO AND issue in hasLinks("blocks") ORDER BY created DESC.
3. Function reference
The same list as the Functions tab in the app.
Work items of a query
Each takes a subquery: any JQL, filter = 10001 or a list of keys such as key in (DEMO-1, DEMO-2). The answer is computed on request and kept fresh by Jira events.
| Function | What it returns | Example |
|---|---|---|
subtasksOf(subquery) | Subtasks of the work items the subquery returns. | issue in subtasksOf("project = DEMO AND status = \"In Progress\"") |
parentsOf(subquery) | Parents of the work items the subquery returns: the task of a subtask, the epic of a task, at any level. | issue in parentsOf("project = DEMO AND type = Sub-task AND status = Done") |
epicsOf(subquery) | Epics of the work items the subquery returns. | issue in epicsOf("fixVersion = 2.0") |
issuesInEpics(subquery) | Work items in the epics the subquery returns, in company-managed and team-managed projects. | issue in issuesInEpics("project = DEMO AND status = Done") |
childIssuesOf(subquery, [depth]) | All descendants of the work items the subquery returns; the optional depth limits the levels. | issue in childIssuesOf("key = DEMO-1")issue in childIssuesOf("project = DEMO AND type = Epic", "1") |
linkedIssuesOf(subquery, [linkType]) | Work items linked to the work items the subquery returns; optionally one link type or direction, such as "blocks" or "is blocked by". | issue in linkedIssuesOf("project = DEMO AND status = Open", "blocks") |
linkedIssuesOfRecursive(subquery, [linkType]) | Work items linked directly or through other links, up to 10 levels, without looping on cycles. | issue in linkedIssuesOfRecursive("key = DEMO-1", "is blocked by") |
linkedIssuesOfRecursiveLimited(subquery, depth, [linkType]) | The same as linkedIssuesOfRecursive with the depth you set. | issue in linkedIssuesOfRecursiveLimited("key = DEMO-1", "3", "blocks") |
Links and subtasks across the site
Answered from the site index; no subquery.
| Function | What it returns | Example |
|---|---|---|
hasLinks([linkType]) | Work items that have links, optionally of one type or direction. | issue in hasLinks("blocks") |
hasLinkType(linkType) | Work items that have links of the given type (the ScriptRunner name of hasLinks). | issue in hasLinkType("Duplicate") |
hasSubtasks() | Work items that have subtasks. | project = DEMO AND issue in hasSubtasks() |
Board sprints
Take a board name or id.
| Function | What it returns | Example |
|---|---|---|
previousSprint(board) | Work items of the last closed sprint of a board. | issue in previousSprint("DEMO board") |
nextSprint(board) | Work items of the next future sprint of a board. | issue in nextSprint("DEMO board") |
Sprint history
Built from the Sprint changelog in the site index. Take a board and a sprint (name or id).
| Function | What it returns | Example |
|---|---|---|
addedAfterSprintStart(board, [sprint]) | Work items added to a sprint after it started, even if removed later; without a sprint, the active sprint of the board. | issue in addedAfterSprintStart("DEMO board")issue in addedAfterSprintStart("DEMO board", "DEMO Sprint 7") |
removedAfterSprintStart(board, [sprint]) | Work items removed from a sprint after it started and not returned before it closed. | issue in removedAfterSprintStart("DEMO board") |
incompleteInSprint(board, sprint) | Work items that were in the sprint when it closed and not done. | issue in incompleteInSprint("DEMO board", "DEMO Sprint 6") |
completeInSprint(board, sprint) | Work items that were in the sprint when it closed and done. | issue in completeInSprint("DEMO board", "DEMO Sprint 6") |
Comments
Read the comment index. Comments with restricted visibility are ignored.
| Function | What it returns | Example |
|---|---|---|
commented([clauses]) | Work items with comments matching the clauses: by, after, before, on, inRole, inGroup. | issue in commented("after -7d inRole Developers") |
lastComment([clauses]) | Work items whose last comment matches the clauses. | issue in lastComment("before -14d") |
hasComments([count]) | Work items with comments: without a number, any; "n" for exactly n, "+n" for more than n, "-n" for fewer than n. | issue in hasComments("5")issue in hasComments("+5")issue in hasComments("-3") |
Attachments
Read the attachment index.
| Function | What it returns | Example |
|---|---|---|
fileAttached([clauses]) | Work items with attachments matching the clauses: by, after, before, on, ext. | issue in fileAttached("after startOfWeek() ext pdf") |
hasAttachments([extension]) | Work items with attachments, optionally of one file extension. | issue in hasAttachments("xlsx") |
Compare fields
Take a subquery and an expression over fields of each work item.
| Function | What it returns | Example |
|---|---|---|
dateCompare(subquery, expression) | Work items of the subquery where one date field compares to another, such as resolutiondate > duedate or created + 2d < firstCommented. | issue in dateCompare("project = DEMO", "resolutiondate > duedate") |
expression(subquery, expression) | Work items of the subquery where arithmetic over number and time fields is true, such as timespent > originalestimate * 1.2. | issue in expression("project = DEMO", "timespent > originalestimate * 1.2") |
Conditions of commented, lastComment and fileAttached
The argument is a list of conditions separated by spaces:
by— the author of the comment or attachment (currentUser()is not supported);after,before,on— dates:after -7d,on 2026/03/28,after startOfWeek();inRole,inGroup— the author belongs to the role or group (comments only);ext— the file extension without a dot, such aspdforgz(attachments only).
The conditions roleLevel and groupLevel (the comment's own visibility) are planned for a later version; today they answer “Clause is not available yet”. Comments with restricted visibility are ignored by every function, so a result never reveals that a restricted comment exists.
hasComments takes a count: "5" exactly five, "+5" more than five, "-3" fewer than three.
dateCompare and expression
dateComparecompares two date fields: operators< > <= >= =, an interval such as+2dor+1won either side, and the pseudo-fieldsfirstCommentedandlastCommented.expressiondoes arithmetic over number and time fields:timespent > originalestimate * 1.2. Units areNw,Nd,Nh,Nm, and the ScriptRunner nameswdandww. Compare with> < >= <= = == !=. Write a field whose name has spaces without the spaces, or ascustomfield_NNNNN.
4. Dates, time zone and working time
- Dates in conditions (
after,on,before,-7d,startOfWeek()) are in UTC, and weeks start on Monday. Jira does not tell a function the time zone of the user, so a day boundary can differ from the one you see in Jira by your offset from UTC. - In
expression, 1d of work time is 8h and 1w is 5d, the Jira default. Jira does not pass the site's time-tracking settings to a function. This differs from ScriptRunner, wheredis a 24-hour day;wdandwware supported.
5. Excluded projects
A Jira administrator opens Apps → ArtUp Query settings and chooses projects to exclude from the index — for example a large archive project.
- Their sprint history, comments and attachments are removed from the index.
- Under
in, work items of excluded projects never match a function that reads the index or runs the app's own searches. Undernot inthe result is the exact complement, so they appear like any other work item outside the result. - A few functions are answered by Jira itself and are not filtered:
previousSprint,nextSprint,hasAttachments()without an extension,hasComments("-n")and, in most cases,hasLinksandhasLinkType. - A sprint function for a board of an excluded project answers “Project X is excluded from the ArtUp Query index” instead of an empty result.
- The same page can reindex one project or rebuild the whole index. A work item moved to another project keeps its old project in the index until you reindex the old project and then the new one.
6. Freshness and the index
The functions keep their results up to date from Jira events, within Jira's API allowance for apps — the amount an app may read from Jira per hour.
- Functions that read the app's index (links, subtasks, sprint history, comments, attachments) and functions over small subqueries answer within seconds.
- Edits reach the results through Jira's change events, which arrive in a queue. Ordinary edits show up soon; bulk imports and bulk edits take longer.
- Large results update later: the app spreads their recomputation over time so that it stays within the allowance.
- A new site builds its index once, at the pace the allowance permits. Until it is ready, the sprint, comment and attachment functions answer “Index is building: n of m issues”.
The Status tab shows what is waiting and how far the index has come. Times depend on your site and on Jira's own load.
If a function needs more than a few seconds to compute, it answers “Computing, retry in a minute” and finishes in the background — never an empty or partial result.
7. Errors
A problem is reported in the JQL editor in English (Jira does not give a function the user's language). The app pages are in 26 languages.
| Message | Meaning |
|---|---|
| Board "X" not found; Sprint "Y" not found | The name or id does not exist. If several match, use the id. |
| Subquery rejected by Jira | The JQL in the argument is not valid; the message carries Jira's own text. |
| Index is building: n of m issues | The first fill is not finished. |
| Computing, retry in a minute | A long computation continues in the background. |
| The result needs n issues; one function returns at most m | Narrow the subquery. How many issues one function can read depends on the function and on Jira's API allowance for apps; the message names the limit. |
| Project X is excluded from the ArtUp Query index | An administrator excluded it. |
| ArtUp Query license is not active | The site has more than 10 users and no active licence. |
| Unknown clause, Invalid date, Unclosed quote… | A condition is not valid; the message lists what is allowed. |
The Status tab keeps the recent errors with the function name and message. It never stores the arguments, which hold your JQL.
8. Coming from ScriptRunner
Names and arguments are the same wherever the meaning is the same. Write issue in instead of issueFunction in: issue in subtasksOf("project = DEMO"). ScriptRunner Enhanced Search on Cloud works only on its own search screen; ArtUp Query works in the standard Jira search.
| Difference | In ArtUp Query |
|---|---|
childrenOf (Cloud), portfolioChildrenOf (DC) | childIssuesOf(subquery, [depth]) |
parentsOf depth argument (Cloud) | None; parentsOf covers parents at any level. |
linkedIssuesOf with several link names (DC) | One link type or direction; use two calls joined by OR for more. |
hasLinks("blocks", "+2"), hasAttachments("pdf", "+3") (a count) | Not supported yet; the call answers with an error. |
incompleteInSprint and completeInSprint without a sprint | The sprint is required (the state when the sprint closed). |
d in expression is a 24-hour day | 1d is 8h; wd and ww work as in ScriptRunner. |
.clearTime() in dateCompare | Not supported. |
roleLevel, groupLevel, visibility | Not available in this version; restricted comments are ignored. |
9. Limits
- Jira Cloud only; company-managed and team-managed projects.
- The functions are the same for every user: results do not depend on who runs them, and the app reads as itself. Work items a user cannot see are still hidden by Jira when it applies the result to the search.
- A result that cannot be returned in full is an error with the numbers, not a cut-off list. How many issues one function can read depends on the function and on Jira's API allowance for apps; the error names the limit.
- No search in the text of comments or attachments.
10. Data handling
No external servers and no egress. The app reads work items, links, the hierarchy, Sprint and status changes, and comment and attachment metadata as the app. It stores ids, dates, status categories, the account ids of comment and attachment authors, the visibility type of comments, file extensions and cached result ids; it does not store issue text, comment bodies or attachment content. The only write scope, write:app-data:jira, saves the JQL function results. Details: Privacy Policy and Security.
11. Languages and support
The app pages follow each user's Jira language (26 languages) and the light or dark theme.
Questions, bug reports and feature requests: [email protected]. Please include your Jira site URL, the JQL you ran and the message you saw. See Support.