Argus0.1.5

Guides

Running locally & offline testing

The entire service builds, runs, and tests offline — no network, no credentials, no Azure. Everything infra-shaped sits behind an interface with an in-process implementation, selected by environment variables:

Switch Effect
DATABASE_URL=memory In-memory state stores instead of Postgres
QUEUE_MODE=memory In-process queue instead of Azure Service Bus
MOCK_ADO=1 FakeAdoClient with a seeded demo PR instead of the ADO REST API
MOCK_RUNNER=1 Deterministic MockRunner instead of the Claude Agent SDK
CHECKOUT_MODE=fixture Copy a fixture directory instead of git clone

The full mock loop

Requires Node 22+. With QUEUE_MODE=memory, dev:ingress also runs the worker consume loop in-process, giving the complete loop — webhook POST → job → review → fake-ADO threads — in one terminal:

npm install && npm run build

export ADO_ORG_URL=https://dev.azure.com/example-org
export ARGUS_IDENTITY_ID=argus-identity-guid
export WEBHOOK_BASIC_USER=argus-hooks WEBHOOK_BASIC_PASS=change-me WEBHOOK_SHARED_SECRET=sekrit
export DATABASE_URL=memory QUEUE_MODE=memory MOCK_ADO=1 MOCK_RUNNER=1
export CHECKOUT_MODE=fixture FIXTURE_CHECKOUT_DIR=examples/demo-workspace

npm run dev:ingress

Then simulate an ADO service-hook delivery:

curl -i -X POST http://127.0.0.1:3000/webhook \
  -u argus-hooks:change-me -H 'x-argus-webhook-secret: sekrit' \
  -H 'content-type: application/json' \
  -d '{"subscriptionId":"sub-1","notificationId":1,
       "eventType":"git.pullrequest.created",
       "resource":{"pullRequestId":1,
                   "repository":{"id":"demo-repo","name":"demo-repo",
                                 "project":{"name":"demo-project"}}}}'

You get 202 {"outcome":"queued","jobType":"review.full"}; the inline worker picks up the job, "reviews" the demo workspace, and posts an inline thread on the fake PR. Replaying the same delivery is deduplicated; an update event with an unchanged head is dropped as vote churn.

Placeholders, not credentials

The values exported above are mock-mode placeholders, not credentials — nothing here talks to a real system.

The four-ring ladder

Confidence builds in four rings, each wider than the last, all offline:

Ring 1 — Unit tests

npm test

330+ vitest tests across every package, fully offline. Tests live in src/__tests__/ directories (never beside production code), run on in-memory fakes (pg-mem for Postgres, FakeAdoClient for ADO), and touch no network and no API keys.

Ring 2 — Evals

npm run evals

The golden-PR harness replays a corpus of curated PRs through the same worker pipeline as production with the deterministic MockRunner and scores findings against known expectations, gating on regression against a recorded baseline. See Evals & quality.

Ring 3 — Full mock loop in a container

npm run docker:up        # = docker compose up --build
curl http://127.0.0.1:3000/health
# then the webhook curl above, against the container

The same image that ships to production runs the complete loop with the mock-mode environment baked into docker-compose.yml — fake ADO, mock runner, in-memory state and queue, fixture checkout — plus a /health healthcheck. docker compose up also starts the docs site you are reading on port 4100, served by the same image.

Ring 4 — Swap real pieces one at a time

Every mock is an env switch, so realism arrives incrementally, not as one big bang:

Each swap changes exactly one variable of the experiment; everything else stays mocked until you choose otherwise.

Working on the docs site

npm run docs:build      # render markdown → static HTML in docs-site/dist
npm run docs:serve      # what production serves: build + bin/argus-docs.ts on :4100
Generated page

The configuration reference is generated from .env.example and the config schemas at build time — edit those sources, not the generated page.