Jira connector
Resolves three things against the Jira Cloud REST API v3: exact issue keys, vague "my last task" references, and Jira links the message already carries.
| Message | Resolves to |
|---|---|
EVER-123 is blocked | that issue, by key |
finished my last task, what's next? | the author's assigned issues, in-progress first |
https://yourorg.atlassian.net/browse/EVER-123 | that issue, enriched with status and assignee |
A pasted link is the unambiguous case — it names exactly one issue — so it outranks every inferred match.
Configuration
[connectors.jira]
base_url = "https://yourorg.atlassian.net" # required
email = "bot@yourorg.com" # required — the account the token belongs to
api_token_env = "JIRA_API_TOKEN" # required — the token lives ONLY in the env var
# chat user id -> Jira accountId (NOT a username, NOT an email)
[connectors.jira.user_map]
U0123ABC = "5b10ac8d82e05b22cc7d4ef5"
| Key | Required | Meaning |
|---|---|---|
base_url | ✅ | Site root; trailing slash trimmed. Also the link matcher's authority |
email | ✅ | Atlassian account email the API token belongs to |
api_token_env | ✅ | Env var holding the API token |
[…user_map] | — | Chat user id → Jira accountId |
Auth is Jira's standard HTTP Basic: base64(email:token). The header is built
once at startup and never logged.
Getting the API token
id.atlassian.com/manage-profile/security/api-tokens → Create API token. Then:
export JIRA_API_TOKEN=...
The token inherits the permissions of the account it belongs to, so give it a service account with read access to the projects you want resolved — not someone's personal admin account.
The accountId trap
user_mapvalues must be JiraaccountIds, not usernames and not emails.
Assignee searches are keyed on accountId; anything else silently matches
nothing. Since GDPR, Atlassian's APIs stopped accepting usernames at all.
Find an accountId from the profile URL:
https://yourorg.atlassian.net/jira/people/5b10ac8d82e05b22cc7d4ef5
^^^^^^^^^^^^^^^^^^^^^^^^
or with the API:
curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
"https://yourorg.atlassian.net/rest/api/3/myself" | jq -r .accountId
An unmapped author resolves to nothing — a normal answer, not an error. Exact
keys (EVER-123) still work without a mapping, because they need no author
inference.
Confidence
| Situation | Confidence |
|---|---|
| Named by a URL in the message | 0.99 |
Fetched by an exact key (EVER-123) | 0.95 |
| The author's sole in-progress issue | 0.80 |
| Any other assignee-search match | ≤ 0.70 |
The inferred cap sits right at the default [policy] min_confidence of 0.7
on purpose: a guess among several tickets is at the bar, not comfortably over
it. Raise min_confidence to 0.8 and only links, exact keys and sole
in-progress issues will ever be posted publicly.
Vague references run one assignee search (max 5 results, in-progress ranked first) and are scored by title-token overlap with the message text.
Link enrichment
With [policy] unfurl_links = true, base_url doubles as the link matcher's
authority: only URLs on that host — and under its path prefix, which is
what makes Jira Server installs mounted at /jira work — are claimed.
Everything else is silently left to the other connectors.
# Jira Server / Data Center mounted under a path
[connectors.jira]
base_url = "https://tools.acme.internal/jira"
Host comparison is normalized: letter case, a leading www., and a default
port are all ignored.
Health check
everasync doctor
Calls GET /rest/api/3/myself. Two useful signals:
- 401/403 — the email + token pair is wrong, or the token was revoked.
- 404 —
base_urlis not a Jira site root. This is the common one: people paste a board URL (.../jira/software/projects/EVER/boards/1) instead of the site root.
Behaviour and limits
- Jira Cloud REST v3. Jira Server exposes a compatible surface at the same
paths for these endpoints; set
base_urlto the mount point. - Read-only. Ever Async never transitions, comments on, or assigns an issue.
- 6-second timeout per resolve, counted as
ever_async_connector_calls_total{connector="jira",outcome="timeout"}. - Issue-key extraction is generic (
[A-Z][A-Z0-9]{1,9}-\d{1,6}), so a string likeAWS-123in prose is offered to Jira as a candidate. If it is not a real key, Jira answers nothing and the message is unaffected.