Skip to content

nmaties/nreactive

Repository files navigation

nreactive

Turn runtime errors into reviewable pull/merge requests, automatically.

nreactive is an open-source, self-hostable tool. You POST an error (plus the code area and any context) to its API; it queues the error, packs the relevant code with repomix, asks an LLM for a fix, and opens a draft PR (GitHub) or MR (GitLab) on your repo for human review. A dashboard lists every error, whether a PR was opened, and exactly why if it wasn't.


1. What it does

HTTP POST /api/send  ──>  store record (status=pending)  ──>  202 { id }
                                   │
        in-process poller (every POLL_INTERVAL_MS)
                                   │  claim up to QUEUE_BATCH_SIZE pending
                                   ▼
        per record:
          1. shallow-clone the target repo into a temp workdir
          2. repomix --include <area globs>  ──> packed code context
          3. build prompt(error, context, packed code)
          4. LLM generateFix()  ──> { title, summary, files:[{path,content}] }
          5. guardrails (allowed paths, max files, max diff size)
          6. git: branch (nreactive/...), write files, commit, push
          7. open PR (GitHub) / MR (GitLab)  ──> mrUrl
          8. record status = done + mrUrl   (or failed + failureReason)

Status lifecycle: pendingdone | failed. A claimed-but-crashed record is re-claimed after LEASE_TIMEOUT_MS (crash recovery).


2. Quick start

# 1. clone + install
git clone https://github.com/your-org/nreactive.git
cd nreactive
npm install

# 2. configure
cp .env.example .env
# edit .env: set your LLM key, git host token, DEFAULT_REPO, INGEST_API_KEY

# 3. start a database (Postgres + Mongo both provided)
docker compose up -d postgres   # or: docker compose up -d mongo

# 4. (Postgres only) run migrations
npm run prisma:migrate

# 5. run
npm run dev

Send your first error:

curl -X POST http://localhost:3000/api/send \
  -H "content-type: application/json" \
  -H "x-api-key: $INGEST_API_KEY" \
  -d '{
    "error": "TypeError: Cannot read properties of undefined (reading \"id\")",
    "area": ["src/users", "src/lib/auth"],
    "context": "Thrown in production when a session token is expired."
  }'

Watch the worker logs; the record flips pending → done and a draft PR/MR appears on your repo.


3. Creating the git host token

nreactive needs a token that can read repo contents, push a branch, and open a PR/MR. Use a token scoped to only the repos you want it to touch.

GitHub (fine-grained personal access token)

  1. Go to GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token.
  2. Resource owner: pick the user/org that owns the target repo.
  3. Repository access: choose Only select repositories and pick the repo(s) you want nreactive to open PRs on.
  4. Repository permissions — set these to Read and write:
    • Contents (clone, push branch)
    • Pull requests (open the PR)
    • Leave everything else at No access.
  5. Generate, copy the token, and set it in .env:
    GIT_HOST=github
    GITHUB_TOKEN=github_pat_xxx
    DEFAULT_REPO=owner/repo
    

Classic PATs also work — give them the repo scope — but fine-grained tokens are strongly preferred because you can limit them to specific repos.

GitLab (personal, project, or group access token)

  1. Go to GitLab → your repo → Settings → Access tokens (project token, most scoped), or User Settings → Access tokens for a personal token.
  2. Name it (e.g. nreactive) and set an expiry.
  3. Role: at least Developer (needed to push branches and open MRs).
  4. Scopes: select api (covers repo read/write + merge requests). If you prefer minimal scopes, write_repository plus MR access also works.
  5. Create, copy the token, and set it in .env:
    GIT_HOST=gitlab
    GITLAB_TOKEN=glpat-xxx
    GITLAB_BASE_URL=https://gitlab.com        # or your self-hosted instance
    DEFAULT_REPO=group/project                # full project path
    

The target repo is DEFAULT_REPO by default; any request can override it with a repo field in the payload (as long as the token has access).


4. Choosing the database driver

nreactive ships a storage adapter with two interchangeable backends, selected by DB_DRIVER.

Postgres (default, via Prisma)

DB_DRIVER=postgres
DATABASE_URL=postgresql://nreactive:nreactive@localhost:5432/nreactive?schema=public

Run migrations before first use (and after pulling schema changes):

npm run prisma:migrate     # prisma migrate deploy

MongoDB (via Mongoose)

DB_DRIVER=mongo
MONGODB_URI=mongodb://localhost:27017/nreactive

No migration step is needed — Mongoose creates the collection and indexes on first write.


5. API reference

POST /api/send

Ingest an error for processing.

Headers

header required notes
content-type: application/json yes
x-api-key: <INGEST_API_KEY> only if INGEST_API_KEY is set Authorization: Bearer <key> is also accepted

Body

{
  "error": "string (required) — the message + stacktrace",
  "area": ["string"],   // optional — folder globs to scope the code context
  "context": "string",  // optional — extra runtime/user context
  "repo": "owner/repo"  // optional — overrides DEFAULT_REPO
}

Response202 Accepted

{ "id": "", "status": "pending" }

Errors: 400 (invalid JSON / payload), 401 (bad or missing API key).

GET /api/errors

Paginated list for the dashboard.

Query params: page (default 1), limit (default 20, max 100), status (pending | done | failed).

{ "items": [ /* ErrorRecord[] */ ], "total": 0, "page": 1, "limit": 20 }

6. Guardrails & queue config

All configurable via env vars (see .env.example):

var default purpose
QUEUE_BATCH_SIZE 5 pending records claimed per poll tick
POLL_INTERVAL_MS 10000 how often the poller runs
LEASE_TIMEOUT_MS 300000 stuck-record re-claim window (crash recovery)
MAX_FILES_CHANGED 10 reject fixes touching more files
MAX_DIFF_BYTES 200000 reject oversized fixes
MAX_ATTEMPTS 3 stop retrying a record
BRANCH_PREFIX nreactive generated branches are always prefixed
ENABLE_WORKER true set false to run the web app without the poller

The fix is also restricted to paths under the request's area (path allowlist), and nreactive never pushes to the default branch — it always opens a PR/MR for human review.


7. Self-host / Docker notes

  • The background worker boots from Next.js instrumentation.ts and is gated by ENABLE_WORKER. To scale, run the web app with ENABLE_WORKER=false and a single separate next start instance with ENABLE_WORKER=true as the worker.
  • docker-compose.yml provides Postgres and Mongo for local development. Bring up only the one matching DB_DRIVER.
  • repomix is invoked as a CLI (npx repomix) against the cloned repo, so the upstream tool is tracked as-is.
  • Set WORK_DIR to control where repos are cloned during processing (default /tmp/nreactive-work); each job uses a fresh temp dir that is cleaned up after.

Development

npm run dev          # next dev
npm run build        # production build (+ typecheck)
npm test             # vitest run
npm run test:watch   # vitest watch

Tests live in tests/ and cover the core (prompt builder, guardrails, LLM output parsing, store CRUD + claim-batch, and the full process-record pipeline with mocked LLM + git host).

License

Open source. See LICENSE (add the license of your choice).

About

Turn runtime errors into pull requests.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Contributors