Jira Cloud connector
The Jira connector lets an AI agent read issues, comment, and update fields in your Jira Cloud project — without holding your Jira credentials, and with sensitive changes (like moving an issue to "Done") paused for a human. The agent proposes the change; Axtary authorizes the exact payload and makes the Jira call from inside your machine.
What it's for
Say you have an agent that triages incoming bugs: it reads an issue, adds a summary comment, and tweaks the priority. Useful — but you don't want it silently closing tickets or transitioning issues through your workflow without a human glance. This connector lets the everyday actions through and stops to ask before a protected status change, while keeping the Jira token off the agent entirely.
The agent never receives the Jira credential. The Jira REST calls happen in the local enforcement plane, only after the exact action has been authorized.
What an agent can do
| Action | What it does | Default treatment |
|---|---|---|
jira.issues.read | Read one issue by its key | allowed within your project scope |
jira.comments.create | Add a comment (plain text is converted to Jira's format) | allowed within your project scope |
jira.issues.update | Update summary, description, priority, or status | pauses for approval on protected statuses |
Status changes are handled carefully. Status isn't just another field in Jira — it's a workflow transition. So when an agent asks to move an issue to, say, "Done", Axtary first reads the issue's available transitions, resolves the requested status to the matching transition, and submits that. If the target isn't reachable from the current state, it fails before changing anything and tells you which statuses were available.
What happens when the agent updates an issue
- The agent proposes the change — e.g. set issue
SCRUM-1's status to "Done" — and sends it to Axtary. - Policy decides. A comment or priority tweak inside your project is
allowed; a protected status like "Done" returns
step_upand waits. - A human approves the exact change, bound to its payload hash.
- Axtary executes the Jira REST call locally and records a decision plus an outcome in the tamper-evident ledger.
$ # agent tries to move an issue to a protected status
decision: step_up
reasons: [jira_update_inside_policy, step_up_protected_status]
Connect it
Option 1: API token (simplest, live-verified)
Create an API token for a dedicated Jira Cloud user (not your own admin account) and export it with that account's email:
export JIRA_EMAIL="you@example.com"
export JIRA_API_TOKEN="..."
Point Axtary at your site:
adapters:
jira:
mode: rest
auth: api_token
emailEnv: JIRA_EMAIL # the env var names — not the values
tokenEnv: JIRA_API_TOKEN
siteUrl: https://your-site.atlassian.net
Option 2: OAuth 2.0 (3LO)
Status: the API-token path above is verified end to end. This OAuth path is implemented and unit-tested but has not yet been exercised against a live Atlassian OAuth app — verify it in your own environment before relying on it in production.
Register an Atlassian OAuth 2.0 integration with scopes read:jira-work,
write:jira-work, read:me, and offline_access, then run the browser flow.
Like every Axtary OAuth flow, the token is captured and stored locally — Axtary
never sees your client secret:
export AXTARY_JIRA_CLIENT_ID="..."
export AXTARY_JIRA_CLIENT_SECRET="..."
axtary connect jira --redirect-uri https://your-tunnel.example/callback
Atlassian requires the callback to match the registered URL, and the HTTPS URL
should forward to the local listener on port 7878. Axtary discovers the Jira
sites the token can reach and stores the chosen cloud ID and site URL as
non-secret metadata; the access and rotating refresh tokens stay in the local
credential broker. If the account can reach more than one site, name it:
axtary connect jira \
--redirect-uri https://your-tunnel.example/callback \
--cloud-id YOUR_CLOUD_ID
adapters:
jira:
mode: rest
auth: oauth
tokenEnv: JIRA_OAUTH_TOKEN
cloudIdEnv: AXTARY_JIRA_CLOUD_ID
siteUrl: https://your-site.atlassian.net
The broker credential takes precedence over the fallback env vars. Expired access tokens are refreshed locally, and Atlassian's replacement refresh token is saved with the new access token.
Check it before you write
Confirm the credential works without touching any issue — the smoke check only
calls GET /rest/api/3/myself (it identifies the authenticated user and nothing
else):
axtary doctor connectors --config axtary.yml
axtary smoke --config axtary.yml
Then, before pointing it at real tickets, exercise it in a throwaway project:
send a read, a reversible comment, and a non-destructive field update, confirm
the outcomes in the ledger, and run axtary attest-ledger followed by axtary verify-export to prove the record is intact.
FAQ
Does the agent ever see my Jira token? No. The token stays in the local credential broker or env; the agent only talks to Axtary, which makes the Jira call for it.
Can the agent close or transition issues on its own?
Only if your policy allows that status. Protected statuses return step_up and
wait for a human; an unreachable transition fails before anything changes.
What if I ask to move an issue to a status it can't reach? The update fails before mutating the issue and reports which statuses were actually available from the current state.