What the agent does
An ASP.NET Core exception in Sentry has the exception type, the message, the HTTP route and a .NET stack trace whose in-app frames name a controller action, a command or a service method. The agent reads the alert payload after the prompt, fetches the issue and its latest event through the Sentry connection and keeps the frames, the route and the tags such as release and environment. Then it opens its clone and reads the project those frames belong to.
In an ASP.NET Core solution like bitwarden/server that is the first decision, because bitwarden-server.slnx holds many projects: src/Api, src/Identity, src/Core, src/Admin, src/Billing, src/Events, src/Notifications and the libraries under src/Libraries. global.json pins the SDK to 10.0.103 with rollForward set to latestFeature, and Directory.Build.props targets net10.0, turns TreatWarningsAsErrors on, enables nullable references and restores with a lock file. A frame in Bit.Api.Vault.Controllers.CiphersController points at src/Api/Vault/Controllers/CiphersController.cs, whose actions Get, GetDetails, GetAll, Post, PostCreate, Put, PutPartial, PutShare, PutCollections and GetOrganizationCiphers call ICipherService in src/Core/Vault/Services/Implementations/CipherService.cs and ICipherRepository. A frame in Bit.Identity points at src/Identity/Controllers/AccountsController.cs, with PostRegisterSendVerificationEmail, PostRegisterFinish, PostPrelogin and the WebAuthn assertion endpoints, or at the request validators under src/Identity/IdentityServer/RequestValidators. Exceptions the API means to return as 400, 404 or 409 are BadRequestException, NotFoundException and ConflictException from src/Libraries/ExceptionHandling; anything else reaching Sentry is a real 500.
The test goes in the matching test project. test/Api.Test/Vault/Controllers/CiphersControllerTests.cs uses [Theory, BitAutoData] with SutProvider<CiphersController> from test/Common, stubbing GetDependency<ICipherRepository>().GetByIdAsync(...) with NSubstitute, and test/Identity.Test/Auth/Controllers/AccountsControllerTests.cs does the same for Identity. Directory.Build.props sets xunit 2.6.6, NSubstitute 5.1.0 and AutoFixture.Xunit2 4.18.1 for every test project. The agent writes one test that stubs the dependencies to return what the Sentry breadcrumbs show, such as a cipher with a null Data field or a user with no master password, calls the action and asserts the exception or the response it should give. It runs dotnet test test/Api.Test --filter <Name> and keeps the failure as the reproduction.
Then it fixes the action or the service, reruns the test until it passes, and runs dotnet test test/Api.Test or test/Identity.Test in full, then dotnet build on the solution so a warning turned error elsewhere is caught. The test.yml workflow runs dotnet test ./test --configuration Debug across every project plus the bitwarden_license/test tree, which is long; the agent runs the affected projects and says in the pull request which it ran. It does not downgrade a thrown exception to a BadRequestException just to clear the alert when the real cause is a null the service should have handled.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "A Sentry alert fired for this ASP.NET Core app; its payload follows this prompt. Use the Sentry connection to read the issue, its latest event, the route, breadcrumbs and the in-app stack frames. Find the project and the action the frames name, starting with the vault controllers under src/Api/Vault/Controllers and the identity controllers and request validators under src/Identity. Add an xUnit test to the matching test project, using [Theory, BitAutoData] and SutProvider with NSubstitute stubs as the neighbouring tests do, that reproduces the exception. Fix the code until the test passes, run `dotnet test` for that test project and `dotnet build` for the solution with warnings as errors. Open a pull request that links the Sentry issue, quotes the frames and the failing test output, and explains the cause. Change nothing unrelated to this error.\n\nAlert payload:\n{payload}",
"resources": [
{
"url": "https://github.com/your-org/your-app"
}
],
"connections": [
"sentry"
]
}- 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.
- 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.
- 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
The result is a pull request that changes one controller, service or validator and adds one [Theory, BitAutoData] test to the project that already tests it. The description links the Sentry issue, quotes the exception and the frames, shows the test failing before and passing after, and lists the dotnet test projects it ran with their summaries. Your own workflows run on the branch as they would on any pull request.
The session's transcript keeps every Sentry read, every dotnet command with its full output and every file opened, so a reviewer can check which test projects ran rather than take the description's word. The run.completed webhook carries the final message as data.result and a session_url for the rest.
Before merging, a reviewer checks that the stubs match the state the event showed, that a fix which now throws NotFoundException or BadRequestException is the honest status for that case, and that a change in CipherService keeps the organization and collection permission checks around it. A follow-up message to the same session asks for a different approach and the branch is amended.
Run it on every Sentry issue alert
Create an alert rule in the Sentry project with a webhook action and point it at a handler on your server. The handler sends this request with the alert's JSON after the prompt and the issue id as Idempotency-Key, so Sentry's retries return the run already started rather than a second one. Each issue gets one run and one pull request.
Set a webhook URL on the API key and Rush POSTs run.completed to it with session_url when the turn finishes; the handler can comment the pull request link on the issue. Or have that handler call a webhook trigger on an automation in the Project with this prompt: it forwards the alert's JSON as the body with the trigger's secret as Authorization: Bearer, because Sentry signs its own webhooks and cannot send that header. The body becomes the event text after the prompt, and max_runs_per_hour caps an issue that keeps firing.
The use case this job follows, with its automation and trigger: Fix a bug from an alert.
Why run it on Rush?
A large .NET solution punishes a quick local fix: the restore, the build with warnings as errors, and a test tree that takes long to run in full. The agent does that in a sandbox with the pinned SDK, runs the one test first and the affected projects last, and keeps the output, so the reviewer opens a pull request whose claims are already backed by a transcript.
Each Sentry issue is its own run in its own clone, in parallel up to the key's max_concurrent limit, so an exception in the vault API and another in registration are handled at the same time without two engineers switching branches. What comes back is small enough to review in minutes and carries its own failing-then-passing test.
Frequently asked questions
Which .NET SDK does the sandbox use?
The one global.json pins, 10.0.103 with rollForward set to latestFeature, which is what actions/setup-dotnet resolves in the test.yml workflow. The agent reads that file first and does not build with a different major version.
Does it run every test project in the solution?
No. It runs the test project that owns the changed code, test/Api.Test or test/Identity.Test for a controller, and builds the solution. The workflow's full dotnet test ./test plus the bitwarden_license/test tree runs in your CI on the pull request, and the description says what was run in the sandbox.
Does the test need SQL Server or the integration factories?
Not for a controller or service exception. The unit tests stub repositories with NSubstitute through SutProvider, so they run in process. test/Api.IntegrationTest uses ApiApplicationFactory with an in-process Identity; the agent runs it only when the fix spans the request pipeline and the prompt allows it.
What if the exception is already a BadRequestException?
Then it is a 400 the API intends, and it should not have reached Sentry as an error. The agent says so in its final message, points at the filter in src/Libraries/ExceptionHandling that maps it, and opens no pull request unless the mapping is what is broken.