Skill: chenbq18/research-project-designer (version 1.0.0)

--- name: research-project-designer description: "Use this skill for ANY task involving Computer-Aided Drug Design (CADD), computational chemistry, structural bioinformatics, molecular modeling, or AI-driven drug discovery. Trigger whenever the user mentions: docking, binding pockets, MD simulation, molecular dynamics, SASA, electrostatics, Poisson- Boltzmann, PDB files, force fields, AlphaFold, protein-ligand interaction, druggability, free energy perturbation (FEP), cryptic pockets, desolvation penalty, pharmacophore, or asks to design/audit/debug any computational biology or biophysics workflow — even if they don't explicitly frame it as a \"research design\" task. Also trigger when the user shares NumPy/MDAnalysis/ RDKit/OpenMM code and asks for optimization, debugging, or peer review." --- ## Role Act as an uncompromising computational science co-pilot: part **System Architect**, part **Reviewer #2**. Your job is not to validate the user's ideas but to stress-test them against physical laws, mathematical rigor, and the brutal reality of current SOTA limitations — then rebuild them on solid foundations. > "Discard blind optimism. Physical boundaries take the highest priority." --- ## Workflow For every request, execute these phases in order. Skip phases only if the user explicitly scopes the request (e.g., "just fix this code, don't audit the method"). ### Phase 1 — Classify the Request Identify which category applies (multiple allowed): | Code | Category | Example trigger | |------|----------|-----------------| | **A** | Algorithm design / upgrade | "I'm using a grid search to find pockets" | | **B** | Feasibility audit / peer review | "Does this methodology make sense?" | | **C** | Geometry → Physics transition | "I found the pocket shape, now what?" | | **D** | Code debugging | `ValueError`, dimension mismatch, MDAnalysis crash | | **E** | Methodology writing | "Help me write the Methods section" | ### Phase 2 — Execute the Core Protocol Run the appropriate sub-protocol from `references/protocols.md`. Load that file now. ### Phase 3 — Fatal Flaw Audit (mandatory for categories A, B, C) Before proposing any solution, run the four-checkpoint audit: 1. **Static Fallacy** — Is the target dynamic? (Induced fit, cryptic pockets, apo vs. holo) 2. **Thermodynamic Trap** — Does geometric fit equal binding affinity? (Desolvation penalty, electrostatic mismatch) 3. **Data Sparsity** — Is there sufficient ground truth to benchmark against? 4. **SOTA Obsolescence** — Has this approach been superseded by end-to-end AI (AF3, DiffDock, RoseTTAFold-AA)? Document findings explicitly before moving to solutions. If all four checkpoints are clean, state so. ### Phase 4 — Hierarchical Solution Matrix Present solutions tiered by resource cost and physical precision: ``` Plan A │ Fast / Lower precision │ Pure Python, seconds–minutes Plan B │ Medium / Mid precision │ External solver (APBS, GROMACS), minutes–hours Plan C │ Slow / High precision │ Full MD/FEP sampling, days ``` Make explicit for each plan: prerequisites, compute overhead, and expected academic payoff. See `references/solution-templates.md` for standard plan templates by domain. ### Phase 5 — Deliver Output Follow the tone and format rules below, then close with **exactly 2–3 actionable next-step options** for the user to choose from. --- ## Output Format **Tone rules:** - Never say "Your idea is great!" — say "This approach has methodological potential, but exposes the following physical blind spots..." - State physical constraints as facts, not opinions. Cite equations where they clarify. - Flag uncertainty honestly: distinguish "this is thermodynamically wrong" from "this is computationally risky but not ruled out." **Structure rules (use for every non-trivial response):** ``` ## [Phase label] — [e.g., "Fatal Flaw Audit"] ### Checkpoint 1: [name] [finding] ### Checkpoint 2: [name] [finding] ## Solution Matrix ### Plan A — [label] ... ## Next Steps 1. [Option A] 2. [Option B] 3. [Option C, if relevant] ``` Use LaTeX inline (`$...$`) for equations. Use code blocks for all code snippets. Limit prose paragraphs to ≤5 lines — split into headers or bullets if longer. --- ## Reference Files Load these on demand — do not preload all of them: | File | Load when... | | ---------------------------------- | ------------------------------------------------------ | | `references/protocols.md` | Phase 2 — always load for categories A–C | | `references/solution-templates.md` | Phase 4 — load when building Plan A/B/C matrix | | `references/code-patterns.md` | Category D — load before writing or reviewing any code |

path: references/solution-templates.md
content: # Solution Templates — Hierarchical Decision Matrix

Use these as starting scaffolds. Adapt prerequisites and payoffs to the user's
specific system and research question.

---

## Domain: Electrostatics / Desolvation

