OpenHands / OpenHands/enterprise

Make repository selection optional for Jira and Jira DC resolvers

Open
#44 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Python
Stars
4
Forks
2
Avg merge
1d 22h
Merged PRs (30d)
101

Description

Summary

Both the Jira and Jira DC resolvers currently refuse to start a conversation unless they can infer and verify exactly one repository from the triggering issue/comment. This is stricter than necessary and blocks legitimate use cases:

  • Repo-less tasks (e.g., "translate this comment to German and post it back")
  • Multi-repo workflows (e.g., "compare the implementations in frontend-app and backend-api")
  • Ambiguous mentions that the agent could clarify at runtime using skills

The resolvers should instead allow zero, one, or multiple repos, and defer resolution to the agent when unclear — mirroring how the GitHub resolver already works (repo is provided by the webhook context) and how Slack allows a "No Repository" option.

Current Behavior

Jira (Cloud)
  • JiraFactory._select_single_repo() (enterprise/integrations/jira/jira_view.py:402-427) raises RepositoryNotFoundError if len(verified_repos) != 1.
  • Zero repos → "Could not determine which repository to use."
  • Multiple repos → "Multiple repositories found: …. Please specify exactly one."
  • The agent/conversation is never started.
Jira DC (Data Center)
  • JiraDcManager.is_job_requested() (enterprise/integrations/jira_dc/jira_dc_manager.py:487-524) returns False unless len(verified_repos) == 1.
  • Zero repos → posts "Could not access any of the mentioned repositories" (or "Could not determine which repository to use") and stops.
  • Multiple repos → posts "Multiple repositories found…" and stops.
  • JiraDcNewConversationView.create_or_update_conversation() (line 86) has a second guard that raises StartingConvoException('No repository selected…').

Both use infer_repo_from_message() (enterprise/integrations/utils.py:173) to extract candidate repos from free text.

Why This Is Too Restrictive

  1. Repo-less tasks are blocked. Example from a real C24 support bundle: user wants to "translate this comment" — no repo needed. Today: refused.

  2. The agent could resolve ambiguity at runtime. If two repos are mentioned, the agent could read the issue, ask a clarifying question in a Jira comment, or infer from context (linked PRs, previous comments). Today: hard refusal upfront.

  3. Contrast with other integrations:

    • GitHub/Bitbucket DC: repo comes from the webhook payload (inherently unambiguous).
    • Slack: offers an explicit "No Repository" button and starts the conversation in an empty workspace; the agent can clone repos later via skills.
    • Jira should be at least as flexible as Slack.
  4. The agent has the tools to handle this. Once started with credentials, the agent can:

    • Use the git-provider skill to search/verify/clone repos.
    • Post a Jira comment asking the user for clarification.
    • Proceed without a repo if the task doesn't require one.

    Refusing before the agent even runs discards these capabilities.

Related Issues

  • Linear APP-1068: "Jira missing repo information should be optional" — already identified for the regular Jira integration.
  • Trailing punctuation regex bug (not yet filed): infer_repo_from_message fails to match repos followed by ?/!/; due to a too-narrow right-boundary in direct_pattern (line 215). Example: "in repo BANKAPP/bank-android?" extracts nothing. This is a separate one-line fix but contributes to the perception that repo inference is fragile.

Proposed Solution

