# Project export: DryRun

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: UC Berkeley AI Hackathon 2026
- Tagline: DryRun is a multi-agent AI system that optimizes protein design by coordinating 23 specialized agents to reduce experimental cost and improve success rates.
- Devpost: https://devpost.com/software/dryrun
- GitHub: https://github.com/Anthony-Yangg/dryrun_v2
- Video: https://www.youtube.com/embed/LR_dWkoLAoA?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — RaunakGengiti2725 (8 commits), Cursor (5 commits), Anthony-Yangg (1 commits)

## Devpost submission (written by the team)

### Inspiration

Protein design is powerful, but the workflow is expensive, fragmented, and hard to reason about. Researchers generate dozens of variants, run separate tools for fitness, folding, synthesis, and cost, and then still have to decide which designs are actually worth ordering. Each physical test costs real money and weeks of time, and most designs fail. We wanted a system that doesn't just rank variants in isolation, but coordinates specialist agents that each evaluate a different part of the design problem, then recommends the most cost-effective set of variants to test, before a single dollar is spent on synthesis.

### What it does

DryRun is a multi-agent AI platform for protein design. You provide a protein sequence, a design goal, and a budget. DryRun runs the sequence through a coordinated pipeline of specialist agents, each owning one decision: Design Generator creates candidate protein variants. Sequence Fitness scores biological plausibility. Fold Risk predicts structural stability and fragile regions. Synthesis Cost estimates manufacturing cost. Portfolio Optimizer selects the best set under budget. Design Council reviews the selected portfolio through stability, function, diversity, synthesis, and budget lenses. Reporting Agent produces a clear final recommendation. In the background, toolbox agents run additional protein and DNA checks: codon optimization, DNA QC, hydropathy, restriction-site scanning, solubility, liability scanning, and thermostability estimation. The result is a report that helps labs avoid wasting money on low-value variants and focus their budget on designs more likely to succeed. The core idea: specialist agents that each own a real decision The strongest part of DryRun is its multi-agent architecture, where each agent owns one specific part of the design problem and contributes real evidence to a shared decision, rather than one model trying to do everything at once. Protein design is genuinely many problems at once: is this variant biologically plausible, will it fold, where is it fragile, what will it cost to manufacture, is it diverse enough to hedge risk, does it have synthesis or solubility liabilities. DryRun gives each of these its own specialist agent. The Design Generator proposes variants, Sequence Fitness scores plausibility, Fold Risk predicts structure and fragile regions, Synthesis Cost prices each construct, and the Portfolio Optimizer selects under budget, while background toolbox agents run codon optimization, DNA QC, hydropathy, solubility, liability, and thermostability checks. Each agent enriches the same shared candidate objects, so dozens of independent signals converge into one coherent recommendation instead of a pile of disconnected outputs. The agents coordinate over the Chat Protocol through Agentverse, every agent is independently discoverable and usable on its own, and the orchestrator routes work between them and recovers gracefully if any single agent fails. This is real agent-to-agent orchestration, not a single script wearing many hats. Sitting at the end of that pipeline, the Portfolio Optimizer turns all of that collected evidence into the actual decision. It is deliberately not a ranker: picking the top variants concentrates risk, because near-identical high-scoring designs tend to share the same hidden flaws and fail together. Instead, DryRun treats selection like building an investment portfolio, choosing a diversified set under budget so failures are decorrelated, maximizing the expected number of successful experiments per dollar rather than the score of any single design.

### How we built it

The backend is Python with a distributed agent architecture built on uAgents. Each specialist agent has its own identity, task, capability, seed, and address, so agents can run locally in one Bureau or separately through Agentverse mailbox mode. The orchestrator receives the user request, calls each specialist over the Chat Protocol, tracks request IDs, collects results, and falls back to an in-process pipeline if any marketplace agent fails. This keeps the system reliable while demonstrating real agent-to-agent coordination. The pipeline is built around a shared candidate model. Each agent enriches the same candidate objects with new evidence: mutations, viability scores, fold confidence, fragile regions, synthesis risk, cost, success probability, and final selection status. This is what lets many agents contribute to one coherent decision instead of producing disconnected outputs. The frontend is Next.js, React, TypeScript, Tailwind CSS, and 3D molecular visualization, designed to feel like a real product: sequence intake, a live run view, candidate detail pages, a molecule studio, and final report surfaces.

