All jobs

Add Rate Limiting to an Express API from a Linear Issue

Yes. An agent picks up the Linear issue, adds per-route rate limits to your Express API, proves them with Jest tests and opens a pull request.

Run this on RushIn a Project that has your repository.

What the agent does

The run starts from the repository URL in resources: the agent clones it into its own cloud sandbox and reads the app the way a new maintainer would. In an Express project like hagopj13/node-express-boilerplate it opens package.json and finds yarn test mapped to jest -i --colors --verbose --detectOpenHandles, Express 4.17, and express-rate-limit already pinned at 5.3.0 in yarn.lock, so no new dependency is needed. Tests live under tests/, with tests/integration/auth.test.js driving the app through supertest.

The boilerplate already has one limiter, and the agent reads it before writing anything. src/middlewares/rateLimiter.js exports a single authLimiter: a 15 minute window, 20 requests, skipping successful ones, and src/app.js mounts it on /v1/auth only when config.env === 'production'. The issue asks for something stricter and always on: 5 requests per minute per IP on login and register, 100 per minute on every other route, with 429 and a Retry-After header when a limit trips.

The agent extends that middleware file rather than adding a second one. It adds a 60 second limiter with max: 5 and mounts it on POST /v1/auth/register and POST /v1/auth/login in src/routes/v1/auth.route.js, where the auth routes are declared. A second limiter, 100 requests per 60 seconds, goes in app.js ahead of app.use('/v1', routes) so it covers users, docs and health checks alike. express-rate-limit answers 429 and sets Retry-After itself, so the response shape comes from the library the project already ships.

Proving it needs a database: tests/utils/setupTestDB.js connects Mongoose to MONGODB_URL with a -test suffix, and docker-compose.test.yml runs mongo:4.2.1-bionic for exactly that. The agent starts MongoDB in the sandbox, adds tests/integration/rateLimiter.test.js with a case that sends six register requests from one IP inside a minute and asserts the sixth answers 429 with a Retry-After header, plus a case that a plain GET under /v1 is still allowed below the general limit. Then it runs yarn test 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: \"Add Rate Limiting to an Express API. Limit login and register to 5 requests per minute per IP and every other route to 100, returning 429 with a Retry-After header.\" Do the work in this repository, add tests for it, run yarn test with a MongoDB started in the sandbox, and open a pull request that links back to the issue.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
  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. Its diff touches src/middlewares/rateLimiter.js with the two new limiters, src/app.js with the general mount, src/routes/v1/auth.route.js with the per-route mounts on register and login, and a new tests/integration/rateLimiter.test.js. The description quotes the issue and links back to it.

The checks on the pull request run the same yarn test command a developer would run on a laptop. A reviewer reads the diff for three things: the limit values match the issue, 429 responses carry Retry-After, and the tests fail if either limiter is removed from the middleware stack. Nothing else in the app changes: the existing production-only authLimiter and the security headers from helmet() stay where they are.

The session read keeps the record behind the pull request: every command the agent ran with its output, including the jest run against the sandbox MongoDB and the requests that proved a 429. Anyone who questions the checks can read exactly how the suite was run.

Run it on every Linear issue labelled agent

The Project's automation turns the label into the run. In the console, add an automation with a Linear trigger on linear.issue.labeled filtered to the agent label and this prompt; each labelled issue starts its own run in its own sandbox and opens its own pull request. The issue stays the queue and the label stays the only action a person takes.

If the automation is not wanted, a small server can do the same: receive Linear's issue webhook, put the issue text into input in place of the quoted text, and POST to /o/{org}/sessions. A run.completed webhook on the API key then posts the result URL to that server when each run finishes, so nothing polls.

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

Why run it on Rush?

On a laptop this job is a chain of setup: a checkout, yarn install against the lockfile, and a MongoDB on port 27017 before jest will even connect. Each run on Rush boots its own sandbox with that already in reach, starts MongoDB itself, and keeps every command and its output, so the proof of the 429 tests is the run's own record rather than a paste into a pull request comment.

The label scales to however many issues land at once. Issues labelled in one evening become one run each, in one sandbox each, each on its own branch with its own pull request, instead of a queue of checkouts competing for a single laptop's MongoDB and a single person's attention.

Frequently asked questions

The boilerplate already ships a rate limiter. What changes?

The existing authLimiter in src/middlewares/rateLimiter.js stays; it limits all of /v1/auth to 20 requests in 15 minutes, only in production. The new limiters enforce the issue's numbers, 5 per minute on register and login and 100 per minute elsewhere, in every environment, and they answer 429 with Retry-After.

Does it work with yarn?

Yes. The agent installs with the lockfile the repository already has and runs the test script from package.json, so the checks on the pull request run exactly what a developer running yarn test would run.

The tests need MongoDB. Where does it come from?

tests/utils/setupTestDB.js connects Mongoose to MONGODB_URL with a -test suffix, and docker-compose.test.yml documents the mongo:4.2.1-bionic image the suite expects. The sandbox starts its own MongoDB, runs the suite against it, and the session keeps the output.

What does a limited request get back?

express-rate-limit answers 429 and sets a Retry-After header with the number of seconds to wait. The integration tests assert both, so the header cannot silently disappear in a later change.

Can I change the limits without editing the code myself?

Yes. Edit the issue text: the limits and the routes they apply to are the spec the agent works from, so a new run picks up the new numbers and updates the tests to match.