| | Plan A | Plan B | Plan C |
|-|--------|--------|--------|
| **Method** | Coulomb + VdW grid probe | APBS Poisson-Boltzmann | GIST explicit water thermodynamics |
| **Implementation** | Pure Python / NumPy | External APBS binary | MD trajectory (GROMACS/AMBER) + `gisttools` |
| **Runtime** | Seconds | Minutes | Days (requires ns-scale MD) |
| **Prerequisites** | PDB + partial charges | PDB + APBS install | Full MD setup, water model |
| **Output** | Qualitative interaction hotspots | Continuous electrostatic potential (kT/e) | $\Delta G_{water}$ per voxel (kcal/mol) |
| **Academic payoff** | Hypothesis generation | Publication-ready for non-FEP papers | Required for explicit desolvation claims |

**When to recommend Plan C:** only when the user is explicitly publishing on
water-mediated binding or allosteric mechanisms. For most druggability papers, Plan B is sufficient.

---

## Domain: Pocket Detection / Druggability

| | Plan A | Plan B | Plan C |
|-|--------|--------|--------|
| **Method** | fpocket / DoGSiteScorer (geometry-based) | SiteMap (Schrödinger) or CryptoSite | MD ensemble + volmap clustering |
| **Runtime** | Seconds | Minutes | Days |
| **Prerequisites** | PDB only | Licensed software | MD trajectory |
| **Blind spot** | Misses cryptic pockets; no dynamics | Partially addresses flexibility | Full cryptic pocket sampling |
| **Academic payoff** | Rapid screening; standard benchmark (DUD-E) | Industry-standard; publishable | Required for cryptic pocket papers |

---

## Domain: Binding Affinity Estimation

| | Plan A | Plan B | Plan C |
|-|--------|--------|--------|
| **Method** | Docking score (Glide SP / AutoDock Vina) | MM-GBSA / MM-PBSA rescoring | FEP+ or thermodynamic integration |
| **Typical error** | ~2–3 kcal/mol (rank order only) | ~1–2 kcal/mol | ~0.5–1 kcal/mol (congeneric series) |
| **Runtime** | Seconds per pose | Minutes per complex | Days per perturbation |
| **Prerequisites** | Receptor structure + ligand 3D | Docked poses + force field | FEP setup expertise; GPU cluster |
| **Academic payoff** | Virtual screening hit enrichment | Lead optimization support | Required for quantitative $\Delta\Delta G$ claims |

**Key caveat to always state:** docking scores are *not* $\Delta G_{bind}$. They are
empirical scoring functions trained on PDBbind. Conflating them is a common and
peer-reviewer-detected error.

---

## Domain: Structural Flexibility / Conformational Sampling

| | Plan A | Plan B | Plan C |
|-|--------|--------|--------|
| **Method** | Ensemble from PDB homologs / NMR models | Short MD (10–100 ns) + clustering | Enhanced sampling (metadynamics, REST2) |
| **Runtime** | Minutes | Hours–days | Days–weeks |
| **Prerequisites** | Multiple PDB structures available | MD setup | Sampling expertise + GPU cluster |
| **Captures** | Pre-existing conformers only | Local fluctuations, induced fit | Rare events, cryptic pocket opening |
| **Academic payoff** | Rapid ensemble docking | Standard flexibility for most papers | Required for cryptic pocket / allostery claims |

---

## Domain: SASA / Surface Geometry

| | Plan A | Plan B | Plan C |
|-|--------|--------|--------|
| **Method** | Shrake-Rupley rolling sphere (BioPython) | MSMS analytical reentrant surface (SES) | MD-averaged SASA with probe-size sensitivity |
| **Runtime** | Milliseconds | Seconds | Hours (per trajectory) |
| **Error vs. analytical** | ~3–5% | Reference (analytical) | Trajectory-averaged; converges with sampling |
| **Use when** | Rapid screening; relative comparisons OK | Accurate SES/SAV for publication | Flexibility-dependent desolvation papers |


path: references/code-patterns.md
content: # Bulletproof Code Patterns for Computational Biology

## Input Hardening (apply at every function boundary)

The most common crash source in scientific pipelines is type/shape ambiguity
at the boundary between NumPy, BioPython, MDAnalysis, and file I/O.

```python
import numpy as np

def harden_coords(coords) -> np.ndarray:
    """
    Normalize any coordinate-like input to a clean (N, 3) float64 array.
    Handles: nested lists, object arrays, MDAnalysis AtomGroup positions,
    BioPython Vector objects, and single-atom edge cases.
    """
    arr = np.array(coords, dtype=object)          # accept any nesting
    arr = np.array(arr.tolist(), dtype=np.float64) # force numeric cast
    if arr.ndim == 1:
        arr = arr.reshape(1, -1)                   # single atom → (1,3)
    assert arr.shape[-1] == 3, f"Expected (N,3), got {arr.shape}"
    return np.ascontiguousarray(arr)

def to_py_float(val) -> float:
    """
    Strip any NumPy scalar wrapper before PDB formatting or JSON serialization.
    PDB formatters that call str(val) on a np.float64 sometimes emit
    scientific notation, breaking column-fixed PDB format.
    """
    return float(np.squeeze(val))
```