### Challenges we ran into

The biggest challenge was coordinating many agents without making the system fragile. If one specialist timed out, an entire run could fail, so we built resilient fallbacks and made background toolbox calls non-blocking. Another was turning complex protein-design signals into something understandable. Fold confidence, synthesis risk, GC content, fragile regions, and expected success only matter if the user can see how they shape the final recommendation. We also had to balance realism and speed. Structure prediction is slow, so DryRun supports configurable fold backends and concurrent folding while keeping the demo responsive. On the frontend, the challenge was clarity over volume. Protein design carries a lot of data, so we focused on the decision funnel: how many variants were generated, filtered, folded, priced, selected, and refined.

### Accomplishments we're proud of

We built a working multi-agent system that connects generation, scoring, folding, synthesis cost, optimization, review, and reporting into one workflow focused on reducing cost and improving success rate, rather than just generating variants. We are especially proud of the Portfolio Optimizer, which chooses a diversified set under budget instead of the top-ranked variants, accounting for the fact that similar designs can fail for the same reason. We are also proud that every agent has one clear responsibility, which is what keeps a system of this many agents reasonable to understand and reliable to run.

### What we learned

We learned that agent systems are most useful when each agent has a clear job. The project became far easier to reason about once every agent did exactly one thing: generate, score, fold, price, optimize, review, or report. We learned that cost is the real bottleneck in scientific AI. A model can suggest hundreds of variants, but labs need to know which experiments are worth paying for, so optimization under budget became the center of the product. And we learned that a good AI interface for a technical domain is not just a chat box. Users need traces, scores, visualizations, comparisons, and clear explanations of why the system reached its recommendation.

### What's next

Make every backend model fully production-grade and reduce real structure-prediction latency. Add richer wet-lab constraints, like vendor-specific synthesis rules. Expand the agent marketplace so researchers can plug in their own specialists, such as antibody developability, enzyme activity, toxicity screening, or assay planning. Validate the predicted cost-and-success improvements against real experimental outcomes. Long term, DryRun could become an AI research operating system for protein engineering: a place where specialized agents collaborate to help labs reduce cost, improve success rate, and choose better experiments.

## README (from the GitHub repository)

# DryRun — decide which protein designs are worth synthesizing, before you pay to build them

**ASI:One Agent Challenge — From Intent to Action**

## The problem, the user, and the outcome

- **Problem.** Wet-lab synthesis is expensive and slow. Teams routinely order DNA
  for protein variants that were never going to work, or pile their whole budget
  into near-duplicate designs that all fail for the same hidden reason. The
  expensive part — structure prediction — gets re-run by every lab independently.
- **Target user.** Protein engineers and synthetic-biology teams deciding *which*
  designs to actually order under a fixed budget.
