Runbook: JIRA integration¶
Goal¶
A user can drive vibey entirely from Jira, and vibey can drive Jira back. Both directions, fully comprehensive:
- Inbound (Jira → vibey): a new ticket in a watched project becomes a vibey project (INTAKE); a comment on a linked ticket answers a parked human gate; a status transition (e.g. "Approved") accepts a design or opts into deployment; an attachment becomes DESIGN input.
- Outbound (vibey → Jira): vibey creates the ticket hierarchy (epic per
project, story per work item), comments progress (phase transitions,
verify results, spend), transitions statuses as phases advance, posts
park prompts as comments with the exact
vibey answercontract, attaches artifacts (specs, demo output), and closes tickets on DONE.
Current state (verified)¶
- No Jira code exists anywhere in the repo.
- Human gates already un-park via
gates.answer+NOTIFY vibey_job_ready(infrastructure/db/human_gate_repository.py) — a Jira comment handler only has to call the same application service the CLIvibey answeruses. No queue changes needed. infrastructure/notify/publishers.pyalready fans events out to pluggable publishers — the outbound half slots in as one more publisher.
Design¶
application/interfaces/tracker.py:IssueTrackerPortProtocol — vendor-neutral (create_issue,comment,transition,attach,watch_events), so Linear/GitHub Issues can implement it later.infrastructure/jira/client.py: Jira Cloud REST v3 over httpx; auth via API token (email+token basic) first, OAuth 2.0 (3LO) as a follow-up.infrastructure/jira/inbound.py: two modes, both feeding the same translator —- Webhook mode (server deployments): FastAPI route registered with
Jira webhooks (
jira:issue_created,comment_created,jira:issue_updated). - Poll mode (MacBook, no public ingress): JQL poll
updated >= -2m ORDER BY updatedon a worker heartbeat. - Translator maps Jira events → existing application calls:
issue_created →
vibey newequivalent; comment matching an open gate id →gates.answer(comment body supports the--defaultsand--rawgrammars verbatim); transition names mapped per-project in config. infrastructure/jira/outbound.py: a ledger-event publisher that mirrors PhaseTransitioned / FindingRaised / park events into comments and transitions. Idempotent: every mirrored event carries the ledger event id in a hidden Jira entity property, so replays never double-comment.- State mapping stored in
project.config(jira_site,jira_project,jira_epic_id, transition map).
Work items (vibey decomposition seed)¶
IssueTrackerPortProtocol + in-memory fake + port-parity tests.- Jira REST client (fixture-tested at the HTTP boundary, respx).
- Outbound publisher: epic/story creation + progress comments + transitions + attachments, idempotent via entity properties.
- Inbound poll mode: JQL watcher job (
tracker.polljob kind, serial). - Inbound comment → gate answer (full
--defaults/--rawgrammar). - Webhook mode: FastAPI ingress (server mode only) + HMAC verification.
- CLI:
vibey jira link <project> --site --jira-project,vibey jira status. tests/live/test_jira_live.py: against a free Jira Cloud site, gated onVIBEY_JIRA_LIVE=1+ credentials.
Verification¶
- Fixture suites green across all layers (100% branch).
- Live: create ticket on the free site → vibey project appears → park a gate → answer it from a Jira comment → phase transition mirrored back to the ticket, all with zero CLI interaction.
Needs from operator¶
Jira Cloud free site, an API token, and one watched project key.
Risks¶
- Jira rate limits (poll mode: back off on 429, jitter).
- Comment-grammar injection: answers only accepted from configured accounts; everything else is recorded but ignored.
- Transition maps differ per Jira workflow — config, never hardcoded.