All jobs

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 RushIn 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 with this body:

{
  "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.

The use case this job follows, with its automation and trigger: Turn a Linear label into a PR.

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.