# Turn Linear Issues Into Pull Requests for a Django App

Yes. Point a run at a Linear issue and your Django repository, and the agent implements it, runs manage.py test and opens a pull request that links the issue.

[Run this on Rush](https://cloud.getrush.ai/run/linear-issue-to-pr/django/), in a Project that has your repository.

## What the agent does

The run starts with the issue in front of the agent. A `resources` entry of the form `https://linear.app/<workspace>/issue/<ID>` puts the issue into the prompt, read through your Linear connection, and the repository entry beside it clones the code. The agent reads the description, the comments and the acceptance criteria before it opens a file, and asks on the pull request rather than guessing when the ticket leaves a decision open.

In a Django service like healthchecks/healthchecks, that reading maps onto a small set of modules. `requirements.txt` pins `Django[argon2]` at 6.1.2 and `psycopg` at 3.3.6; `requirements-dev.txt` adds `mypy` 2.4.0 with `django-stubs`, and `mypy.ini` loads the Django plugin. `hc/api/urls.py` routes `ping/<uuid>` with its `fail`, `start`, `log` and exit-status variants to `views.ping`, `ping/<ping_key>/<slug>` to `views.ping_by_slug`, and `api/v1/` and `api/v2/` to the management views: `checks/`, `checks/<uuid>`, `pause`, `resume`, `pings/`, `flips/`, `channels/`, `badges/`. A ticket about ping handling lands in `views.ping` and the `_lookup` and `_update` helpers below it; a ticket about a management endpoint lands in the views behind the `@authorize` and `@authorize_read` decorators.

Alert integrations are one package each under `hc/integrations/<kind>/`, 31 of them from `slack` and `pd` to `ntfy` and `telegram`, each with `transport.py`, `views.py`, `urls.py` and a `tests/` folder holding `test_add.py` and `test_notify.py`. `CONTRIBUTING.md` spells out that layout and asks for a test with every fix or feature, formatted with `ruff`. The agent follows it: the change goes into the transport or view that owns the behaviour, and the test goes next to the existing ones.

Tests extend `BaseTestCase` in `hc/test.py`, which creates `alice` with a project whose `api_key` is 32 `X` characters and whose `ping_key` is 22 `p` characters, plus `bob` on her team, so new tests build on the same fixtures as `hc/api/tests/test_ping.py`. The agent runs `python manage.py test` with `SECRET_KEY` set, as `.github/workflows/tests.yml` does across Python 3.12 to 3.15 and SQLite, PostgreSQL, MySQL and MariaDB, then `ruff` on the files it touched, and opens the pull request with the issue URL in its description.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "Implement the Linear issue given as a resource in this Django codebase. Read the issue and its comments first. Make the change where it belongs, in the ping and API views under hc/api or in the integration package under hc/integrations that the issue names, and keep the diff small. Add tests on BaseTestCase next to the existing ones for the module you changed. Run `python manage.py test` with SECRET_KEY set, then `ruff check` and `ruff format --check` on the files you touched, and fix what fails. Open a pull request whose description links the issue, explains the change and quotes the test result. Do not merge.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    },
    {
      "url": "https://linear.app/your-org/issue/ENG-42"
    }
  ]
}
```

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 on its own branch. Its description links the Linear issue, names the view, transport or model the change touched, and quotes the `manage.py test` output. The diff holds the change and its tests, in the module layout the repository already uses.

The session carries the pull request URL. Your handler reads it from `GET /o/{org}/sessions/{id}` or from the `run.completed` webhook and posts it as a comment on the issue through your own Linear integration, since the sandbox has no Linear tools of its own. The transcript keeps every command and file, so a reviewer can see the test run and the files the agent read before changing anything.

Before merging, a reviewer checks the change against the acceptance criteria, confirms the new test fails without the fix, and looks at the database question: the sandbox ran SQLite, so a change to a query that behaves differently on PostgreSQL still needs CI's other legs.

## Run it on every Linear issue labeled agent

Create an automation with a `linear` trigger on `linear.issue.labeled`, `config.labels` set to the label your team uses to hand work off, and the Linear team keys in `config.teams` if only some teams should fire it. Labeling an issue starts one run with that issue as its context and this prompt. Changes made by an app integration never fire the trigger, so a bot that labels issues starts no runs.

A `linear.issue.state_changed` trigger adds a first step: `config.states` maps a Linear state to `plan`, a read-only run that posts its plan as a comment on the issue, or to `exec`, an ordinary run that opens the pull request. Map one state to `plan` and the next to `exec`, and the plan gets a human read before any code changes.

## Why run it on Rush?

A healthchecks change touches a test suite that wants a database and, for the full matrix, four of them. On Rush the agent gets its own sandbox with its own SQLite file, runs the suite there and keeps the output, so nobody's development database is migrated for a ticket about ping bodies. Several tickets run at the same time in separate sandboxes.

The result carries proof: the pull request quotes the test run and the transcript shows which files the agent read before editing `views.ping`. A reviewer judging a small change to alert delivery sees the `test_notify.py` test that covers it, not a message saying it was done.

## Frequently asked questions

### How does the agent see the Linear issue?

Through a `resources` entry with the issue URL, which Rush reads with your Linear connection and places in the prompt before the run starts. Connect Linear once with `POST /me/connections {"type": "app", "name": "linear"}` and finish the sign-in it returns. An issue URL with no Linear connection answers `422 RESOURCE_NOT_ACCESSIBLE`.

### Can it comment the pull request link on the issue?

Not from inside the sandbox: a Linear sign-in cannot yet be named in `connections`. The pull request URL comes back on the session and in the `run.completed` webhook, and your handler posts it on the issue.

### Which database does the test run use?

SQLite, the default in `hc/settings.py` when `DB` is unset. Set `DB=postgres` with the user and password variables, as the CI workflow does, by saving them as Project secrets and starting the session in that Project, and the agent runs against PostgreSQL instead.

### Will it add a new integration from a ticket?

If the ticket asks for one. `CONTRIBUTING.md` describes the package layout under `hc/integrations/<kind>/`, with the transport, the add view and the two test files, and the agent follows it. A ticket that large deserves a `plan` run first so the team reads the plan before the code.
