What the agent does
The agent reads how the app boots before adding a module. In a NestJS API like brocoders/nestjs-boilerplate, src/main.ts creates the app on NestJS 11, adds Helmet and CORS, calls enableShutdownHooks(), sets a global prefix from app.apiPrefix with only / excluded, turns on URI versioning, and serves Swagger at /docs. src/app.module.ts picks the database at startup: a <database-block> comment wraps a ternary that loads TypeOrmModule for Postgres through TypeOrmConfigService or MongooseModule through MongooseConfigService, depending on isDocumentDatabase from src/database/config/database.config.ts. src/home/home.controller.ts already answers GET / with the app name, which is the closest thing to a health route today, and package.json lists no @nestjs/terminus.
It adds @nestjs/terminus at the version matching the installed @nestjs/common and a HealthModule under src/health/. GET /health/live answers 200 with no dependency checks, so an orchestrator restarts the process only when the event loop is stuck. GET /health/ready runs Terminus's TypeOrmHealthIndicator.pingCheck or MongooseHealthIndicator.pingCheck, chosen by the same isDocumentDatabase switch, with a short timeout, and answers 503 with the indicator's result when the database is unreachable. The controller keeps the repository's conventions: @ApiTags('Health') so the routes appear in Swagger, and no version decorator, so they sit beside the home route rather than under /v1. Because the global prefix applies, the paths are /api/health/live and /api/health/ready with the default API_PREFIX=api; the pull request says so and shows the one-line change to the exclude list in src/main.ts if you want them at the root instead.
The e2e tests follow test/user/auth.e2e-spec.ts, which uses Supertest against APP_URL built from APP_PORT and runs under test/jest-e2e.json with ts-jest. A new test/health/health.e2e-spec.ts expects 200 from the live route, 200 with a database entry marked up from the ready route, and no authentication on either. The agent runs the suite the way the repository does, through docker-compose.relational.ci.yaml, which starts postgres:17.9-alpine and maildev beside the API container built from relational.e2e.Dockerfile.
Last, the container. Dockerfile starts from node:24.14.1-alpine and startup.relational.dev.sh waits for Postgres with wait-for-it.sh, runs migrations and seeds, then npm run start:prod. The agent adds a HEALTHCHECK that calls the ready route with wget, which the Alpine image has, and documents the two paths in the README's environment section next to APP_PORT and API_PREFIX.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Add health checks to this NestJS API. Read src/main.ts, src/app.module.ts, src/database/config/database.config.ts, src/home/home.controller.ts, test/user/auth.e2e-spec.ts, test/jest-e2e.json, docker-compose.relational.ci.yaml and the Dockerfile first. Add @nestjs/terminus at the version matching @nestjs/common, and a HealthModule with GET /health/live, which answers 200 with no dependency checks, and GET /health/ready, which pings the database through the TypeORM or Mongoose indicator chosen by the same isDocumentDatabase switch app.module.ts uses, with a timeout, and answers 200 or 503 with the indicator result. Keep the routes unauthenticated, tag them for Swagger, and say in the pull request what paths they get under the global prefix. Add an e2e spec under test/health/ in the style of the existing specs and run the relational e2e suite through docker compose. Add a HEALTHCHECK on the ready route to the Dockerfile. Open a pull request with the paths, the test output and the one-line change needed to serve the routes at the root instead.",
"resources": [
{
"url": "https://github.com/your-org/your-app"
}
]
}- 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.
- 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.
- 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 with src/health/health.module.ts, src/health/health.controller.ts, the import in src/app.module.ts, test/health/health.e2e-spec.ts, the HEALTHCHECK line in Dockerfile, and package.json with package-lock.json for @nestjs/terminus. The description names the final paths under the prefix, which indicator the ready route uses for each database, and the timeout.
The session's transcript holds the dependency install, the compose build and start, the e2e run with its output, and any failure on the way, in order. The repository's own CLI tests workflow runs on the pull request as well, so the generator suites that run on every change report alongside.
A reviewer checks three things before merging: that the live route touches nothing that can fail, that the ready route's timeout is shorter than the orchestrator's probe interval, and that the routes are reachable at the path the deployment expects, since the global prefix moves them under /api by default. One follow-up message to the same session changes the prefix handling or adds a check for the mail host, and the sandbox runs the suite again.
Run it on every new service without a health route
A platform team adding probes to several NestJS services starts one run per repository, a POST /o/{org}/sessions with that repository in resources and this prompt. An Idempotency-Key per repository makes a retried request return the run it already started.
Each run has its own sandbox and its own Docker daemon, so the compose-based e2e suites of several services run at the same time without sharing ports. A webhook on the key posts run.completed for each turn with the session_url to read the pull request from, and a run whose suite does not pass is reported rather than merged.
The use case this job follows, with its automation and trigger: Hand off from your terminal.
Why run it on Rush?
Testing a readiness probe means running the API against a real database, taking the database away, and watching the route turn to 503. The repository's own e2e setup does that through Docker Compose, which on a laptop means a Postgres container, a maildev container and an API container bound to local ports. In a Rush sandbox the agent runs that stack on its own daemon, and the sandbox parks when the turn ends.
The pull request carries the compose run and the e2e output in the transcript, so a reviewer sees the ready route answering 200 with the database up and the spec passing, rather than trusting a description. The same prompt runs against several services at once, each in its own sandbox, each ending in its own pull request.
Frequently asked questions
Why two endpoints rather than one /health?
Because they answer different questions. A liveness probe asks whether the process should be restarted and must not depend on the database, or a database outage turns into a restart loop. A readiness probe asks whether traffic should be routed here and may fail while the database is down. Kubernetes and most load balancers expect the two separately.
Does the ready check open a new database connection?
No. The TypeORM indicator runs a query through the connection TypeORM already holds, and the Mongoose indicator uses the existing connection's state. The timeout the agent sets keeps a slow database from making the probe hang.
The boilerplate supports Postgres and MongoDB. Which one gets the check?
Both. The health module picks the indicator with the same isDocumentDatabase switch that src/app.module.ts uses to load TypeORM or Mongoose, inside the same comment markers, so the repository's generator that strips one database still leaves a working check.
Are the routes behind the JWT guard?
No. Guards in this repository are applied per controller with @UseGuards, not globally, so the health controller simply does not add one. The e2e spec asserts both routes answer without a token.
Will the Docker HEALTHCHECK work on the Alpine image?
Yes. The image is node:24.14.1-alpine, which ships wget, so the check calls the ready route with it rather than curl. The check is in the application Dockerfile; the e2e Dockerfiles are for tests and are left alone.