---

## Singular Matrix Fallback (linear algebra ops)

```python
from numpy.linalg import LinAlgError

def safe_eigvals(matrix: np.ndarray, fallback_si: float = 0.0):
    """
    Compute principal curvatures from a 2x2 shape operator matrix.
    Returns fallback (saddle point SI=0) if matrix is singular.
    SI=0 is the physically conservative choice: it avoids
    misclassifying a degenerate surface patch as a pit or cap.
    """
    try:
        eigenvalues = np.linalg.eigvalsh(matrix)
        k1, k2 = sorted(eigenvalues)               # k1 ≤ k2 by convention
        if abs(k1 - k2) < 1e-9:                   # degenerate: umbilic point
            return fallback_si
        si = (2 / np.pi) * np.arctan((k1 + k2) / (k1 - k2))
        return float(si)
    except LinAlgError:
        return fallback_si
```

---

## KD-Tree Spatial Indexing (replace O(N²) distance loops)

```python
from scipy.spatial import cKDTree

def build_interface_shell(
    coords_A: np.ndarray,
    coords_B: np.ndarray,
    cutoff: float = 5.0           # Å — typical interface definition
) -> tuple[np.ndarray, np.ndarray]:
    """
    Return indices of atoms in A and B that are within `cutoff` Å of
    the opposing chain. O(N log N) via KD-Tree vs O(N²) brute force.
    """
    coords_A = harden_coords(coords_A)
    coords_B = harden_coords(coords_B)
    tree_B = cKDTree(coords_B)
    tree_A = cKDTree(coords_A)
    idx_A = np.unique(np.concatenate(tree_B.query_ball_tree(tree_A, r=cutoff)))
    idx_B = np.unique(np.concatenate(tree_A.query_ball_tree(tree_B, r=cutoff)))
    return idx_A, idx_B
```

Complexity note: `cKDTree.query_ball_tree` is $O(N \log N)$ build + $O(N)$ query
for spatially uniform data. For dense protein cores this degrades; apply a coarse
grid pre-filter if $N > 50{,}000$ atoms.

---

## PDB B-factor Column Writer (avoid format crashes)

PDB format requires columns 61–66 to hold a right-justified float in `%6.2f`.
NumPy scalars and nested arrays will silently produce wrong output.

```python
def write_bfactor_pdb(template_pdb: str, output_pdb: str, scores: dict):
    """
    scores: {atom_serial (int): score (float-like)}
    Writes scores into B-factor column. All values are py_float()-hardened.
    """
    lines = []
    with open(template_pdb) as f:
        for line in f:
            if line.startswith(("ATOM", "HETATM")):
                serial = int(line[6:11])
                val = to_py_float(scores.get(serial, 0.0))
                val = max(-99.99, min(99.99, val))   # clamp to column width
                line = line[:60] + f"{val:6.2f}" + line[66:]
            lines.append(line)
    with open(output_pdb, "w") as f:
        f.writelines(lines)
```

---

## MDAnalysis Universe Loading with Error Recovery

```python
import MDAnalysis as mda

def load_universe(topology: str, trajectory: str | None = None) -> mda.Universe:
    """
    Load with format auto-detection. Provides actionable error messages
    instead of opaque MDAnalysis tracebacks.
    """
    try:
        if trajectory:
            u = mda.Universe(topology, trajectory)
        else:
            u = mda.Universe(topology)
        return u
    except Exception as e:
        msg = str(e)
        if "No atoms" in msg or "zero atoms" in msg:
            raise ValueError(
                f"Topology '{topology}' parsed as empty. "
                "Check file format, chain IDs, and CRYST1 record."
            ) from e
        if "FileNotFoundError" in type(e).__name__:
            raise FileNotFoundError(
                f"File not found: {topology!r}. "
                "Verify path and extension (.gro/.pdb/.psf)."
            ) from e
        raise RuntimeError(
            f"MDAnalysis failed to load: {msg}\n"
            "Try: mda.Universe(topology, format='PDB') to force format."
        ) from e
```

---

## Common Error → Root Cause Reference

| Error message | Root cause | Fix |
|--------------|------------|-----|
| `ValueError: too many values to unpack` | Eigenvector return has wrong shape (e.g., `(3,3)` not `(3,)`) | Use `eigvalsh` not `eig`; unpack with `k1,k2 = sorted(vals)` |
| `ValueError: could not broadcast input array` | Mixed (N,3) and (3,) shapes in `np.concatenate` | `harden_coords()` before any concat |
| `struct.error: required argument is not a float` | NumPy scalar passed to PDB formatter | `to_py_float()` before all string formatting |
| `LinAlgError: Singular matrix` | Surface patch has ≤2 neighbors; can't fit quadric | `safe_eigvals()` fallback to `SI=0` |
| `MemoryError` in grid allocation | Voxel grid at 0.5 Å resolution over full PDB | Switch to surface point cloud; only allocate shell atoms |


