# Set Up GitHub Actions CI for an Express App

Yes. An agent reads your Express repo, adds a GitHub Actions workflow that lints, tests against Postgres and builds, and fixes it until it passes.

[Run this on Rush](https://cloud.getrush.ai/run/add-github-actions-ci/express/), in a Project that has your repository.

## What the agent does

The agent starts from what the repository already declares. In an Express API like gothinkster/node-express-realworld-example-app, `package.json` has three scripts, `start`, `build` and `test`, and each of them calls `nx`: the project is an Nx 17.2.6 workspace with one application, `api`, described in `project.json`. The lockfile is `package-lock.json` at `lockfileVersion` 3, there is no `engines` field and no `.nvmrc`, and `@types/node` is pinned to `18.16.9`, so the agent pins Node 18 in the workflow and says in the pull request why.

Then it reads how the project is built and tested. `project.json` defines `build` with the `@nx/esbuild` executor from `src/main.ts` into `dist/api`, `lint` with `@nx/eslint:lint` over `./src`, and `test` with `@nx/jest:jest` reading `jest.config.ts`, which runs `ts-jest` over `src/**/*.spec.ts` and `*.test.ts`. The five unit tests under `src/tests/services/` mock Prisma with `jest-mock-extended` through `src/tests/prisma-mock.ts`, so they need no database. The `e2e` project is different: `e2e/jest.config.ts` has a global setup and a spec that calls the running server with axios, so it needs the API up and a database behind it.

The database is the part the workflow has to get right. `src/prisma/schema.prisma` declares a `postgresql` datasource read from `DATABASE_URL`, with migrations under `src/prisma/migrations/` and a seed script in the `prisma` block of `package.json`. The README lists `DATABASE_URL`, `JWT_SECRET` and `NODE_ENV` as the required variables. So the workflow adds a `postgres` service container, sets `DATABASE_URL` to it, runs `npx prisma generate` and `npx prisma migrate deploy` before the tests, and sets a throwaway `JWT_SECRET`.

The workflow it writes at `.github/workflows/ci.yml` runs on pull requests and on pushes to the default branch, checks out, sets up Node 18 with `actions/setup-node` caching keyed on `package-lock.json`, runs `npm ci`, then `npx nx lint api`, `npx nx test api --configuration=ci` for coverage, `npx nx build api`, and the migrations against the service. The agent pushes the branch and watches the workflow run on its own pull request; when a step fails, it reads the log, fixes the cause and pushes again. In this repository it also notes that `e2e/src/server/server.spec.ts` expects a `Hello API` body that `src/main.ts` does not send, and leaves the e2e project out of the required job with that reason in the description rather than editing the test to pass.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "Add a GitHub Actions workflow at .github/workflows/ci.yml that runs on every pull request and on pushes to the default branch. Read package.json, the lockfile, project.json, nx.json, jest.config.ts and prisma/schema.prisma first: pin the Node version the repository implies, use the package manager the lockfile implies with caching keyed on that lockfile, and run the lint, test and build targets the project defines. If the tests or the app need a database, add a postgres service container, point DATABASE_URL at it, and run prisma generate and prisma migrate deploy before the tests, with any other required variables set to throwaway values. Do not touch existing workflow files. Open a pull request and make sure the new workflow passes on it; if a step fails, fix the cause and push again. If an existing test cannot pass as written, leave it out of the required job and explain why in the pull request instead of changing the test.",
  "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 on its own branch adding `.github/workflows/ci.yml` and nothing else unless a script was missing. The workflow has one job with a `postgres` service, Node 18 from `actions/setup-node` with npm caching, `npm ci`, the Prisma generate and migrate steps with `DATABASE_URL` pointing at the service, and the three Nx targets in order: lint, test with the `ci` configuration, build. The job's checks show green on the pull request itself before the agent finishes.

The description explains each pin: Node 18 because `@types/node` is `18.16.9` and nothing else declares a version, npm because the lockfile is `package-lock.json`, the service container because the Prisma datasource is Postgres. It also says what was left out and why, such as the `e2e` project whose spec expects a response body the server does not send.

A reviewer checks that the workflow runs the same commands they run locally, that no secret was committed (the `JWT_SECRET` in the workflow is a throwaway string for tests only), and that the service's Postgres major matches what production uses. The session read returns the repository and the pull request, and the transcript keeps every workflow run the agent watched, including any failed attempt and the fix that followed.

## Run it on every new repository

Start one run per repository without CI from your own server: `POST /o/{org}/sessions` with this prompt and that repository in `resources`, one call each. `GET /o/{org}/github` lists every repository the Rush GitHub App installation can reach, so a script can find the ones with no `.github/workflows/` directory and start a run for each. Each run works in its own sandbox and on its own branch.

Give the key a `webhook_url` and each run POSTs `run.completed` with its `session_url` when the turn finishes, so the pull request links collect on your side without polling. A key has at most `max_concurrent` runs in progress at once, 4 by default, so a batch over many repositories queues past that.

## Why run it on Rush?

A workflow is only done when it has passed on a real pull request, and that loop of push, wait, read the log, fix, push again is the tedious part. On Rush the agent runs that loop itself in its own sandbox, with the repository's own Node, npm and Postgres, and every attempt stays in the transcript. The reviewer sees the first failure and the fix rather than a workflow that was never run.

The details that break CI are all in files: the Nx targets, the Prisma datasource, the missing `engines` field, the e2e spec that disagrees with the server. The agent reads them in the sandbox and writes the workflow from what it found, not from a template, and the pull request says which file each choice came from.

## Frequently asked questions

### Will it change my existing workflow files?

No. The prompt says not to touch existing workflows, so the agent adds `ci.yml` beside them. If an existing workflow already covers lint or tests, say so in the prompt and the new one is scoped to what is missing.

### The tests need a database. How does the workflow get one?

With a service container. The agent reads the Prisma datasource provider, adds a `postgres` service with a health check to the job, sets `DATABASE_URL` to it and runs `prisma migrate deploy` before the tests. Unit tests that mock Prisma, like the ones under `src/tests/services/`, run without it either way.

### Does it work with Nx, Turborepo or a plain npm scripts repository?

Yes. The agent runs whatever the repository's scripts call. In the RealWorld example that is `npx nx lint api`, `npx nx test api` and `npx nx build api`; in a plain repository it is `npm run lint`, `npm test` and `npm run build`.

### Which Node version will it pin?

The one the repository implies, in this order: `.nvmrc`, `engines.node` in `package.json`, then the `@types/node` major. The RealWorld example has only the last, `18.16.9`, so the workflow pins Node 18 and the description says that is the reason.

### What happens if a test fails for a reason unrelated to CI?

The agent does not edit the test to make it pass. It leaves that test out of the required job, names it in the pull request with the reason, and the workflow stays green on what is actually correct. You can reply to the session with a follow-up to fix the test as well.