- **Outcome the agent produces.** From a plain-English goal ("improve heat
  tolerance of this enzyme, budget $1,500, 24 variants"), DryRun returns an
  **executable order list**: the specific, diversified set of designs to
  synthesize, the dollar spend, the expected number of distinct successful
  experiments, and how much better that is than a naive top-ranked buy — produced
  entirely through agent-to-agent orchestration over the Chat Protocol.

## How it works

A natural-language request reaches the **Orchestrator** (the ASI:One entry
point). It parses intent, then runs a pipeline by **messaging six specialist
agents over the Agent Chat Protocol**, and convenes a **Design Council** swarm
(five advisor agents + a moderator) that deliberates over the optimized
portfolio and refines it:

```
intent → Design Generator → Sequence Fitness → Fold Risk → Synthesis Cost
       → Portfolio Optimizer → Design Council (deliberation) → Reporting
```

The intelligence core is the optimizer: it maximizes **expected distinct
successes per dollar** under the budget, penalizing correlated designs so you
buy a decorrelated spread of bets rather than near-duplicates.

## Requirement checklist

| Mandatory requirement | How DryRun meets it |
|---|---|
| Register ≥1 agent on Agentverse | All 13 agents connect via mailbox — see [`backend/AGENTVERSE.md`](backend/AGENTVERSE.md) |
| Implement the Agent Chat Protocol | Every agent uses `chat_protocol_spec` and publishes its manifest (`backend/agents/protocol.py`) |
| Discoverable + usable through ASI:One | Orchestrator publishes a descriptive Chat Protocol manifest; greets on session start and runs the full workflow from a chat message |
| Meaningful tool execution / orchestration | Orchestrator runs a 7-stage pipeline across specialists + a 6-agent deliberation swarm |
| Complete the workflow with no custom frontend | The whole decision report is produced and returned **inside the ASI:One chat** (the Next.js app is optional) |
| Public GitHub repo with run/test instructions | This repo; see **Run & test** below |

**Bonus covered:** multi-agent collaboration (the Council); **Payment Protocol**
monetization on the Fold Risk agent (see [`backend/README.md`](backend/README.md));
reliability — every remote/agent/payment call falls back so a report is always
produced; deterministic, key-free operation so it keeps running after the event.

## Run & test

```bash
cd backend
python -m venv ../.venv && source ../.venv/bin/activate   # Python 3.12
pip install -r requirements.txt

# 1) Local one-process demo (all agents in one Bureau + REST gateway)
python run_all.py
curl -s -X POST http://127.0.0.1:8000/run -H 'Content-Type: application/json' \
  -d '{"goal":"improve heat tolerance, budget $1500, 24 variants","poolSize":24,"budgetUsd":1500}'

# 2) Quick check
python tests/smoke.py
```

To put the agents on Agentverse / ASI:One, follow [`backend/AGENTVERSE.md`](backend/AGENTVERSE.md)
(set `USE_MAILBOX=true`, run `python run_mailbox.py`, connect each mailbox).
The optional web UI lives in `frontend/` (`npm install && npm run dev`).

Everything runs **deterministically with zero API keys**. An optional
`ASI_ONE_API_KEY` enables LLM intent parsing; optional fold backends and the
testnet payment fee are off by default.

## Submission links

- **ASI:One shared chat session:** _add URL_
- **Agentverse agent profile(s):** _add URL(s)_
- **Demo video:** _add URL_
- **GitHub repository:** _this repo_


## Detected evidence (automated analysis)

Indexed codebase: 90 recognized source files, 416 KB.
- CSS (language) — detected in the code
- Hugging Face (technology) — detected in the code
- Next.js (technology) — detected in the code
- OpenAI (technology) — detected in the code
- Python (language) — detected in the code
- PyTorch (technology) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- FastAPI (technology) — claimed on Devpost, not found in the code
- AI coding agent: Claude Code — evidence: config files committed to the repository
- AI coding agent: Codex — evidence: config files committed to the repository
- AI coding agent: Cursor — evidence: commit authorship or trailers

## Codebase structure (from repository index)

### Files (98 of 98)

```
.gitignore
backend/.env.example
backend/agents/__init__.py
backend/agents/codon_optimizer.py
backend/agents/config.py
backend/agents/council_budget.py
backend/agents/council_diversity.py
backend/agents/council_function.py
backend/agents/council_moderator.py
backend/agents/council_stability.py
backend/agents/council_synthesis.py
backend/agents/design_generator.py
backend/agents/dna_qc.py
backend/agents/fold_risk.py
backend/agents/hydropathy.py
backend/agents/intent.py
backend/agents/liability_scanner.py
backend/agents/orchestrator.py
backend/agents/payment.py
backend/agents/portfolio_optimizer.py
backend/agents/protein_properties.py
backend/agents/protocol.py
backend/agents/reporting.py
backend/agents/restriction_scanner.py
backend/agents/sequence_aligner.py
backend/agents/sequence_fitness.py
backend/agents/signal_peptide.py
backend/agents/solubility.py
backend/agents/synthesis_cost.py
backend/agents/thermostability.py
backend/AGENTVERSE.md
backend/core/__init__.py
backend/core/cluster.py
backend/core/cost.py
backend/core/council.py
backend/core/esmfold_nim.py
backend/core/fitness.py
backend/core/fold.py
backend/core/generator.py
backend/core/models.py
backend/core/optimizer.py
backend/core/pdb.py
backend/core/pipeline.py
backend/core/plm.py
backend/core/reporting.py
backend/core/rng.py
backend/core/seq.py
backend/core/toolbox.py
backend/README.md
backend/requirements.txt
backend/run_all.py
backend/run_council_mailbox.py
backend/run_mailbox.py
backend/tests/optimizer_regression.py
backend/tests/pricing_regression.py
backend/tests/smoke.py
backend/tests/sweep.py
docs/superpowers/specs/2026-06-21-real-pipeline-design.md
frontend/.gitignore
frontend/AGENTS.md
frontend/app/api/fold/route.ts
frontend/app/api/run/route.ts
frontend/app/globals.css
frontend/app/layout.tsx
frontend/app/page.tsx
frontend/CLAUDE.md
frontend/components/Brand.tsx
frontend/components/CandidateDetail.tsx
frontend/components/CandidateTable.tsx
frontend/components/ConfidenceTrack.tsx
frontend/components/CostBreakdown.tsx
frontend/components/CostComparison.tsx
frontend/components/Dashboard.tsx
frontend/components/Intake.tsx
frontend/components/MoleculeStudio.tsx
frontend/components/PortfolioComparisonChart.tsx
frontend/components/Report.tsx
frontend/components/RunView.tsx
frontend/components/ScreeningFunnel.tsx
frontend/components/SequenceComparison.tsx
frontend/components/SequenceSpaceMap.tsx
frontend/components/Sidebar.tsx
frontend/components/ui.tsx
frontend/eslint.config.mjs
frontend/lib/format.ts
frontend/lib/mockPdb.ts
frontend/lib/mol3d.ts
frontend/lib/runConstants.ts
frontend/lib/store.ts
frontend/lib/studioMolecule.ts
frontend/lib/types.ts
frontend/lib/utils.ts
frontend/next.config.ts
frontend/package.json
frontend/postcss.config.mjs
frontend/README.md
frontend/tsconfig.json
README.md
```

### Dependencies

- backend/requirements.txt: httpx@>=0.27, numpy@>=1.26, openai@>=1.40, python-dotenv@>=1.0, scikit-learn@>=1.4, torch@>=2.2, transformers@>=4.40, uagents@>=0.25,<0.26, uagents-core@>=0.4,<0.5
- frontend/package.json: @tailwindcss/postcss@^4, @types/node@^20, @types/react@^19, @types/react-dom@^19, clsx@^2.1.1, eslint@^9, eslint-config-next@16.2.9, framer-motion@^12.40.0, lucide-react@^1.21.0, next@16.2.9, react@19.2.4, react-dom@19.2.4, tailwind-merge@^3.6.0, tailwindcss@^4, typescript@^5, zustand@^5.0.14

### Recent commits (newest first)

- Merge pull request #3 from Anthony-Yangg/feat/design-studio-and-ui-overhaul
- Ship real pipeline agents and live UI
- Merge pull request #2 from Anthony-Yangg/feat/design-studio-and-ui-overhaul
- Add Payment Protocol monetization, redesign report UX, and harden ASI:One chat
- Fix agent startup on Python 3.14 by ensuring an asyncio event loop exists.
- Add codon optimization, right-sizing curve, and stronger Design Council.
- Merge pull request #1 from Anthony-Yangg/feat/design-studio-and-ui-overhaul
- Add Molecule Design Studio and improve scoring credibility.
- Initial commit: DryRun protein design pre-screening platform

## Key source files (fetched from GitHub, selected and truncated for size)

### frontend/CLAUDE.md

```markdown
@AGENTS.md

```

### frontend/AGENTS.md

```markdown
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->

```

### backend/requirements.txt

```
# DryRun multi-agent backend (Fetch.ai stack)
uagents>=0.25,<0.26
uagents-core>=0.4,<0.5

# LLM intent parsing / summaries via ASI:One (OpenAI-compatible). Optional —
# the system runs fully deterministic with no key.
openai>=1.40
python-dotenv>=1.0

# HTTP for optional real integrations (Evo2 NIM, ESMFold).
httpx>=0.27

# Real scientific core: ESM-2 protein language model (sequence fitness, variant
# effect scoring, embeddings) and k-means/PCA clustering over those embeddings.
torch>=2.2
transformers>=4.40
numpy>=1.26
scikit-learn>=1.4

```

### frontend/package.json

```
{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint"
  },
  "dependencies": {
    "clsx": "^2.1.1",
    "framer-motion": "^12.40.0",
    "lucide-react": "^1.21.0",
    "next": "16.2.9",
    "react": "19.2.4",
    "react-dom": "19.2.4",
    "tailwind-merge": "^3.6.0",
    "zustand": "^5.0.14"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "^4",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^9",
    "eslint-config-next": "16.2.9",
    "tailwindcss": "^4",
    "typescript": "^5"
  }
}

```

### frontend/app/layout.tsx

```typescript
import type { Metadata } from "next";
import { Inter, Space_Grotesk, JetBrains_Mono } from "next/font/google";
import "./globals.css";

const inter = Inter({
  variable: "--font-inter",
  subsets: ["latin"],
});

const grotesk = Space_Grotesk({
  variable: "--font-grotesk",
  subsets: ["latin"],
  weight: ["400", "500", "600", "700"],
});

const jbMono = JetBrains_Mono({
  variable: "--font-mono-jb",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "DryRun — spend your synthesis budget where it pays off",
  description:
    "DryRun predicts which protein designs will fail before you build them, and picks the smartest, diversified set of designs to fit your budget.",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html
      lang="en"
      className={`${inter.variable} ${grotesk.variable} ${jbMono.variable} h-full antialiased`}
    >
      <body className="min-h-full flex flex-col">{children}</body>
    </html>
  );
}

```

### frontend/app/page.tsx

```typescript
"use client";

import { AnimatePresence, motion } from "framer-motion";
import { useDryRun } from "@/lib/store";
import { Sidebar } from "@/components/Sidebar";
import { Intake } from "@/components/Intake";
import { RunView } from "@/components/RunView";
import { Report } from "@/components/Report";

export default function Home() {
  const { view, report } = useDryRun();
  return (
    <div className="flex h-screen w-full overflow-hidden">
      <Sidebar />
      <main className="min-w-0 flex-1 overflow-y-auto">
        <AnimatePresence mode="wait">
          {view === "intake" && (
            <motion.div key="intake" exit={{ opacity: 0 }}>
              <Intake />
            </motion.div>
          )}
          {view === "running" && (
            <motion.div key="running" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>
              <RunView />
            </motion.div>
          )}
          {view === "report" && report && (
            <motion.div key="report" initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
              <Report report={report} />
            </motion.div>
          )}
        </AnimatePresence>
      </main>
    </div>
  );
}

```

### frontend/app/api/run/route.ts

```typescript
import { NextResponse } from "next/server";

// Server-side proxy to the DryRun orchestrator agent's REST gateway.
// Keeps the browser same-origin (no CORS) and hides the agent URL.
const ORCHESTRATOR_URL =
  process.env.ORCHESTRATOR_URL ?? "http://127.0.0.1:8000";
// The orchestrator may run a real structure predictor (ESMFold) on survivors,
// which can take a few minutes. Keep this comfortably above the agent's own
// per-specialist budget so we don't abort a valid run and fall back to mock.
const RUN_TIMEOUT_MS = Number(process.env.RUN_TIMEOUT_MS ?? "300000");

export async function POST(req: Request) {
  let body: unknown;
  try {
    body = await req.json();
  } catch {
    return NextResponse.json({ error: "invalid json" }, { status: 400 });
  }

  try {
    const res = await fetch(`${ORCHESTRATOR_URL}/run`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
      // agents can take a few seconds (mock) to a few minutes (real ESMFold)
      signal: AbortSignal.timeout(RUN_TIMEOUT_MS),
    });
    if (!res.ok) {
      return NextResponse.json(
        { error: `orchestrator ${res.status}` },
        { status: 502 },
      );
    }
    const data = await res.json();
    return NextResponse.json(data);
  } catch (err) {
    return NextResponse.json(
      { error: `orchestrator unreachable: ${(err as Error).message}` },
      { status: 503 },
    );
  }
}

```

### frontend/app/api/fold/route.ts

```typescript
import { NextResponse } from "next/server";

// Server-side proxy for real protein structure prediction (ESMFold).
// This is OPTIONAL: the Structure tab always works with the synthetic
// structure the pipeline already returns. When a provider is configured
// via env vars, the "Fold real structure" button upgrades the view to a
// predicted structure with per-residue pLDDT in the B-factor column.
//
// Configure in frontend/.env.local (same variable name as backend/.env):
//   NVIDIA_NIM_API_KEY=...                      (NVIDIA-hosted ESMFold NIM)
//   NVIDIA_ESMFOLD_URL=...                      (optional override)
// or
//   ESMFOLD_API_URL=https://api.esmatlas.com/foldSequence/v1/pdb/

const NVIDIA_NIM_API_KEY = process.env.NVIDIA_NIM_API_KEY;
const NVIDIA_ESMFOLD_URL =
  process.env.NVIDIA_ESMFOLD_URL ??
  "https://health.api.nvidia.com/v1/biology/nvidia/esmfold";
const ESMFOLD_API_URL =
  process.env.ESMFOLD_API_URL ?? "https://api.esmatlas.com/foldSequence/v1/pdb/";

const MAX_LEN = 400; // ESMFold hosted endpoints cap sequence length

function cleanSequence(raw: unknown): string | null {
  if (typeof raw !== "string") return null;
  const seq = raw.toUpperCase().replace(/[^A-Z]/g, "");
  if (seq.length < 8) return null;
  return seq;
}

async function foldWithNvidia(seq: string): Promise<string> {
  const res = await fetch(NVIDIA_ESMFOLD_URL, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${NVIDIA_NIM_API_KEY}`,
      "Content-Type": "application/json",
      Accept: "application/json",
    },
    body: JSON.stringify({ sequence: seq }),
    signal: AbortSignal.timeout(110_000),
  });
  if (!res.ok) throw new Error(`nvidia ${res.status}`);
  const data = await res.json();
  const pdb: string | undefined =
    data?.pdbs?.[0] ?? data?.pdb ?? (typeof data === "string" ? data : undefined);
  if (!pdb || !pdb.includes("ATOM")) throw new Error("nvidia: no pdb in response");
  return pdb;
}

