Add Jira and Azure DevOps issue backends (#81, #82) - #83
Merged
Conversation
Adds a first-class `jira` issue source alongside `file` and `github`, implementing the same uniform 9-verb backend contract (list, get, update, comment, close, create, claim, release, any-claimable) against the Jira REST API v2. - issues-jira.sh: self-contained backend. Maps Jira issues (PROJ-N) to the gh-compatible JSON shape, exposing the numeric key suffix as `number` so it stays compatible with the swarm manifest and the rest of the workflow. Uses API v2 for plain-text descriptions. Non-secret connection settings (baseUrl, project) come from the `jira` object in .autocoder.json; credentials are env-only (JIRA_EMAIL + JIRA_API_TOKEN, or JIRA_AUTH_HEADER for Server/DC PATs) and never committed. - Claimable/open JQL ORs in `labels is EMPTY` so label-less issues are not silently dropped — the Jira analogue of the GitHub `no:label` bug (#57). - Registers `jira` in both dispatchers (plugins + .agent mirror), issue-source-lib.sh validation, and the set-issue-source command. - test_issues_jira.sh: 35 assertions covering JQL, request shaping, output schema, and exit codes, with curl fully stubbed (no network). - Updates CLAUDE.md/GEMINI.md, launcher help strings, and bumps autocoder 4.5.2 -> 4.6.0 and the marketplace 3.26.0 -> 3.27.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zJKDkbj54vZeGaTWLJEHv
The unit test (test_issues_jira.sh) stubs curl and asserts request/JQL shape; this adds real end-to-end coverage without any network: - tests/fixtures/fake_jira.py: a small stdlib-only STATEFUL fake of the Jira REST API v2 covering exactly the endpoints issues-jira.sh calls (search, issue CRUD, comment, transitions, assignee, myself). It keeps issues in memory and evaluates the JQL the backend emits, so state filters and the lifecycle behave like real Jira. Binds an ephemeral loopback port (printed as "LISTENING <port>") so CI runs never collide. - tests/test_issues_jira_integration.sh: starts the fake, exercises the full lifecycle (create → get → claim/release → comment → update → close) over real HTTP and asserts every state filter — including the label-less "labels is EMPTY" guard a stateless mock cannot exercise — then tears the server down. Skips cleanly if curl/python3 are absent. 17 assertions. - plugins/autocoder/scripts/jira-smoke-test.sh: opt-in check against a REAL Jira instance (JIRA_* env). Kept out of tests/ so CI never needs egress. - CLAUDE.md: document the three test layers. Full shell suite green (15/15); server teardown leaves no stray process. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zJKDkbj54vZeGaTWLJEHv
Walks through creating a free Jira Cloud site, project, and API token; wiring the non-secret baseUrl/project into .autocoder.json while keeping credentials in the environment; verifying with jira-smoke-test.sh; and the two hermetic CI tests. No secrets in the doc. Linked from CLAUDE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zJKDkbj54vZeGaTWLJEHv
Adds a first-class `ado` issue source implementing the same uniform 9-verb backend contract against the Azure DevOps Work Item Tracking REST API. - issues-ado.sh: self-contained backend. Work item IDs are integers, so `number` maps to System.Id directly. Labels ↔ work-item Tags (System.Tags), state ↔ System.State (done-state set covers the default Agile/Basic/Scrum/CMMI processes). Uses WIQL for list/any-claimable, workitemsbatch for details, and json-patch for create/update. Non-secret orgUrl/project come from the `ado` object in .autocoder.json; the PAT is env-only (ADO_PAT) and never committed. Overridable work-item type and open/closed state names via env. - WIQL `[System.Tags] NOT CONTAINS 'x'` already matches tag-less items, so untagged work stays claimable without a special empty clause (the ADO analogue of the GitHub no:label / Jira empty-labels traps) — asserted by both tests. - Registers `ado` in both dispatchers (plugins + .agent mirror), issue-source-lib validation, the set-issue-source command, and launcher help strings. - Tests (both hermetic, in CI): test_issues_ado.sh (28 assertions, stubs curl; WIQL + json-patch shape, schema, exit codes) and test_issues_ado_integration.sh (18 assertions; real HTTP against a stateful fake, tests/fixtures/fake_ado.py, full lifecycle + WIQL filtering). - Docs: docs/ado-setup.md; updates CLAUDE.md/GEMINI.md. Bumps autocoder 4.6.0 -> 4.7.0 and the marketplace 3.27.0 -> 3.28.0. Full shell suite green (17/17). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zJKDkbj54vZeGaTWLJEHv
- docs/issue-backends.md: unified overview of the four built-in backends — the 9-verb contract, uniform JSON shape and exit codes, per-backend model mapping, secrets handling, configuration precedence, and the hermetic test layers. Links to the Jira and ADO setup guides. - README: refresh the "Issue Backends" section — full 9-verb contract table (adds claim/release/any-claimable), point at the new docs, and use a genuinely custom name (linear) for the custom-backend example now that jira/ado are first-class. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zJKDkbj54vZeGaTWLJEHv
laird
added a commit
that referenced
this pull request
Jul 29, 2026
Two gaps found by a dry-run of the full merge chain. 1. issue-source-lib.sh existed only under plugins/autocoder/scripts/. It is issue-source resolution used by the swarm launch/lifecycle scripts — shared issue-layer infrastructure, not platform-specific — so the mirror was incomplete. Copied verbatim. 2. The parity guard's SHARED list covered only the two original backends (file, gh). issues-jira.sh and issues-ado.sh arrived with #83 and were never checked, and neither was issue-source-lib.sh. A backend that ships only under plugins/ is invisible to the guard — which is exactly how the drift in #71 went unnoticed: the mirror looked healthy because nothing checked the files missing from it. SHARED now lists the whole issue layer (7 files). Verification: parity guard 19/19, up from 13/13. Negative-tested both new assertion classes — removing issue-source-lib.sh from the mirror fails 2 assertions, and perturbing issues-jira.sh fails the divergence check — so the added coverage is not vacuous. 18/18 suites pass, build clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4 tasks
laird
added a commit
that referenced
this pull request
Aug 8, 2026
…er (jira/ado) (#87) * Add Jira issue backend parallel with GitHub (#81) Adds a first-class `jira` issue source alongside `file` and `github`, implementing the same uniform 9-verb backend contract (list, get, update, comment, close, create, claim, release, any-claimable) against the Jira REST API v2. - issues-jira.sh: self-contained backend. Maps Jira issues (PROJ-N) to the gh-compatible JSON shape, exposing the numeric key suffix as `number` so it stays compatible with the swarm manifest and the rest of the workflow. Uses API v2 for plain-text descriptions. Non-secret connection settings (baseUrl, project) come from the `jira` object in .autocoder.json; credentials are env-only (JIRA_EMAIL + JIRA_API_TOKEN, or JIRA_AUTH_HEADER for Server/DC PATs) and never committed. - Claimable/open JQL ORs in `labels is EMPTY` so label-less issues are not silently dropped — the Jira analogue of the GitHub `no:label` bug (#57). - Registers `jira` in both dispatchers (plugins + .agent mirror), issue-source-lib.sh validation, and the set-issue-source command. - test_issues_jira.sh: 35 assertions covering JQL, request shaping, output schema, and exit codes, with curl fully stubbed (no network). - Updates CLAUDE.md/GEMINI.md, launcher help strings, and bumps autocoder 4.5.2 -> 4.6.0 and the marketplace 3.26.0 -> 3.27.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zJKDkbj54vZeGaTWLJEHv * Add hermetic Jira integration test with a stateful fake server The unit test (test_issues_jira.sh) stubs curl and asserts request/JQL shape; this adds real end-to-end coverage without any network: - tests/fixtures/fake_jira.py: a small stdlib-only STATEFUL fake of the Jira REST API v2 covering exactly the endpoints issues-jira.sh calls (search, issue CRUD, comment, transitions, assignee, myself). It keeps issues in memory and evaluates the JQL the backend emits, so state filters and the lifecycle behave like real Jira. Binds an ephemeral loopback port (printed as "LISTENING <port>") so CI runs never collide. - tests/test_issues_jira_integration.sh: starts the fake, exercises the full lifecycle (create → get → claim/release → comment → update → close) over real HTTP and asserts every state filter — including the label-less "labels is EMPTY" guard a stateless mock cannot exercise — then tears the server down. Skips cleanly if curl/python3 are absent. 17 assertions. - plugins/autocoder/scripts/jira-smoke-test.sh: opt-in check against a REAL Jira instance (JIRA_* env). Kept out of tests/ so CI never needs egress. - CLAUDE.md: document the three test layers. Full shell suite green (15/15); server teardown leaves no stray process. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zJKDkbj54vZeGaTWLJEHv * Add docs/jira-setup.md — Jira backend setup & testing guide Walks through creating a free Jira Cloud site, project, and API token; wiring the non-secret baseUrl/project into .autocoder.json while keeping credentials in the environment; verifying with jira-smoke-test.sh; and the two hermetic CI tests. No secrets in the doc. Linked from CLAUDE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zJKDkbj54vZeGaTWLJEHv * Add Azure DevOps issue backend parallel with GitHub/Jira (#82) Adds a first-class `ado` issue source implementing the same uniform 9-verb backend contract against the Azure DevOps Work Item Tracking REST API. - issues-ado.sh: self-contained backend. Work item IDs are integers, so `number` maps to System.Id directly. Labels ↔ work-item Tags (System.Tags), state ↔ System.State (done-state set covers the default Agile/Basic/Scrum/CMMI processes). Uses WIQL for list/any-claimable, workitemsbatch for details, and json-patch for create/update. Non-secret orgUrl/project come from the `ado` object in .autocoder.json; the PAT is env-only (ADO_PAT) and never committed. Overridable work-item type and open/closed state names via env. - WIQL `[System.Tags] NOT CONTAINS 'x'` already matches tag-less items, so untagged work stays claimable without a special empty clause (the ADO analogue of the GitHub no:label / Jira empty-labels traps) — asserted by both tests. - Registers `ado` in both dispatchers (plugins + .agent mirror), issue-source-lib validation, the set-issue-source command, and launcher help strings. - Tests (both hermetic, in CI): test_issues_ado.sh (28 assertions, stubs curl; WIQL + json-patch shape, schema, exit codes) and test_issues_ado_integration.sh (18 assertions; real HTTP against a stateful fake, tests/fixtures/fake_ado.py, full lifecycle + WIQL filtering). - Docs: docs/ado-setup.md; updates CLAUDE.md/GEMINI.md. Bumps autocoder 4.6.0 -> 4.7.0 and the marketplace 3.27.0 -> 3.28.0. Full shell suite green (17/17). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zJKDkbj54vZeGaTWLJEHv * Document all issue backends (file, GitHub, Jira, Azure DevOps) - docs/issue-backends.md: unified overview of the four built-in backends — the 9-verb contract, uniform JSON shape and exit codes, per-backend model mapping, secrets handling, configuration precedence, and the hermetic test layers. Links to the Jira and ADO setup guides. - README: refresh the "Issue Backends" section — full 9-verb contract table (adds claim/release/any-claimable), point at the new docs, and use a genuinely custom name (linear) for the custom-backend example now that jira/ado are first-class. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zJKDkbj54vZeGaTWLJEHv * Complete the .agent issue-layer mirror and widen the parity guard (#71) Two gaps found by a dry-run of the full merge chain. 1. issue-source-lib.sh existed only under plugins/autocoder/scripts/. It is issue-source resolution used by the swarm launch/lifecycle scripts — shared issue-layer infrastructure, not platform-specific — so the mirror was incomplete. Copied verbatim. 2. The parity guard's SHARED list covered only the two original backends (file, gh). issues-jira.sh and issues-ado.sh arrived with #83 and were never checked, and neither was issue-source-lib.sh. A backend that ships only under plugins/ is invisible to the guard — which is exactly how the drift in #71 went unnoticed: the mirror looked healthy because nothing checked the files missing from it. SHARED now lists the whole issue layer (7 files). Verification: parity guard 19/19, up from 13/13. Negative-tested both new assertion classes — removing issue-source-lib.sh from the mirror fails 2 assertions, and perturbing issues-jira.sh fails the divergence check — so the added coverage is not vacuous. 18/18 suites pass, build clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds two first-class issue backends alongside
fileandgithub, each implementing the same uniform 9-verb contract (list/get/update/comment/close/create/claim/release/any-claimable) with the same gh-shaped JSON output and exit codes, so the rest of the workflow never branches on which tracker is in use.Closes #81
Closes #82
Jira (
jira)plugins/autocoder/scripts/issues-jira.sh— REST API v2. KeysPROJ-Nmap to the numeric suffix asnumber; labels ↔ Jira labels; state viastatusCategory+ transitions. Non-secretbaseUrl/projectfrom ajiraobject in.autocoder.json; credentials env-only (JIRA_EMAIL+JIRA_API_TOKEN, orJIRA_AUTH_HEADERfor Server/DC).labels is EMPTYso unlabeled issues aren't dropped — the Jira analogue of the GitHubno:labelbug (issues-gh.sh list uses invalidno:labelsearch syntax — autonomous loop sees zero issues #57).Azure DevOps (
ado)plugins/autocoder/scripts/issues-ado.sh— Work Item Tracking REST API. Work-item IDs are integers, sonumber=System.Id; labels ↔ Tags (System.Tags); state viaSystem.State(done-state set covers the default Agile/Basic/Scrum/CMMI processes). WIQL forlist/any-claimable,workitemsbatchfor details, JSON-patch for create/update. Non-secretorgUrl/projectfrom anadoobject; PAT env-only (ADO_PAT); type/state names env-overridable.[System.Tags] NOT CONTAINS 'x'already matches tag-less items, so untagged work stays claimable with no special clause.Wiring
plugins/dispatcher and the.agent/mirror,issue-source-lib.shvalidation,/set-issue-source(both platforms), and launcher help strings..autocoder.jsonor committed — only non-secret connection settings live there.Tests — hermetic, green in CI (no network)
test_issues_jira.sh(35)test_issues_jira_integration.sh(17) +fixtures/fake_jira.pytest_issues_ado.sh(28)test_issues_ado_integration.sh(18) +fixtures/fake_ado.pyThe integration fakes maintain state and evaluate the query language (JQL / WIQL), so the full
create → get → claim/release → comment → update → closelifecycle and every state filter run over real HTTP. Both auto-run in the existing CIshelljob. Full shell suite: 17/17 green locally and in CI (run #135 on the head commit).For a check against a real Jira,
plugins/autocoder/scripts/jira-smoke-test.shruns the lifecycle withJIRA_*set (kept out of CI since it needs egress).Docs & versioning
docs/issue-backends.md(overview of all four backends),docs/jira-setup.md,docs/ado-setup.md; CLAUDE.md / GEMINI.md / README updated.4.5.2 → 4.7.0, marketplace3.26.0 → 3.28.0.Notes for review
Closed(Agile/CMMI); Basic/Scrum useDone— override withADO_CLOSED_STATE=Done(documented)..agent/issue layer has known pre-existing drift (.agent mirror issue layer is stale: workflows call issue_claim/issue_release/issue_any_claimable which do not exist #71); these changes add the ADO/Jira routing to it but do not attempt that larger sync.🤖 Generated with Claude Code
Generated by Claude Code