6 AI agents · fully parallel execution · one merged report
Point CodeAudit Swarm at any public GitHub repo and it fans out six specialized AI reviewers at the same instant — security, performance, test coverage, documentation, dependencies, and architecture — then merges their findings into a single scored, severity-ranked audit. Because every agent runs concurrently instead of one after another, a review that would take over a minute sequentially finishes in roughly 15 seconds.
codeaudit-swarm/
├── backend/ Node.js + TypeScript + Express — orchestration, agents, LLM router
└── frontend/ Next.js 14 + Tailwind CSS — live dashboard
POST /analyze { github_url }
│
▼
[GitHub Fetcher] ─── fetches file tree + raw source (sequential prerequisite)
│
▼
Promise.all([ ← all 6 dispatched at T = 0
securityAgent(ctx),
performanceAgent(ctx),
testCoverageAgent(ctx),
documentationAgent(ctx),
dependencyAgent(ctx),
architectureAgent(ctx),
])
│
▼
[Merger] ─── normalizes issues, deduplicates, computes weighted score
│
▼
FinalReport { overallScore, issues[], agentScores[], speedupFactor }
Each agent is isolated: a timeout or failure in one never blocks the others,
and partial results are still accepted into the final report. The frontend
polls /status/:jobId every 1.5s and animates each agent card from
pending → running → completed as results land.
| Agent | Focus |
|---|---|
| 🔒 Security | OWASP Top-10 issues, injection, hardcoded secrets, auth flaws |
| ⚡ Performance | N+1 queries, memory leaks, blocking operations |
| 🧪 Test Coverage | Untested functions, missing edge cases, test quality |
| 📄 Documentation | README gaps, missing docstrings, undocumented API surface |
| 📦 Dependency | CVEs (OSV.dev-style), outdated packages, license risk |
| 🏗 Architecture | SOLID violations, tight coupling, code smells, circular dependencies |
Rather than a single hard-coded model, every agent call goes through a router
(backend/src/services/llmRouter.ts) that picks a primary provider/model per
agent type, then fails over through a fixed chain if the primary errors or
times out (default 10s per attempt):
| Agent | Primary provider | Primary model |
|---|---|---|
| architecture | Gemini | gemini-2.5-pro |
| security | OpenRouter | deepseek/deepseek-chat |
| performance | Groq | llama-3.3-70b-versatile |
| documentation | Groq | mixtral-8x7b-32768 |
| testCoverage | Gemini | gemini-2.5-flash |
| dependency | Gemini | gemini-2.5-flash |
Fallback order: groq → gemini → openrouter (skipping whichever provider
was already tried as primary). Anthropic and OpenAI are also wired up in
services/llm.ts as legacy/optional providers. Any prompt longer than 10,000
characters is automatically upgraded to gemini-2.5-pro, regardless of agent,
except for architecture (already on Pro). If every provider in the chain
fails, the router degrades gracefully with a "partially complete" placeholder
instead of crashing the job.
The merger (backend/src/orchestrator/merger.ts) computes a weighted overall
score from each agent's individual score:
| Agent | Weight |
|---|---|
| Security | 0.30 |
| Dependency | 0.20 |
| Performance | 0.15 |
| Test Coverage | 0.15 |
| Documentation | 0.10 |
| Architecture | 0.10 |
speedupFactor is the sum of each completed agent's individual duration
divided by the actual wall-clock parallel duration — i.e. how much faster the
swarm ran versus running the same six agents one after another.
cd backend
cp .env.example .env
# fill in at least one LLM key — see Environment Variables below
npm install
npm run dev # → http://localhost:3001cd frontend
cp .env.example .env
npm install
npm run dev # → http://localhost:3000Open http://localhost:3000, paste any public GitHub repo URL, and launch
the audit. Watch the six agent cards update live, then view the merged score
and issue list.
| Variable | Required | Default | Description |
|---|---|---|---|
PORT |
No | 3001 |
HTTP server port |
NODE_ENV |
No | development |
development | production |
GEMINI_API_KEY |
Yes* | — | Primary provider for architecture/testCoverage/dependency |
GROQ_API_KEY |
Yes* | — | Primary provider for performance/documentation |
OPENROUTER_API_KEY |
Yes* | — | Primary provider for security |
ANTHROPIC_API_KEY |
No | — | Legacy/optional provider |
OPENAI_API_KEY |
No | — | Legacy/optional provider |
GITHUB_TOKEN |
Recommended | — | GitHub PAT — avoids the unauthenticated 60 req/hr limit |
REDIS_URL |
No | — | Optional Redis for job persistence (in-memory store used otherwise) |
AGENT_TIMEOUT_MS |
No | 45000 |
Max ms per agent before it's marked timeout |
DEMO_MODE |
No | true |
Adds a visible 2–8s delay per agent so parallelism is easy to see live |
*At least one of GEMINI_API_KEY, GROQ_API_KEY, OPENROUTER_API_KEY,
ANTHROPIC_API_KEY, or OPENAI_API_KEY must be set, or the server refuses to
start.
| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_API_URL |
http://localhost:3001 |
Backend API base URL |
Starts a new parallel audit.
// Request
{ "github_url": "https://github.com/owner/repo", "github_token": "ghp_optional_for_private_repos" }
// Response 202
{ "jobId": "3f8a2c1d-...", "status": "queued", "message": "Audit started. Poll GET /status/3f8a2c1d-... for progress." }Poll for live per-agent progress. Agent statuses move
pending → running → completed | error | timeout.
{
"jobId": "3f8a2c1d-...",
"status": "analyzing",
"progress": 65,
"agents": {
"security": { "status": "completed", "durationMs": 8210, "findingCount": 4 },
"performance": { "status": "running", "durationMs": null, "findingCount": 0 },
"testCoverage": { "status": "completed", "durationMs": 6540, "findingCount": 7 },
"documentation": { "status": "running", "durationMs": null, "findingCount": 0 },
"dependency": { "status": "completed", "durationMs": 4320, "findingCount": 3 },
"architecture": { "status": "pending", "durationMs": null, "findingCount": 0 }
}
}Returns 202 while still running, 200 with the full merged report when
done — including overallScore, severity summary, per-agent scores, the
normalized issues[] list, speedupFactor, and each agent's raw report.
A single agent's raw, unmerged report. agentName is one of security,
performance, testCoverage, documentation, dependency, architecture.
Liveness probe → { "status": "ok", "service": "codeaudit-swarm" }.
# Start an audit
curl -X POST http://localhost:3001/analyze \
-H "Content-Type: application/json" \
-d '{"github_url": "https://github.com/expressjs/express"}'
# Poll status (replace JOB_ID)
JOB_ID="3f8a2c1d-0000-0000-0000-000000000000"
curl http://localhost:3001/status/$JOB_ID | jq '.agents | to_entries[] | {agent: .key, status: .value.status, ms: .value.durationMs}'
# Wait for completion
while true; do
STATUS=$(curl -s http://localhost:3001/status/$JOB_ID | jq -r '.status')
echo "Status: $STATUS"
[ "$STATUS" = "completed" ] || [ "$STATUS" = "error" ] && break
sleep 2
done
curl -s http://localhost:3001/result/$JOB_ID | jq '{score: .overallScore, issues: .summary, speedup: .speedupFactor}'backend/src/
├── agents/ securityAgent, performanceAgent, testCoverageAgent,
│ documentationAgent, dependencyAgent, architectureAgent
├── orchestrator/
│ ├── index.ts Promise.all fan-out dispatcher
│ └── merger.ts normalizes findings, dedupes, computes weighted score
├── services/
│ ├── llm.ts provider clients (Gemini, Groq, OpenRouter, Anthropic, OpenAI)
│ ├── llmRouter.ts per-agent primary model + fallback chain + timeout handling
│ ├── githubFetcher.ts GitHub REST API integration
│ └── jobStore.ts in-memory job state (Redis-ready)
├── controllers/ HTTP request handlers
├── routes/ Express route definitions
├── middleware/ global error + 404 handling
├── config/ env var validation & provider/model config
├── types/ shared TypeScript interfaces
├── utils/logger.ts Winston logger
├── app.ts Express app factory
└── server.ts entry point + graceful shutdown
frontend/src/
├── app/ Next.js App Router: layout.tsx, page.tsx
├── components/ LandingHero, AuditDashboard, AgentCard, ParallelTimeline,
│ ScoreRing, SeveritySummary, IssueCard, AgentScoreChart,
│ SpeedupBanner
├── hooks/useAudit.ts polling + state hook for a running audit
├── lib/ api.ts (fetch wrapper), constants.ts
├── styles/globals.css dark cyber / terminal theme
└── types/ shared frontend types
- Stack: Next.js 14 (App Router), TypeScript, Tailwind CSS, Framer Motion, lucide-react — no heavy component library, mostly custom components + CSS.
- Fonts: Syne (display), JetBrains Mono (data/mono), DM Sans (body).
- Views: Landing hero with GitHub URL input → live 6-agent grid with a parallel Gantt-style timeline → final report with a score ring, severity breakdown, and filterable issue list.
- Aesthetic: dark cyber/terminal — void-black background, cyan accent
(
#00d4ff), severity-coded neon colors, scanline animation, noise texture, grid background.
Add a new agent:
- Create
backend/src/agents/myNewAgent.tsimplementing(ctx: CodeContext) => Promise<MyReport>. - Add a
MyReportinterface tobackend/src/types/index.ts. - Export it from
backend/src/agents/index.ts. - Register it in the
AGENT_RUNNERSmap inbackend/src/orchestrator/index.ts. - Add normalization logic for its issues in
backend/src/orchestrator/merger.ts(and give it a weight if it should count towardoverallScore).
The fan-out dispatcher picks it up automatically — no other wiring needed.
Add or reorder an LLM provider: edit FALLBACK_ORDER and the
primaryProvider/primaryModel switch in backend/src/services/llmRouter.ts,
and add the corresponding client function to backend/src/services/llm.ts.
- Designed for public repos; pass
github_tokenin the/analyzebody for private repos or to raise GitHub's rate limit. DEMO_MODE=trueintentionally adds a 2–8s delay per agent so the parallel execution is visibly demonstrable rather than finishing instantly.- Job state is in-memory by default; set
REDIS_URLfor persistence across restarts.