All jobs

Schedule Posts for Later in a Symfony App from a Linear Issue

Yes. An agent reads the Linear issue, hides future-dated posts everywhere readers can reach them, marks them scheduled in the admin and opens a pull request.

Run this on RushIn a Project that has your repository.

What the agent does

The agent clones the repository into its own cloud sandbox and starts by finding what already exists, because scheduling is often half there. In a Symfony app like symfony/demo, src/Entity/Post.php already has a publishedAt column mapped as date_point, set to the current time in the constructor, and src/Form/PostType.php already renders it with a DateTimePickerType. So an author can already pick a future date. The issue is really about what happens to such a post afterwards.

Next it traces every place a reader can reach a post. PostRepository::findLatest() already filters on p.publishedAt <= :now, so the blog index, the tag pages and the RSS feed (all served by BlogController::index) hide future posts. But findBySearchQuery() has no such condition, so the /blog/search route returns scheduled posts, and BlogController::postShow() resolves /blog/posts/{slug} straight from the slug, so anyone with the link reads the post early. The agent adds the same publishedAt <= now condition to the search query and makes the show route answer 404 for a future post unless the current user is its author, reusing the PostVoter that already decides show for authors.

For the admin side, templates/admin/blog/index.html.twig already lists each post with its publishedAt date. The agent adds a "Scheduled" badge when that date is in the future, with the label in the translation files the template already uses, so authors can tell queued posts from published ones at a glance.

Tests follow the existing ones. tests/Controller/BlogControllerTest.php and tests/Controller/Admin/BlogControllerTest.php use Symfony's browser client against a SQLite test database (.env.test points DATABASE_URL at data/database_test.sqlite), and phpunit.dist.xml loads the DAMA Doctrine test bundle so each test rolls back. The agent adds cases that a future-dated post is absent from the index and search, 404s for an anonymous reader, renders for its author, and shows the badge in the admin list. Then it runs vendor/bin/phpunit and fixes what fails.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "A Linear issue labeled agent says: \"Schedule Posts for Later in a Symfony App. Let an author set a future publishedAt on a post, hide it from the blog until then, and show it as scheduled in the admin list.\" Do the work in this repository, add tests for it, run vendor/bin/phpunit, and open a pull request that links back to the issue.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    },
    {
      "url": "https://linear.app/your-workspace/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. In an app shaped like the Symfony Demo the diff touches src/Repository/PostRepository.php (the search filter), src/Controller/BlogController.php (the show route), the admin index template and its translation keys, and the two controller test files. No migration is needed, because the column was already there; the description says so and lists every reader-facing route it checked.

A reviewer checks the edges: that a post scheduled for later is invisible on the index, tag pages, RSS, search and its direct URL; that the author can still preview it; and that the comparison uses the same clock in the query and in the controller. The tests are written to fail if any one of those routes leaks a future post.

The session keeps the record behind the change: every command with its output, including composer install, the PHPUnit run and the agent's notes on which routes already filtered and which did not. That list is often the most useful part of the review.

Run it on every Linear issue labelled agent

A Project automation with a Linear trigger on linear.issue.labeled, filtered to the agent label, starts one run per labelled issue with the issue as its context. Each run works on its own branch and ends in its own pull request, so the label is the whole handoff.

To start runs from your own system instead, send this request with the issue's URL in resources, and set a webhook URL on the API key. Rush POSTs run.completed with the session_url when the turn finishes, so the result arrives without polling.

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

Why run it on Rush?

The work here is mostly reading: finding the one query that filters and the two routes that do not. A run on Rush does that reading in a sandbox with the real app installed, then proves the result with PHPUnit against the SQLite test database, and every command and its output stays on the session for the reviewer.

It also runs while the team does something else. Labelled issues each get their own sandbox and branch, so a scheduling change, a form fix and a translation update can all be in progress at once and arrive as separate pull requests with their own checks.

Frequently asked questions

Does this add a cron job or a message queue to publish posts?

No. Because readers' queries compare publishedAt with the current time, a scheduled post appears on its own once that time passes. Nothing has to flip a flag, so there is no worker to run or monitor.

Will it add a new status column to the post table?

Not when the date is enough. The agent prefers the field the entity already has and says why in the pull request. If your issue asks for drafts that have no date at all, that is a different change, and the agent adds a Doctrine migration for it.

Can authors still preview a scheduled post?

Yes. The show route checks the existing PostVoter, which grants show to a post's author, before returning 404. Other users and anonymous readers get the 404 until the publish time.

What timezone does the comparison use?

The repository compares against new DatePoint(), and the admin template formats dates in UTC. The agent keeps that convention in every new condition and test, and a reviewer should confirm it matches how authors enter dates in the form.