async function foldWithEsmAtlas(seq: string): Promise<string> {
  const res = await fetch(ESMFOLD_API_URL, {
    method: "POST",
    headers: { "Content-Type": "text/plain" },
    body: seq,
    signal: AbortSignal.timeout(110_000),
  });
  if (!res.ok) throw new Error(`esmatlas ${res.status}`);
  const pdb = await res.text();
  if (!pdb || !pdb.includes("ATOM")) throw new Error("esmatlas: no pdb in response");
  return pdb;
}

export async function POST(req: Request) {
  let body: unknown;
  try {
    body = await req.json();
  } catch {
    return NextResponse.json({ error: "invalid json" }, { status: 400 });
  }

  const seq = cleanSequence((body as { sequence?: unknown })?.sequence);
  if (!seq) {
    return NextResponse.json({ error: "invalid sequence" }, { status: 400 });
  }
  if (seq.length > MAX_LEN) {
    return NextResponse.json(
      { error: `sequence too long for hosted ESMFold (${seq.length} > ${MAX_LEN})` },
      { status: 413 },
    );
  }

  const providers: { name: string; fn: () => Promise<string> }[] = [];
  if (NVIDIA_NIM_API_KEY) providers.push({ name: "esmfold-nvidia", fn: () => foldWithNvidia(seq) });
  providers.push({ name: "esmfold-esmatlas", fn: () => foldWithEsmAtlas(seq) });

  const errors: string[] = [];
  for (const p of providers) {
    try {
      const pdb = await p.fn();
      return NextResponse.json({ pdb, source: p.name });
    } catch (err) {
      errors.push(`${p.name}: ${(err as Error).message}`);
    }
  }

  return NextResponse.json(
    { error: "fold providers unavailable", detail: errors.join("; ") },
    { status: 502 },
  );
}

