Connect a GitHub repository to generate an inspectable architecture map, six-dimension health score, and evidence-linked findings.
Arbor's core analysis is deterministic: it shallow-clones a temporary working copy, parses supported source files with Babel AST and rule-based static checks, records derived metrics and findings, and removes the clone when processing finishes. Optional AI explanations and unified-diff patch suggestions are bring-your-own-key (BYOK) and review-only — Arbor never writes commits or opens pull requests on your behalf.
-
Create
.envfrom.env.exampleand start the stack:cp .env.example .env docker compose up -d --build
.env.exampledefaultsCOMPOSE_PROFILES="postgres,redis", so this single command builds the rootDockerfileonce (arbor-selfhosted:local), starts bundled PostgreSQL 16 + Redis 7, reconciles all 30 Prisma models (arbor-migrate), and launches the Next.js app (http://localhost:3000, probed viaGET /api/health) alongside the long-lived BullMQ worker (arbor-worker). To use external managed PostgreSQL and/or Redis instead of the bundled containers, adjustCOMPOSE_PROFILES(postgres,redis, or"") andDOCKER_DATABASE_URL/DOCKER_REDIS_URLin.env— seedocs/self-hosting.md.
-
Create
.envfrom.env.example:cp .env.example .env
Set real random values for
NEXTAUTH_SECRETandENCRYPTION_SECRET, pointDATABASE_URLandREDIS_URLat a running PostgreSQL 16 and Redis 7 instance, and configureGITHUB_CLIENT_IDandGITHUB_CLIENT_SECRETfrom a GitHub OAuth App (http://localhost:3000/api/auth/callback/github) if you want to sign in through the web UI. -
Install dependencies and sync the database schema:
npm install npm run db:push
npm run db:pushcreates all 30 models fromprisma/schema.prismafor local development. (npx prisma migrate deployapplies the 11 committed SQL migrations covering 25 tables; see Status.) -
Run the web app AND the background worker:
npm run dev:all
Or in two separate terminals:
npm run dev npm run worker
Why the worker is required: Repository scans are asynchronous jobs queued in PostgreSQL and BullMQ (
REDIS_URL). Withoutnpm run worker(or an authorizedGET /api/worker/processrequest carryingAuthorization: Bearer $CRON_SECRET), analyses remain inqueuedstatus and will not complete.To run the static analyzer directly against any local directory without starting PostgreSQL, Redis, or GitHub OAuth (and optionally emit a schema-validated SARIF 2.1.0 report for GitHub Code Scanning):
npm run analyze:local -- . npm run analyze:local -- . --sarif ./arbor-results.sarif
See
docs/sarif-github-code-scanning.mdfor the GitHub Actions workflow (github/codeql-action/upload-sarif@v3) andgh apiupload commands that publish Arbor findings into GitHub's Security -> Code scanning tab. -
Export an A4 consultant audit report PDF from any valid read-only share token:
# One-time Chromium install on a standard developer machine: npx playwright install chromium # Start the app (npm run dev, or npm run build && npm run start), # create a read-only share link from a completed project analysis # (optionally setting "Prepared for <client name>"), then run: npm run report:pdf -- <share-token> # Optional flags: # npm run report:pdf -- <share-token> --out ./audit-report.pdf --base-url http://localhost:3000
You can also open
http://localhost:3000/report/<share-token>directly in a browser and print/save as A4 PDF. Expired or revoked share tokens return HTTP404.
- Framework: Next.js 15 (App Router,
15.5.27), React 18 (18.2.0), TypeScript5.9.3(strict: true) - API: tRPC v11 (
11.19.0) + TanStack React Query v5 (5.105.0) + Zod (3.22.4) - Database: PostgreSQL 16 + Prisma 5 (
5.22.0) - Auth: NextAuth.js v4 (GitHub OAuth; optional allowlisted admin credentials for non-production use)
- Queue & Rate Limiting: BullMQ + Redis 7 (
ioredis) - Visualisation & UI: React Flow, Recharts, Tailwind CSS, Radix UI
src/lib/env.ts validates the server environment contract with Zod at import time. Copy .env.example to .env for a complete template.
| Variable | Description |
|---|---|
DATABASE_URL |
PostgreSQL connection URL (e.g. postgresql://arbor:arbor@localhost:5432/arbor) |
REDIS_URL |
Redis connection URL (e.g. redis://localhost:6379) |
NEXTAUTH_SECRET |
Non-empty secret used by NextAuth.js to sign/encrypt JWT sessions |
ENCRYPTION_SECRET |
Non-empty secret used (AES-256-GCM) to encrypt stored user BYOK AI provider keys and GitHub access tokens; rotating it invalidates previously stored keys |
| Variable | Default | Description |
|---|---|---|
GITHUB_CLIENT_ID |
"" |
GitHub OAuth App Client ID (githubConfigured is false when empty) |
GITHUB_CLIENT_SECRET |
"" |
GitHub OAuth App Client Secret |
GITHUB_WEBHOOK_SECRET |
"" |
HMAC secret for verifying /api/webhooks/github deliveries |
LEMONSQUEEZY_API_KEY |
"" |
Lemon Squeezy API key for workspace checkout & customer billing portal (billingConfigured is false when empty) |
LEMONSQUEEZY_STORE_ID |
"" |
Lemon Squeezy store ID for the $15/month per-workspace Teams plan |
LEMONSQUEEZY_TEAMS_VARIANT_ID |
"" |
Lemon Squeezy product variant ID for the Teams workspace subscription |
LEMONSQUEEZY_WEBHOOK_SECRET |
"" |
HMAC-SHA256 signing secret for verifying /api/webhooks/lemonsqueezy deliveries |
APP_URL |
https://arborgit.vercel.app |
Canonical application base URL (set http://localhost:3000 locally) |
CRON_SECRET |
"" |
Bearer token guarding the serverless fallback route /api/worker/process |
CLONE_BASE_DIR |
/tmp/arbor-clones |
Temporary directory for shallow repository clones during analysis |
CLONE_TIMEOUT |
60 |
Git clone timeout in seconds |
MAX_REPO_SIZE_MB |
500 |
Maximum repository size budget (MB) |
MAX_FILES |
5000 |
Maximum files indexed per scan |
MAX_FILE_SIZE_KB |
100 |
Maximum size per parsed source file (KB) |
MAX_PARSE_FILES |
2500 |
Maximum source files parsed with Babel AST per scan |
ANALYSIS_TIMEOUT_MS |
300000 |
Overall per-analysis timeout in milliseconds |
ADMIN_EMAILS |
"" |
Allowlist of admin user emails (comma-, semicolon-, or whitespace-separated) |
ADMIN_GITHUB_USERNAMES |
"" |
Allowlist of admin GitHub usernames |
ADMIN_USERNAME |
"" |
Optional admin credential username — must remain empty in production |
ADMIN_PASSWORD |
"" |
Optional admin credential password — must remain empty in production |
NEXTAUTH_URL— read by NextAuth.js at runtime for callback URL resolution.RESEND_API_KEY,EMAIL_FROM— optional; read directly insrc/server/services/admin.tsfor admin email broadcasts.REPORT_BASE_URL,PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH,PLAYWRIGHT_CHROMIUM_ARGS— optional CLI overrides read byscripts/export-report.ts(npm run report:pdf).COMPOSE_PROFILES,DOCKER_DATABASE_URL,DOCKER_REDIS_URL,APP_PORT,POSTGRES_PORT,REDIS_PORT,POSTGRES_USER,POSTGRES_PASSWORD,POSTGRES_DB,ARBOR_RUN_MIGRATIONS— optional Docker Compose / container entrypoint variables used bydocker-compose.ymlandscripts/docker-entrypoint.sh(seedocs/self-hosting.md).
AI provider keys are not environment variables. OpenAI and Anthropic keys are bring-your-own-key per user, encrypted in PostgreSQL via
ENCRYPTION_SECRET.
src/
├── app/ # Next.js 15 App Router pages & API route handlers
│ ├── (auth)/ # GitHub login & admin login pages
│ ├── (dashboard)/ # Authenticated workbench (/dashboard, /projects, /systems, /settings)
│ ├── (print)/ # Print-dedicated A4 consultant audit route (/report/[token])
│ ├── admin/ # Platform admin views (users, workspaces, audit, waitlist, system)
│ ├── api/ # NextAuth, tRPC, GitHub webhooks, badges, share JSON, SBOM, cron worker
│ └── share/[token]/ # Public read-only shared report page
├── components/ # UI components (dashboard, marketing, auth, Radix/CreateUI primitives)
├── lib/ # Zod env schema (env.ts), Prisma, Redis, NextAuth, AES-256-GCM crypto, SSRF
├── server/
│ ├── analysis/ # Deterministic Babel AST parser, dependency/SBOM scanner, policy packs
│ ├── routers/ # tRPC v11 routers
│ └── services/ # Domain logic (projects, workspaces, PR checks, triage, sharing, BYOK AI)
├── types/ # Module ambient type declarations
├── worker/ # Standalone BullMQ worker, startup stale-job recovery, schedule dispatcher
└── middleware.ts # Route protection & security headers
scripts/
├── analyze-dir.ts # Standalone local directory AST/dependency analyzer (analyze:local)
└── export-report.ts # Playwright headless Chromium A4 PDF exporter (report:pdf)
For self-hosting, phase-by-phase backend architecture notes, SARIF Code Scanning upload, worker container deployment, and verification tracking, see docs/self-hosting.md, docs/sarif-github-code-scanning.md, docs/worker-deployment.md, docs/backend-review-feature-roadmap.md, and docs/typecheck-baseline.md.
- Self-hosted Docker Compose (
Dockerfile+docker-compose.yml): Runcp .env.example .env && docker compose up -d --buildto launch bundledpostgresandredis(controlled viaCOMPOSE_PROFILES="postgres,redis"), schema sync (migrate),app(npm run start), andworker(npm run worker) from the singleDockerfile. Seedocs/self-hosting.md. - Fly.io or Railway: Build from the root
Dockerfilewith start commandnpm run worker, pointingREDIS_URL,DATABASE_URL, andENCRYPTION_SECRETat the exact same instances configured on your Next.js web deployment so queued jobs are picked up continuously. Step-by-step instructions andfly.worker.tomlconfig live indocs/worker-deployment.md. - Serverless cron fallback (
/api/worker/process):vercel.jsonretains the daily0 3 * * *UTC cron (Authorization: Bearer $CRON_SECRET,maxDuration = 300) as a zero-infrastructure fallback when no long-lived worker is active.
npm ci
npx prisma generate
npx prisma validate
npm run typecheck
npm run lint
npm test -- --run
npm run build- Verified by local verification command:
npx prisma generate&npx prisma validate: valid schema (30Prisma models, Prisma CLI5.22.0).npm run typecheck(tsc --noEmitwith TypeScript5.9.3,strict: true):0diagnostics.npm run lint(ESLint CLI across303files,--max-warnings 0):0errors,0warnings.npm test -- --run(Vitest + Testing Library):68test files,315tests passing.npm run build: Next.js15.5.27production build succeeds (including/api/health,/report/[token],/api/webhooks/lemonsqueezy, and/api/projects/[slug]/analyses/[analysisId]/sarif).npm run analyze:local -- . --sarif <file>: computes per-file Babel AST cyclomatic complexity crossed withsimple-gitgit logchurn (hotspots), per-top-level-directory bus factors + copy-ready.github/CODEOWNERSownership map (ownership), and OASIS SARIF 2.1.0 validated at runtime againstsarif-schema-2.1.0.json(1.5scold analysis across 3 runs vs1.8sbaseline —0%slowdown, well inside the<20%budget).npm run report:pdf -- <token>: verified end-to-end against PostgreSQL +next start+ headless Chromium, producing an 8-page A4 consultant audit PDF (docs/examples/arbor-audit-mdadeel-arbor.pdf) with cover metadata, deterministic top-5 recommended actions, severity-groupedfile:linefindings, dependency risk inventory, per-page commit SHA watermark, and HTTP404on expired/revoked tokens.
- GitHub Actions CI (
verifyandbuildjobs):unverified—.github/workflows/ci.ymlis authored withpostgres:16andredis:7service containers,npx prisma migrate deploy, typecheck, lint, tests, and production build, and the CI badge above remains commented out until a maintainer withworkflowsGitHub permission pushes.github/workflows/ci.ymland confirms both jobs green. - Unit-tested only (
unverifiedagainst live external services):- BullMQ job execution against live Redis (
ReportShareLink/Analysis/ProjectSQL migrations and read-only report rendering were verified against live PostgreSQL). - GitHub OAuth sign-in, webhook signature delivery lifecycle, and pull-request Check Runs against live GitHub repositories.
- Lemon Squeezy live store checkout creation, customer billing portal refresh, and live merchant webhook delivery (HMAC-SHA256 verification,
BillingWebhookEventreplay idempotency, owner-only checkout/portal authorization, and server-sideFreevsTeamsplan limits are verified by unit tests). - Optional BYOK OpenAI / Anthropic finding explanations and review-only patch suggestions against live provider APIs.
- Resend email delivery (
RESEND_API_KEY), live OSV advisory queries, and official CycloneDX schema validation (SBOM checks are currently structural only).
- BullMQ job execution against live Redis (
- Known gaps & unbuilt capabilities:
- Migration drift:
prisma/schema.prismadefines30models, whereas the11SQL migrations inprisma/migrations/create25tables (AdminEmail,ProjectGroup,ProjectGroupMember,SystemAnalysis,WaitlistLead, andUseradmin/plan fields are not yet in a SQL migration; usenpm run db:pushon fresh local databases). - Serverless fallback latency: When deployed without the long-lived
workercontainer (Dockerfile/docker-compose.yml/ Fly.io / Railway),vercel.jsontriggers/api/worker/processonce daily at03:00 UTC(maxDuration = 300). - Container runtime execution: Single-
Dockerfilestructure,scripts/docker-entrypoint.shPOSIX shell syntax (sh -n),/api/healthreadiness/liveness route, anddocker-compose.ymlpostgres/redisprofiles (migrate,app, andworkerservices) are verified bysrc/worker/container-config.test.tsandsrc/app/api/health/route.test.ts, while livedocker build/docker compose updaemon execution isunverifiedin sandbox environments without a Docker daemon. - Browser E2E suite:
@playwright/testpowersnpm run report:pdf, but noplaywright.configor automated UI E2E spec suite exists yet (unverified).
- Migration drift:
Arbor is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).
- Self-hosting and modification are free under the terms of the AGPL-3.0.
- Network use: Offering a modified version of Arbor as a network service requires publishing your complete corresponding source modifications under the AGPL-3.0.
- Commercial licensing: A commercial licence is available for white-label deployments or closed-source hosting — contact shahnawasadeel@gmail.com.