# Fix Jira Bug Tickets With Pull Requests in an ASP.NET Core App

Yes. An agent reads the Jira bug, reproduces it with a test in your ASP.NET Core services, fixes it, opens a pull request and links it on the ticket.

[Run this on Rush](https://cloud.getrush.ai/run/fix-jira-bugs/aspnet-core/), in a Project that has your repository.

## What the agent does

The run starts when someone files a bug. A Jira automation rule posts the new work item's key and summary to a handler on your server, which sends the request on this page with them appended to the prompt. The agent clones the repository into its own cloud sandbox and, through your Atlassian connection, reads the full ticket: description, steps to reproduce, environment, attachments listed on it and every comment. The summary in the webhook is a starting point; the comments are often where the real repro lives.

Then it finds the code. In a solution like dotnet/eShop the services sit side by side under `src/`, so a ticket about orders or the basket narrows to two projects. `Ordering.API` maps its minimal API under `api/orders` in `Apis/OrdersApi.cs`: `PUT /cancel` and `PUT /ship` take an `x-requestid` header and return `BadRequest` for an empty GUID, and a cancel the mediator refuses becomes a `Problem` with status 500 and "Cancel order failed to process." `Basket.API` is gRPC, defined in `Proto/basket.proto` (`GetBasket`, `UpdateBasket`, `DeleteBasket`) and implemented in `Grpc/BasketService.cs`, which throws `RpcException` with `Unauthenticated` or `NotFound`. The agent matches the ticket's symptom to one of these paths before changing anything.

It reproduces the bug as a failing test in the framework that project already uses, because eShop uses two. `Basket.UnitTests` and `Ordering.UnitTests` are `MSTest.Sdk` projects with NSubstitute (`BasketServiceTests` substitutes `IBasketRepository` and calls the service with a `TestServerCallContext`). `Ordering.FunctionalTests` and `Basket.FunctionalTests` are xUnit v3 (`xunit.v3.mtp-v2`) on the Aspire app host SDK: `OrderingApiFixture` starts Postgres through `AddPostgres("OrderingDB")` and `RedisFixture` starts Redis, which need Docker. The agent writes the narrowest test that shows the bug, a unit test when the logic is in a handler or the gRPC service and a functional `[Fact]` when the bug only shows over HTTP.

Once the test fails for the reason in the ticket, it fixes the code, builds with `dotnet build eShop.Web.slnf` and runs `dotnet test` (the repository's `global.json` pins SDK `10.0.302` and selects Microsoft.Testing.Platform as the runner). It opens a pull request whose title and branch carry the ticket key, so Jira's development panel links them, and adds a comment on the ticket through the Atlassian connection with the pull request link and one line on the cause.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "codex",
  "input": "A Jira bug ticket was created; its key and summary follow this prompt. Use the Atlassian connection to read the ticket, its description and all comments. Find the code in the ordering and basket services (src/Ordering.API/Apis/OrdersApi.cs, the Ordering.API command handlers, src/Basket.API/Grpc/BasketService.cs). Reproduce the bug with a failing test in the framework that project already uses: MSTest with NSubstitute in Ordering.UnitTests or Basket.UnitTests, or an xUnit [Fact] in Ordering.FunctionalTests or Basket.FunctionalTests when it only shows over HTTP. Fix the code, run dotnet build eShop.Web.slnf and dotnet test until they pass, and say which tests could not run in the sandbox and why. Open a pull request with the ticket key in its title and branch name, then add a comment on the ticket with the pull request link and the cause in one sentence. If you cannot reproduce it, comment on the ticket with what you tried and open no pull request.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is a pull request named after the ticket, such as `<KEY>: return 404 when cancelling an order that does not exist`. In eShop it usually changes one file under `src/Ordering.API` or `src/Basket.API` and adds one test to the matching test project. The description restates the ticket in a sentence, explains the cause with the file and method, shows the test that failed before the change, and lists the `dotnet test` result per project.

On the Jira side the ticket gets one comment with the pull request link, so whoever filed it sees progress without leaving Jira. The pull request's checks run your own workflow; in eShop `pr-validation.yml` builds `eShop.Web.slnf` and runs `dotnet test --solution eShop.Web.slnf`, which includes the Aspire functional tests on GitHub's runners. The session's transcript keeps every command and its output, from the first failing test to the last passing run.

Before merging, a reviewer checks that the new test fails on `main` and passes on the branch, that the fix is in the service that owns the behaviour rather than a guard in the caller, and that the HTTP status or gRPC `StatusCode` it now returns is what the ticket's reporter expected. When the agent could not reproduce the bug, there is no pull request: the ticket's comment says what it tried.

## Run it on every new Jira bug

In Jira, create an automation rule with the trigger "Work item created", a condition on the issue type Bug (or a label such as `agent-fix`), and the action "Send web request" to your handler with `{{issue.key}}` and `{{issue.summary}}` in the body. The handler appends them to `input` and sends one request per ticket, naming your Atlassian connection in `connections` so the agent can read and comment on the ticket.

Set a webhook URL on the API key and Rush POSTs `run.completed` or `run.failed` with the `session_url` when the turn finishes. A key runs at most `max_concurrent` sessions at once (4 by default) and answers `429` past that, so a bug bash that files twenty tickets should queue in the handler.

## Why run it on Rush?

Reproducing a bug in a solution with nine test projects, an Aspire app host and containers for Postgres and Redis is exactly the setup a developer does not want to rebuild for each ticket. In a Rush sandbox the agent installs the .NET SDK from `global.json`, restores the solution and runs the tests on its own machine, so nobody's local Docker or SDK is touched and each ticket starts from a clean checkout.

The proof is the test and its history. The transcript shows the failing test before the fix and the passing run after, the pull request's checks repeat it on GitHub, and the Jira comment ties the two together. Several tickets filed in the same hour each get their own sandbox and their own pull request instead of waiting in one person's queue.

## Frequently asked questions

### Can I put the Jira ticket URL in resources?

No. `resources` takes a GitHub repository or a Linear issue; any other URL is `422 RESOURCE_UNSUPPORTED`. For Jira, put the key in the prompt and name your Atlassian connection in `connections`, and the agent reads the ticket through it.

### eShop has both MSTest and xUnit. Which does the test use?

Whichever the project it lands in already uses. The unit test projects are `MSTest.Sdk` with NSubstitute and the functional test projects are xUnit v3 on Aspire. The agent does not add a third framework or move tests between them.

### What about functional tests that need Postgres and Redis?

`OrderingApiFixture` and `RedisFixture` start them through Aspire, which needs a container runtime. The agent reports whether those tests ran in its sandbox or were skipped, and your pull request workflow runs them on GitHub's runners either way.

### What if the ticket is too vague to reproduce?

The prompt tells the agent to comment on the ticket with what it tried and open no pull request. The reporter can add steps in a comment, and a follow-up message on the same session (or a new run) picks them up.
