# Turn Linear Issues Into Pull Requests for a Laravel App

Yes. Give the run a Linear issue and your Laravel repository: the agent changes the page or permission code, runs PHPUnit and opens a linked pull request.

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

## What the agent does

The issue arrives as a resource. `resources` names the repository and the Linear issue URL, which Rush reads through your Linear connection and puts in the prompt, so the agent has the description, comments and acceptance criteria before it opens a file.

In a Laravel application like BookStackApp/BookStack, `composer.json` asks for PHP 8.3 and Laravel 13, with `phpunit/phpunit` 12.5, `larastan/larastan` 3 and `squizlabs/php_codesniffer` 4 in `require-dev`, and scripts `test` (`phpunit`), `check-static` (`phpstan --memory-limit=2g`), `lint` (`phpcs`) and `refresh-test-database`. Pages are handled by `app/Entities/Controllers/PageController.php` on routes in `routes/web.php` such as `/books/{bookSlug}/create-page`, `/books/{bookSlug}/draft/{pageId}` and `/books/{bookSlug}/page/{pageSlug}/edit`, with the logic in `app/Entities/Repos/PageRepo.php`: `getNewDraftPage`, `publishDraft`, `update`, `updatePageDraft`, `restoreRevision`, `move`, `destroy`. Permissions live in `app/Permissions/`: `PermissionApplicator.php` with `checkOwnableUserAccess`, `restrictEntityQuery` and `restrictPageRelationQuery`, `JointPermissionBuilder.php`, `EntityPermissionEvaluator.php` and `PermissionsRepo.php`.

A ticket about page editing goes into `PageRepo` or the controller; a ticket about who sees what goes into the applicator or the evaluator, and the agent changes the method that owns the behaviour. `dev/docs/php-testing.md` sets the rules for the test: classes under `tests/` ending in `Test`, extending `Tests\TestCase`, with snake_case methods that start with `test_`. `tests/TestCase.php` gives `asAdmin`, `asEditor`, `asViewer`, `assertPermissionError` and `assertActivityExists`, and `tests/Entity/PageTest.php` and `tests/Permissions/EntityPermissionsTest.php` show the pattern, with the `Scenarios` folder for permission cases.

The suite is functional and needs MySQL: `phpunit.xml` sets `DB_CONNECTION` to `mysql_testing`, and the docs expect a `bookstack-test` database at `127.0.0.1` or a `TEST_DATABASE_URL`, migrated and seeded with `composer refresh-test-database`, which runs `migrate:refresh` and the `DummyContentSeeder`. The agent sets that up in the sandbox, runs the changed test class with `php vendor/bin/phpunit tests/Entity/PageTest.php` and then `composer test`, plus `composer lint` and `composer check-static` on the files it touched, and opens the pull request against `development`, the default branch.

## 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 Laravel codebase. Read the issue and its comments first. Make the change in the page repository, page controller or permission classes the issue concerns, and keep the diff small. Add PHPUnit tests following dev/docs/php-testing.md, next to the existing tests for that area. Provide the mysql_testing database the way the docs describe, run `composer refresh-test-database`, then the changed test files and `composer test`, and `composer lint` and `composer check-static`; fix what fails. Open a pull request against the default branch 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 against `development` comes back. Its description links the issue, names the repo method or permission class it changed, and quotes the PHPUnit summary, with the `phpcs` and PHPStan results beside it. The diff holds the change and the test.

The pull request URL is on the session and in the `run.completed` webhook, and your handler posts it as a comment on the issue, because the sandbox has no Linear tools. The transcript keeps the database setup, the seed, each PHPUnit command and every file the agent read, so a reviewer can see a permission change was checked against `EntityPermissionsTest.php` before it was made.

Before merging, a reviewer reads a permission change twice: once against the acceptance criteria, and once with `JointPermissionBuilder.php` open beside it, since the applicator's queries depend on what the builder stores and a mismatch shows up only in a scenario test.

## Run it on every Linear issue labeled agent

Create an automation with a `linear` trigger on `linear.issue.labeled`, your hand-off 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, and a label added by an app integration never fires it.

For permission tickets, add a `linear.issue.state_changed` trigger whose `config.states` maps a review state to `plan`. That run changes no code and posts its plan as a comment on the issue; the state mapped to `exec` starts the run that opens the pull request, once someone has read the plan.

## Why run it on Rush?

BookStack's tests are functional and want a seeded MySQL database, which the docs ask you to create by hand before `composer test` works. On Rush the sandbox does that for each run and is discarded, and the seed, the suite and the static analysis output stay with the run.

Permission code is where a quiet mistake costs most, and a pull request that quotes `EntityPermissionsTest` passing is a different thing from one that says the change is safe. Several tickets run at once in separate sandboxes, each with its own database, while the maintainers' checkouts stay untouched.

## Frequently asked questions

### How does the agent read the issue?

From a `resources` entry with the Linear issue URL, which Rush reads through your Linear connection and places in the prompt. Connect Linear once with `POST /me/connections {"type": "app", "name": "linear"}` and finish the sign-in it returns.

### Does it comment on the issue when the pull request is open?

No. A Linear sign-in cannot yet be named in `connections`, so the sandbox has no Linear tools. Read the pull request URL from the session or the `run.completed` webhook and post it from your handler.

### Does it need MySQL?

Yes, for the suite. `phpunit.xml` fixes `DB_CONNECTION` at `mysql_testing`. The agent starts a MySQL server in the sandbox; if your fork sets `TEST_DATABASE_URL`, save it as a Project secret and the suite uses it.

### Will it change the JavaScript?

Only if the ticket does. The front end has its own `package-lock.json` and `jest.config.ts`; a ticket about the editor is a different job from a ticket about `PageRepo`.