```

### frontend/next.config.ts

```typescript
import type { NextConfig } from "next";
import path from "node:path";

const nextConfig: NextConfig = {
  turbopack: {
    root: path.join(__dirname),
  },
};

export default nextConfig;

```

### backend/run_council_mailbox.py

```python
"""Launch the 4 Design Council agents in MAILBOX mode for Agentverse.

Run this if you already have the core 7 agents up via run_mailbox.py, or run it
standalone to start only the council swarm.

    python run_council_mailbox.py

Keep the terminal open while connecting Inspector URLs (Connect -> Mailbox).
"""

from __future__ import annotations

import os
import signal
import subprocess
import sys
import urllib.parse

sys.path.insert(0, os.path.dirname(__file__))

from agents.config import (  # noqa: E402
    COUNCIL_BUDGET,
    COUNCIL_DIVERSITY,
    COUNCIL_FUNCTION,
    COUNCIL_MODERATOR,
    COUNCIL_STABILITY,
    COUNCIL_SYNTHESIS,
)

MODULES = [
    (COUNCIL_STABILITY, "agents.council_stability", COUNCIL_STABILITY.port),
    (COUNCIL_FUNCTION, "agents.council_function", COUNCIL_FUNCTION.port),
    (COUNCIL_DIVERSITY, "agents.council_diversity", COUNCIL_DIVERSITY.port),
    (COUNCIL_SYNTHESIS, "agents.council_synthesis", COUNCIL_SYNTHESIS.port),
    (COUNCIL_BUDGET, "agents.council_budget", COUNCIL_BUDGET.port),
    (COUNCIL_MODERATOR, "agents.council_moderator", COUNCIL_MODERATOR.port),
]


def inspector_url(port: int, address: str) -> str:
    uri = urllib.parse.quote(f"http://127.0.0.1:{port}", safe="")
    return f"https://agentverse.ai/inspect/?uri={uri}&address={address}"


def main():
    env = {**os.environ, "USE_MAILBOX": "true"}

    print("\n  Design Council — connect each mailbox at its Inspector URL")
    print("  (log into agentverse.ai, then Connect -> Mailbox):\n")
    for info, _, port in MODULES:
        print(f"  {info.name}")
        print(f"    {inspector_url(port, info.address)}\n")
    print("  " + "=" * 60 + "\n")

    procs = []
    for _, module, _port in MODULES:
        procs.append(subprocess.Popen([sys.executable, "-m", module], env=env))

    def shutdown(*_):
        for p in procs:
            p.terminate()
        sys.exit(0)

    signal.signal(signal.SIGINT, shutdown)
    signal.signal(signal.SIGTERM, shutdown)
    for p in procs:
        p.wait()


if __name__ == "__main__":
    main()

```

[78 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]