Jira Data Center tracker adapter¶
Bernstein can pull work from a self-hosted Jira Data Center (or late-model Jira Server) deployment, post progress comments back to the underlying issue, and transition issues through the workflow when a task completes. The adapter is the sibling of the GitHub Projects v2 adapter and follows the same AbstractTrackerAdapter contract.
The adapter lives at bernstein.core.trackers.builtin.jira_dc_adapter and is disabled by default. Operators opt in via bernstein.yaml.
Auth¶
Jira Data Center supports bearer-token auth with Personal Access Tokens. There is no email-pair flow as on Atlassian Cloud, and the adapter never asks for one.
| Environment variable | Purpose |
|---|---|
JIRA_DC_PAT | Personal Access Token used for every request. |
BERNSTEIN_CA_BUNDLE | Optional PEM bundle for self-signed Jira TLS. |
trackers:
jira_data_center:
base_url: https://jira.acme.internal
auth:
pat_env: JIRA_DC_PAT
project_key: ENG
The PAT environment variable name is configurable via pat_env so operators can run multiple instances side by side.
TLS¶
BERNSTEIN_CA_BUNDLE overrides verify_tls when set, so operators can ship a fleet-wide CA bundle without rebuilding the wheel.
Set verify_tls: false in bernstein.yaml only for short-lived test deployments. Production deployments should pin the bundle.
Pulling tickets¶
pull_open_tickets runs a paginated JQL search. Pass an override in the filter dict, or rely on the configured default_jql:
from bernstein.core.trackers.builtin import (
JiraDataCenterAdapter,
JiraDataCenterConfig,
)
config = JiraDataCenterConfig(
base_url="https://jira.acme.internal",
project_key="ENG",
cli_choice_field_id="customfield_10100",
)
with JiraDataCenterAdapter(config) as adapter:
for ticket in adapter.pull_open_tickets({"status": "Ready"}):
cli = ticket.routing_hint.cli # "claude" / "codex" / "aider" / None
# hand ticket.id (issue key) to the orchestrator's routing layer
The filter accepts:
| Key | Meaning |
|---|---|
jql | Raw JQL override; takes precedence over the other keys. |
project | Project key override for this call. |
status | Shorthand that becomes status = "<value>" when no jql set. |
Status mapping¶
status_map maps canonical Bernstein status names to Jira transition names so callers do not need to know the workflow numeric ids:
transition(ticket_id, status_id) resolves status_id in this order:
- Treat it as a transition id (opaque).
- Look it up in
status_map. - Match it against
transition.nameortransition.to.namefrom the issue's available transitions list.
Per-step CLI choice¶
Configure cli_choice_field_id with a Jira custom-field id (for example customfield_10100) and expose it as a single-select field with values claude, codex, aider. The adapter surfaces the value as ticket.routing_hint.cli so the orchestrator's routing layer can pin a CLI per ticket.
Comments and transitions¶
add_comment(ticket_id, body)posts to/rest/api/2/issue/<key>/comment. The optionalidempotency_keyis passed back as theX-Bernstein-Idempotency-Keyheader so operators auditing webhook traffic can reconcile retries.transition(ticket_id, status_id)GETs the available transitions, resolves the target id, then POSTs to/rest/api/2/issue/<key>/transitions.
Rate limiting¶
- A cooperative per-adapter token-bucket throttles outbound calls when
rate_limit_min_intervalis set. - Server-side
429(and503carryingRetry-After) is translated intoRateLimited(retry_after=...).
Exceptions¶
| Exception | When |
|---|---|
TrackerUnavailable | 5xx, missing PAT, unknown transition, malformed JSON. |
RateLimited | 429, or 503 with Retry-After. |
OptimisticConcurrencyError | 412 Precondition Failed on a write. |
Out of scope¶
- Jira Server (end of life) is not a supported deployment target.
- Cloud-to-Data-Center migration helpers.
- A bundled Jira plugin: the adapter runs alongside Jira, not inside it.