High-Level Behavior
  • ≥1 repo confidently inferred → clone it (or them, if multi-repo is supported) and start.
  • 0 repos → start the conversation in an empty workspace (or with an initialized git repo, mirroring Slack's "No Repository" path). Let the agent decide: read the issue, use skills to clone, or ask the user.
  • Ambiguous/multiple → start anyway; optionally post a clarifying comment, but don't block.
Code Changes Required
Both Integrations
  1. enterprise/integrations/utils.py — fix the trailing-punctuation regex bug:
    # Line 215: broaden right boundary to allow ?!; as delimiters
    r'(?=\s|$|}}|[\]\)\'",.:;!?`])'  # right boundary
    
    Strip any trailing . from the captured repo name (mirror the existing .git cleanup).
Jira (Cloud)
  1. enterprise/integrations/jira/jira_view.py:
    • _select_single_repo() (line 402): instead of raising on zero or multiple, log and return None (or the first verified repo, or all of them). Caller must handle None.
    • _infer_repository() (line 431): catch RepositoryNotFoundError and return None instead of propagating.
    • create_view() (line 464): allow view.selected_repo = None.
    • JiraNewConversationView.create_or_update_conversation() (line ~184): drop the if not self.selected_repo: raise StartingConvoException(…) guard.
    • _create_v1_conversation(): pass selected_repository=None when appropriate; ensure credentials are still injected even without a repo (this path already exists for Slack "No Repository").
Jira DC
  1. enterprise/integrations/jira_dc/jira_dc_manager.py:
    • is_job_requested() (line 487): change the zero/multiple logic from return False to return True (with optional clarifying comment for the user). Set jira_dc_view.selected_repo = None or verified_repos[0] as appropriate.
    • OR keep the current short-circuit but add a fallback: if zero verified, still return True and proceed with no repo.
  2. enterprise/integrations/jira_dc/jira_dc_view.py:
    • JiraDcNewConversationView.create_or_update_conversation() (line 86): drop the if not self.selected_repo: raise StartingConvoException('No repository selected…') guard.
    • _create_v1_conversation(): handle selected_repository=None gracefully.
Multi-Repo Support (Optional, Larger Lift)
  • AppConversationStartRequest currently takes a single selected_repository. True multi-repo cloning (passing a list, auto-cloning all) is a broader runtime change.
  • Pragmatic first step: auto-clone at most one unambiguous repo; let the agent clone additional repos via skills.

Benefits

  1. Unblocks legitimate use cases (repo-less tasks, multi-repo, agent-driven clarification).
  2. Parity with Slack's flexibility (no hard refusal for missing/ambiguous repo).
  3. Leverages the agent's capabilities (skills, clarifying questions, context inference) instead of discarding them.
  4. Simpler failure mode: if the agent truly needs a repo and none is available, it can post a Jira comment asking — a better UX than a pre-flight refusal.

Testing Strategy

  1. Repo-less task: Jira issue with "@openhands translate this comment to German" (no repo mention). Verify: conversation starts, agent responds (even if it says "I need more context").
  2. Trailing punctuation: "@openhands clone BANKAPP/bank-android?" (with ?). Verify: repo is extracted and cloned (once regex is fixed).
  3. Multiple repos: Issue mentions two repos. Verify: conversation starts (agent may ask which one, or clone both if multi-repo is supported).
  4. Zero matches, git provider connected: Verify: conversation starts in empty workspace; agent can use skills to search/clone.

Open Questions

  1. Multi-repo cloning: Do we want to support auto-cloning multiple inferred repos in the initial request, or defer that to agent-driven skill usage?
  2. UI/messaging: When starting with zero/multiple repos, should we always post an initial Jira comment to set expectations (e.g., "Starting without a pre-selected repo; I'll infer from context"), or only when truly ambiguous?
  3. Backward compat: Are there workflows that rely on the hard refusal as a safety check (e.g., "don't start unless a repo is explicit")? If so, could we make it a workspace/org setting?

Related Linear Issue: APP-1068
Affected Files:

  • enterprise/integrations/utils.py:173,215 (regex bug + shared inference)
  • enterprise/integrations/jira/jira_view.py:402,431,464,184 (regular Jira guards)
  • enterprise/integrations/jira_dc/jira_dc_manager.py:487 (Jira DC gate)
  • enterprise/integrations/jira_dc/jira_dc_view.py:86 (Jira DC guard)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with JiraFactory._select_single_repo() and _infer_repository() in enterprise/integrations/jira/jira_view.py, then trace JiraDcManager.is_job_requested() and the conversation guards in jira_dc_view.py. Compare the existing Slack “No Repository” path for credential and empty-workspace handling. Done means repo-less, ambiguous, and multi-repository Jira requests start conversations without the current hard refusal, with the listed testing scenarios covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.