jira

The jira extension bidirectionally syncs Jira issues with the Thurbox task list : your issues show up as tasks, and marking a task done moves the issue to a Done-category status. A jira-tick automation (every 15 min, cron:*/15 * * * * ) runs a deterministic Exec command — {home}/scripts/sync.sh — that reconciles the JQL filters in trackers.md with the task list. There is no agent, no LLM, no tokens : Thurbox's scheduler runs the script (TUI or headless heartbeat) and records its output in the automation run history. The script only calls thurbox-cli and talks to Jira Cloud's REST API v3 over curl ; no Jira app, no webhook.

Experimental. jira is new and under active testing — its sync scripts and manifest may change between releases.

Overview #

Pull is the default direction: Jira issues become Thurbox tasks. Jira is authoritative for an issue's title, URL, and open-vs-done state ; your local todoin_progress distinction is preserved. Status maps by statusCategory : newtodo , indeterminatein_progress , donedone . Imported tasks carry source=jira and external_id="<issue key>" (e.g. ENG-7 ), so re-syncing never duplicates them — dedup is by (source, external_id) .

Descriptions are not synced. Jira v3 descriptions are ADF (rich JSON); converting them to text is out of scope, so tasks carry title + URL only .

Requirements #

  • thurbox-cli ≥ 0.141 on PATH — the sync uses the task --source/--external-id/--external-url flags added there (check with thurbox-cli version ).
  • curl and jq on PATH .

Get a Jira API token #

Create a token at id.atlassian.com . Because the sync runs headless (via the automation, with no shell session to inherit your environment), hand it the three values via a credentials.env file in the install home — sync.sh sources it before running:

$ mkdir -p ~/.config/thurbox/extensions/jira
$ cat > ~/.config/thurbox/extensions/jira/credentials.env <<'EOF'
JIRA_BASE_URL=https://your-domain.atlassian.net
JIRA_EMAIL=you@example.com
JIRA_API_TOKEN=your-atlassian-api-token
EOF
$ chmod 600 ~/.config/thurbox/extensions/jira/credentials.env

(Exporting the three vars from your shell profile is an alternative, but it only reaches the headless run if the scheduler inherits your profile — so credentials.env is recommended.) Auth is HTTP Basic ( -u "$JIRA_EMAIL:$JIRA_API_TOKEN" ). Confirm the credentials:

$ curl -fsSL -u "$JIRA_EMAIL:$JIRA_API_TOKEN" "$JIRA_BASE_URL/rest/api/3/myself"

Install #

jira is a Thurbox extension (a declarative extension.toml manifest):

$ thurbox-cli extension install jira       # or ./extensions/jira
$ thurbox-cli extension uninstall jira     # --purge also deletes ~/.config/thurbox/extensions/jira

Installing lays down the ~/.config/thurbox/extensions/jira/ home (override with --home ; it holds scripts/sync.sh + helpers and the seeded trackers.md ) and activates the jira-tick automation — self-healed by Thurbox if deleted.

Configure trackers.md #

Edit ~/.config/thurbox/extensions/jira/trackers.md — one row per filter. The query is a JQL string: the whole cell is one JQL value (it contains spaces and is not word-split), e.g. project = ENG AND statusCategory != Done . Keep push_back = no for the first run.

| name   | query                                               | push_back |
|--------|-----------------------------------------------------|-----------|
| mine   | assignee = currentUser() AND statusCategory != Done | no        |
| triage | project = WEB AND labels = needs-triage             | no        |

First sync & verify #

The automation fires every 15 min. To run it now, trigger it from the Automations pane ( Ctrl+P → select jira-tickr ) or headless:

$ thurbox-cli automation run <id>     # id from: thurbox-cli automation list
$ ~/.config/thurbox/extensions/jira/scripts/sync.sh     # or run the script directly

Then inspect the imported tasks:

$ thurbox-cli task list --json | jq -c '.[] | select(.source=="jira") | {id,status,external_id,title}'

Status maps by statusCategory ( newtodo , indeterminatein_progress , donedone ). Re-running is idempotent — dedup by (source, external_id) leaves unchanged issues alone, and the source=jira tag keeps these tasks distinct from any other tracker's. The run's output (created/updated/unchanged counts) shows in the automation run history.

Two-way sync #

Once the pull looks right, set push_back = yes on a tracker row. Now marking an imported task done transitions its Jira issue into the Done category, and moving it back to todo reopens it — only the open↔done axis is pushed. The sync runs push-then-pull ( push-status.sh then per-tracker fetch.sh | upsert.sh ), so your local change reaches Jira before the pull reads state back. Push uses the workflow's transitions : to close, the first transition landing in the Done category; to reopen, the first non-Done (preferring new ) transition. If the workflow lacks a suitable transition the issue is surfaced in the run output and skipped, not failed.

All-or-nothing push-back. A Jira issue key can't be tied back to the specific JQL row that returned it, so push-back is all-or-nothing — if any row is yes , push acts on all source=jira tasks.

Files #

See extensions/jira for the extension.toml manifest, the seeded trackers.md , the README.md , and the sync scripts ( scripts/sync.sh , scripts/fetch.sh , scripts/upsert.sh , scripts/push-status.sh ).