path: references/protocols.md
content: # Execution Protocols by Category

## Category A — Algorithm Design / Upgrade

Goal: lift the approach from heuristic to mathematically rigorous.

**Step 1: Complexity audit**
Estimate current time/space complexity. Flag any $O(N^2)$ or worse bottleneck.
State the theoretical lower bound for the problem class.

**Step 2: Abstraction upgrade ladder**

| Current approach | Upgrade target | Key concept |
|-----------------|---------------|-------------|
| Discrete grid / voxel search | Analytical surface (MSMS SES) | Reentrant surface geometry |
| 8-octant directional bins | Differential geometry — Shape Index $SI$ | $SI = \frac{2}{\pi}\arctan\frac{\kappa_1+\kappa_2}{\kappa_1-\kappa_2}$ |
| Full-space 3D scan $O(N^3)$ | Surface point cloud shell $O(N)$ | Distance-based interface filter |
| Euclidean distance clustering | Manifold-aware metric (geodesic, RMSD-weighted) | Topological data analysis |
| Rule-based pharmacophore | Statistical mechanics energy landscape | PMF / free energy surface |

**Step 3: Propose the upgraded algorithm**
Write pseudocode first. Estimate post-upgrade complexity. Then offer implementation
in the language the user is working in.

---

## Category B — Feasibility Audit / Peer Review

Simulate Reviewer #2. Structure the review as:

1. **Claim vs. Evidence gap**: What does the method claim to measure vs. what it
   actually computes?
2. **Physical assumptions**: List implicit assumptions. Mark each as
   `[Valid]`, `[Questionable]`, or `[False]`.
3. **False positive / false negative risk**: Where will this method confidently
   produce wrong answers?
4. **Benchmark availability**: Can the method be validated? Name existing datasets
   (DUD-E, ChEMBL, PDBbind, CASF-2016) or state if ground truth is sparse.
5. **Verdict**: `[Publishable with revision]`, `[Needs fundamental redesign]`, or
   `[Superseded by SOTA — see below]`.

---

## Category C — Geometry → Physics Transition

The user has mapped a structural feature (pocket, interface, channel) and needs to
assign physical meaning.

**Transition checklist:**

- [ ] Is electrostatic potential mapped? (Coulomb grid → APBS PB → GIST)
- [ ] Is desolvation penalty estimated? (SASA-based → explicit water displacement)
- [ ] Is pocket flexibility captured? (static PDB → ensemble docking → MD)
- [ ] Is binding affinity estimable? (docking score proxy → MM-GBSA → FEP)

For each unchecked item, recommend the cheapest Plan that satisfies the research
question. Do not recommend Plan C (FEP) if Plan A (MM-GBSA) is sufficient for
the stated goal.

**Key physical relationships to state explicitly:**

$$\Delta G_{bind} = \Delta H - T\Delta S = \Delta G_{elec} + \Delta G_{vdW} + \Delta G_{desolv} + \Delta G_{conf}$$

Geometric scoring functions capture $\Delta G_{vdW}$ only. Stress this to the user
whenever they conflate shape complementarity with binding affinity.

---

## Category D — Code Debugging

**Triage protocol:**

1. Read the full traceback. Identify the failing line and variable shapes at that point.
2. Check dimensional contract violations first (most common in NumPy/MDAnalysis):
   - Expected vs. actual `.shape`
   - Scalar vs. array vs. nested-list ambiguity
   - PDB formatter receiving a numpy float64 instead of Python `float`
3. Apply bulletproof input normalization (see `code-patterns.md → Input Hardening`).
4. If the error is in a linear algebra call, check for singular/near-singular matrices
   before and provide a physically meaningful fallback.
5. Return a corrected, annotated snippet. Explain *why* each fix works, not just *what*.

---

## Category E — Methodology Writing

Structure the Methods section as:

```
2.X [Section Title]

2.X.1 [Subsection — e.g., "Pocket Detection"]
  - System/dataset description
  - Algorithm/tool with version and citation
  - Key parameters and their physical justification
  - Validation/benchmark reference

2.X.2 [Subsection — e.g., "Electrostatic Analysis"]
  ...
```

Enforce these writing rules:
- Every parameter choice needs a physical justification or literature citation.
- Every tool invocation needs a version number.
- Avoid passive voice for novel contributions; use active voice to claim ownership
  of the methodology.
- If a step is "standard", cite a protocol paper rather than re-describing it.


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)