# Turn Linear Issues Into Pull Requests for a Flask App

Yes. Give the run a Linear issue and your Flask repository: the agent changes the forum or user blueprint, runs pytest and opens a pull request linking the issue.

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

## What the agent does

The agent reads the issue first. The `resources` list names the repository and the Linear issue URL, which Rush places in the prompt through your Linear connection, so the description, the comments and the acceptance criteria are in front of the agent before it opens a file.

In a Flask application like flaskbb/flaskbb, `pyproject.toml` requires Python 3.12 or newer and pins `Flask` 3.1, `Flask-SQLAlchemy` 3.1, `SQLAlchemy` 2.1, `Flask-Login`, `Flask-WTF`, `Flask-Allows2` for permissions and `celery` 5.6, with `uv.lock` as the lockfile and `make test` defined as `uv run pytest`. The forum blueprint is `flaskbb/forum/views.py`: `MethodView` classes such as `ViewForum`, `ViewTopic`, `NewTopic`, `EditTopic`, `NewPost`, `EditPost`, `MarkRead`, `LockTopic`, `HideTopic` and `MarkdownPreview`, registered in `flaskbb_load_blueprints` with `register_view` on routes like `/forum/<int:forum_id>` and `/topic/<int:topic_id>/edit`. The user blueprint in `flaskbb/user/views.py` has `UserSettings`, `ChangePassword`, `ChangeEmail`, `ChangeAvatar`, `ChangeUserDetails` and `UserLookup`, with the logic in `flaskbb/user/services/update.py`, `validators.py` and `factories.py`.

A ticket names a behaviour, and the agent traces it to the view, the form in `forms.py`, the model in `models.py` and the permission check, then changes the owner of that behaviour rather than adding a parallel path. A change to how a profile field validates goes into `flaskbb/user/services/validators.py`; a change to who may lock a topic goes into the permission the `LockTopic` view asks for.

Tests live under `tests/unit/forum` and `tests/unit/user`, in files like `test_topic_moderation.py`, `test_mark_read.py`, `test_update_details_handler.py` and `test_lookup_view.py`, and share fixtures that `tests/conftest.py` imports from `tests/fixtures/`. `tests/fixtures/app.py` builds the app from `TestingConfig`, whose database is `sqlite://` in memory and whose Celery runs tasks eagerly, and an autouse fixture clears the cache and the permission state between tests. The agent writes its test in that style, runs `uv sync --group dev` and `uv run pytest`, as `.github/workflows/tests.yml` does through tox on Python 3.12 to 3.15, then `ruff` on the files it changed, and opens the pull request.

## Start it with one API call

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

```json
{
  "agent": "codex",
  "input": "Implement the Linear issue given as a resource in this Flask codebase. Read the issue and its comments first. Make the change in the forum or user blueprint the issue concerns, including its form, model, service or permission check, and keep the diff small. Add pytest tests under tests/unit using the fixtures in tests/fixtures. Run `uv sync --group dev`, then `uv run pytest` and `uv run ruff 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

A pull request on its own branch comes back. Its description links the issue, names the view and service the change touched, and quotes the pytest summary. The diff holds the change, its test and nothing else from the ticket's neighbourhood.

The pull request URL is on the session, in `GET /o/{org}/sessions/{id}` and in the `run.completed` webhook, and your handler comments it on the Linear issue. The transcript keeps the `uv sync`, the test run and every file the agent read, so a reviewer sees that a permission change was checked against `tests/unit/forum/test_topic_page_permissions.py` and not only described.

Before merging, a reviewer checks the acceptance criteria against the diff, confirms the new test fails on the old code, and reads any change to a permission with the plugin system in mind, since `flaskbb_load_blueprints` is a pluggy hook and plugins register views the same way.

## Run it on every Linear issue labeled agent

Create an automation with a `linear` trigger on `linear.issue.labeled`, the label in `config.labels` and the team keys in `config.teams`. Each labeled issue starts one run with the issue as its context and this prompt. Changes made by an app integration never fire, so a label added by a bot starts nothing.

Pair it with a `linear.issue.state_changed` trigger whose `config.states` maps a review state to `plan`: that run changes no code and posts a plan as a comment on the issue through the runner's Linear connection. Move the issue on, and the state mapped to `exec` starts the run that opens the pull request.

## Why run it on Rush?

FlaskBB's suite runs on an in-memory SQLite database and eager Celery, so it is fast, but the project's tooling is `uv`, `tox`, `ruff` and `basedpyright`, and a ticket is not worth setting all of that up on a laptop. On Rush the sandbox installs from `uv.lock`, runs the suite and is discarded, and the output stays with the run.

Each ticket gets its own sandbox, so three small tickets about the user settings page run at once without sharing a checkout. The pull request quotes the test run, and the transcript shows which views and services the agent read, which is what a reviewer needs to trust a change to a permission check.

## Frequently asked questions

### How does the run get the issue?

From a `resources` entry with the Linear issue URL, read through your Linear connection and put into the prompt before the run starts. Connect Linear once with `POST /me/connections` and the `app` type, then name the issue URL on each run.

### Does the agent comment on the issue?

No. A Linear sign-in cannot yet be named in a run's `connections`, so the sandbox has no Linear tools. The pull request URL comes back on the session and in the webhook, and your handler posts it.

### Does it need PostgreSQL or Redis?

Not for the tests. `TestingConfig` uses `sqlite://` and runs Celery tasks in process. The `postgres` extra in `pyproject.toml` is for deployments.

### Will it touch the plugins?

Only if the ticket is about one. `flaskbb-plugin-conversations` and `flaskbb-plugin-portal` are dependencies, and the test app blocks every plugin not listed in `tested_plugins`, so a core change is tested without them.
