An automation rule answers three questions: when (the event), in what state (the condition) and what to do (the actions). Every automated change is journalled with the rule's name and revision number — everything that happened by itself has a signature.
A rule and its scope
A rule belongs to the company and names its own scope: a list of projects, or all of them. A rule has an owner and an acting account: rights are checked against that account at the moment the rule acts. By default it is the creator; a company administrator can replace it with a service account — and only with a service account: a rule acting as somebody who left stops working with them, while a service account outlives people.
Creating rules takes administering at least one project. Editing a rule takes administering every project in its scope; a rule over all projects is edited by company administrators only. Seeing a rule takes seeing its whole scope.
Events
| Event | When it happens |
|---|---|
| Issue created | A new issue appeared. |
| Issue updated | The issue's fields changed. Can be narrowed to a list of fields. |
| Issue transitioned | The issue changed status. Can be narrowed by from-statuses and to-statuses. |
| Comment added | Somebody commented on an issue. |
| Scheduled | A time from the rule's schedule arrived. |
The event speaks about change: which fields moved, from which status to which. The condition speaks about the present: what the state is now. "Status left X" is a trigger setting; "status equals Y" is a condition.
Conditions
A condition is written in QQL — the same language as search, with the same fields and functions. An empty condition means "on every matching event". The condition is judged through the eyes of the rule's account: an issue that account cannot see never matches, so a rule cannot touch what its account would not be shown.
A condition with an error does not publish: it is parsed at publication, and the message points at the position in the query.
Actions
Actions come in two kinds, and the difference is worth understanding before it matters:
Run inside the user's action: assign, set a field, add a label. They are part of the change itself — if such an action cannot run, the change that woke the rule is undone with it, and the person sees the refusal immediately, on screen.
Run after it: add a comment, transition, notify a person, link issues, log time, call an external address. They run after the change is saved, and their failure never undoes anybody's work — a comment that failed to appear is a missing comment, not a lost edit.
Values are validated at publication: a rule writing an unknown code into a select field does not publish, instead of silently damaging data at its first event. The duration for logging time is parsed then too: "an hour and a half" is refused at publication, 1h 30m is accepted.
Drafts, publication, revisions
A rule is born a draft: disabled, and never acting. Only what is published acts — publication freezes the content into a revision, and execution reads revisions only. An edited but unpublished change does not act, even on an enabled rule: the rule speaks with its last publication's voice.
Revisions are never rewritten. Going back to an old revision is a new publication with the old content: history only grows. Every journal entry names the revision the rule acted with, and that stays verifiable forever — even after the rule is deleted, because deletion is soft and the journal and revisions stay readable.
The dry run
The check is the section's main screen: the rule runs over real issues writing nothing. The same condition parser, the same rights, the same action order — but instead of executing, a plan is collected: which issues matched, which actions would run, and what the outbound call would look like, down to the request body with the secret masked. The issues that did not match are shown too.
A draft can be checked as well — it is the only way to see what a rule will do before it starts. Checks are limited, because a rolled-back run costs as much as real work: up to 50 issues per run, 6 runs per minute per person, 10 seconds per run.
Schedules
A scheduled rule waits for no event: it names its own selection in QQL, a time, and a repeat — daily, weekly by weekdays, monthly by days of the month.
- The timezone belongs to the rule, not the company. In a distributed company "every Monday at 9:00" is a different moment per rule; the company timezone is only the starting suggestion.
- Missed slots are not caught up. If the product was unavailable at the appointed time, the rule runs at the next appointed time, once. Waking up, it does not replay what it missed: three missed Mondays do not become three runs on Tuesday.
- One run handles up to 500 issues. When the selection is wider, the rule handles 500 and marks how many were left; after three truncated runs in a row the owner gets a letter.
- Every issue of the selection runs in its own transaction: one issue's failure is recorded and counted, and the rest of the selection continues.
- While the previous run is still going, the slot is skipped with a journal entry: a rule does not run beside itself.
Cascades and their limit
A rule's action can wake other rules: a transition is an "issue transitioned" event. The chain is bounded:
- A rule never meets its own consequences: within one chain, each rule fires at most once. A closing loop is cut, with a journal entry.
- Cascade depth is limited: 3 by default. Beyond it the chain stops, journalled.
- Rate is limited: 60 firings per minute per company by default. Beyond it firings are refused, journalled.
The whole chain carries one correlation id: the journal shows what woke what, and at which depth.
Outbound calls
A rule can send data outside Quevell. This is built so that "where" and "what" are the company's decisions, not the rule's:
- The allowlist. Calls go only to hosts on the company's list, kept by a company administrator. An empty list means outbound calls are off. Removing an address does not delete the rules that used it — their calls start being refused, into the journal.
- HTTPS only. The address is always assembled as
https://host/path; a plaintext call is inexpressible. Methods: POST, PUT, PATCH. - Only what is named leaves. The rule enumerates the fields that leave the product:
key,type,status,link,summary,priority, and custom fields by name. "The whole issue" is not an option: nothing leaves by default. - The authorization secret is stored encrypted, always shown as a mask, and never journalled. It can be replaced; it cannot be seen again.
The request body has a fixed shape, version 1: version, event, sentAt, idempotencyKey, rule (id, name, revision) and issue with exactly the enumerated fields. Limits: 5 seconds per call, 64 KB for the request and for the read part of the response. The journal records that the call happened and the response status; the response body is never journalled.
Auto-disable
A rule whose deferred actions keep failing switches itself off: after 5 consecutive failures by default. This is journalled, and the rule list marks it as disabled by the product rather than by a hand.
What to do: open the rule's journal, find what the last failures say, fix the cause, and enable the rule again. Enabling resets the failure count.
The journal
The journal is one feed: firings and refusals together. Every entry names the rule, the revision, the issue, the cascade depth and the correlation id. Refusals carry their reason: a loop was cut, the depth ran out, the rate was exceeded, the issue is not visible to the rule's account, the rule was disabled.
One rule's journal lives inside the rule and is visible to whoever sees the rule itself. The company-wide feed is a separate right — it is granted, and company administrators hold it by default.
Limits
Limits belong to the company and are changed by a company administrator. The defaults:
| Limit | Default |
|---|---|
| Rules per company | 100 |
| Actions per rule | 10 |
| Firings per minute per company | 60 |
| Cascade depth | 3 |
| Auto-disable after consecutive failures | 5 |
| Issues per dry run | 50 |
| Dry runs per minute per person | 6 |
| Issues per scheduled run | 500 |
| Time per outbound call | 5 seconds |