Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,43 @@
__pycache__/
*.py[cod]
.DS_Store

# Fetched structures and maps (keep the repo free of downloaded data)
AF-*.pdb
AF-*.cif
AF-*_pae.json
*.pdb
*.cif
*.mmcif
*.bcif
*.ent
*.map
*.mrc
*.mrcs
*.ccp4
!tests/fixtures/*.pdb
!tests/fixtures/*.cif

# Rendered output and movies (host large media externally, not in-repo)
*.mp4
*.mov
*.gif
*.webm
/*.png
/scripts/*.png
banners/

# Sequences and model weights
*.fasta
*.fa
*.fastq
*.pt
*.pth
*.npy
*.npz

# Secrets
*.pem
*.key
.env
.env.*
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Changelog

## Unreleased

- Added `chimerax_rest.py`: a managed ChimeraX REST renderer that launches a GUI
session on an ephemeral port, renders via GPU, defeats the 0-byte-PNG save
race, and guarantees teardown.
- Added headless turntable movies (`pymol_agent.py spin` and `chimerax_rest.py
spin`): ray-traced frames encoded with ffmpeg, degrading gracefully when
ffmpeg is absent.
- Added render presets (`--preset publication|illustration|soft`) and pLDDT
confidence coloring (`--color plddt`) to `pymol_agent.py render`.
- Added `add_helix_records.py`: inject HELIX records into CA-only backbones so
cartoons render for de-novo designs.
- Added `map_info.py`: MRC/CCP4 map inspection with sigma-based contour levels.
- Documented six new gotchas (rendering, animation, and cryo-EM maps) and added
turntable, managed-REST, density-map, and exploded-comparison recipes.
- Added ffmpeg detection to `proteus_doctor.py` and hardened `.gitignore`
against accidentally committing structures, maps, and rendered media.

## v0.1.0 - Public Launch

- Added the core Proteus structural biology agent skill.
Expand Down
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,14 @@ Rosetta-oriented protein design guidance without building a custom plugin.

## What It Provides

- **17 documented gotchas** for PyMOL, ChimeraX, and AlphaFold DB — hard-won from real debugging
- Tool detection for PyMOL and ChimeraX across macOS and Linux installs
- Headless PyMOL rendering for publication-quality structure figures
- **23 documented gotchas** for PyMOL, ChimeraX, AlphaFold DB, rendering, and cryo-EM maps — hard-won from real debugging
- Tool detection for PyMOL, ChimeraX, and ffmpeg across macOS and Linux installs
- Headless PyMOL rendering for publication-quality structure figures, with publication/illustration/soft presets and pLDDT coloring
- Headless turntable movies (PyMOL ray-traced frames + ffmpeg), degrading gracefully when ffmpeg is absent
- Managed ChimeraX REST rendering — launches a GUI session, renders via GPU, defeats the 0-byte-PNG save race, and tears down cleanly
- ChimeraX analysis helpers for alignment, SASA, and hydrogen-bond workflows
- HELIX-record injection for CA-only backbones (RFdiffusion / Genie designs) so cartoons render correctly
- MRC/CCP4 map inspection with sigma-based contour-level suggestions
- AlphaFold DB fetch with confidence interpretation and pLDDT coloring
- RCSB PDB fetch for experimental coordinates, metadata, and biological assembly mmCIF
- UniProt lookup for resolving gene/protein names before AlphaFold fetches
Expand Down Expand Up @@ -160,7 +164,11 @@ python3 scripts/validation_report.py 4HHB --json # wwPDB valid
python3 scripts/pocket_report.py 1HSG --json # ligand-pocket contacts
python3 scripts/resolve_structure.py TP53 --json # one-command resolver
python3 scripts/pymol_agent.py render structure.pdb output.png # headless render
python3 scripts/pymol_agent.py spin structure.pdb spin.mp4 # turntable movie (needs ffmpeg)
python3 scripts/chimerax_agent.py align reference.pdb mobile.pdb # structure alignment
python3 scripts/chimerax_rest.py render structure.pdb out.png # GPU render via managed REST
python3 scripts/add_helix_records.py model.pdb --json # fix CA-only backbone cartoons
python3 scripts/map_info.py map.mrc --json # cryo-EM contour levels
```

## Layout
Expand All @@ -178,10 +186,13 @@ proteus/
│ ├── pymol.md
│ └── rosetta.md
└── scripts/ # Agent helper scripts (all stdlib-only)
├── add_helix_records.py
├── chimerax_agent.py
├── chimerax_rest.py
├── compare_structures.py
├── fetch_pdb.py
├── fetch_alphafold.py
├── map_info.py
├── pae_report.py
├── pdb_info.py
├── pocket_report.py
Expand Down
76 changes: 74 additions & 2 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,11 @@ debugging, patching, or the help text is insufficient for the task.
| `scripts/validation_report.py` | Fetch wwPDB/RCSB validation quality metrics | `python3 scripts/validation_report.py 4HHB --json` |
| `scripts/pocket_report.py` | Zero-dep ligand pocket contacts from PDB/PDB ID | `python3 scripts/pocket_report.py 1HSG --json` |
| `scripts/compare_structures.py` | PyMOL CE alignment + optional per-residue deviations | `python3 scripts/compare_structures.py ref.pdb mobile.pdb --json` |
| `scripts/pymol_agent.py` | Headless PyMOL driver | `python3 scripts/pymol_agent.py info structure.pdb` |
| `scripts/chimerax_agent.py` | Headless ChimeraX driver | `python3 scripts/chimerax_agent.py run "open 1ubq; info chains #1"` |
| `scripts/pymol_agent.py` | Headless PyMOL driver (info, render, **spin movie**) | `python3 scripts/pymol_agent.py render structure.pdb out.png --color plddt` |
| `scripts/chimerax_agent.py` | Headless ChimeraX driver (analysis, `--nogui`) | `python3 scripts/chimerax_agent.py run "open 1ubq; info chains #1"` |
| `scripts/chimerax_rest.py` | Managed ChimeraX REST GUI render (GPU) + turntable | `python3 scripts/chimerax_rest.py render structure.pdb out.png --color plddt` |
| `scripts/add_helix_records.py` | Add HELIX records to CA-only backbones so cartoons render | `python3 scripts/add_helix_records.py model.pdb --json` |
| `scripts/map_info.py` | MRC/CCP4 map stats + sigma-based contour levels | `python3 scripts/map_info.py map.mrc --json` |
| `scripts/pdb_info.py` | Legacy zero-dep PDB inspector (PDB only) | `python3 scripts/pdb_info.py structure.pdb` |

## Critical Gotchas (Read This First)
Expand Down Expand Up @@ -204,6 +207,38 @@ can skip by knowing them upfront.
(polyubiquitin-C, 685 residues) instead. Note: this is the full
polyubiquitin chain, not the 76-residue monomer.

### Rendering, Animation & Maps

18. **PyMOL spin loops need `set cache_frames, 0`.** Otherwise PyMOL caches
every ray-traced frame in RAM and the process is OOM-killed partway through
a turntable. Set it before the render loop. (`pymol_agent.py spin` does this
for you.)

19. **`set auto_zoom, 0` before loading when composing a manual view.** Each
`load`/`show` otherwise re-zooms and fights your `orient`/`zoom`/`turn`
framing. Set it first, frame last.

20. **Whole-map isosurfaces stall in headless PyMOL.** The headless build lacks
the VTKm accelerator, so contouring a full density map can hang for minutes
even on a small map. Carve the mesh around the model
(`isomesh m, map, level, sele, carve=2.5`) or do the whole-map surface in
ChimeraX. Use `scripts/map_info.py` to pick a sigma-based contour level.

21. **ChimeraX REST `save` can return before the PNG is flushed** — a 0-byte
file, worse under heavy cartoon recompute. After `save`, issue `wait 1` and
poll the file for non-zero size, retrying a few times.
(`scripts/chimerax_rest.py` handles this.)

22. **ChimeraX color-name traps.** `gold`/`yellow` atom spheres often render
visibly green — use `orange` for a true gold read. And `color #1 cartoons #...`
silently mis-parses `cartoons` as a color: the command is `cartoon`, then
`color #1 <color>`.

23. **Deposited coordinates are the asymmetric unit, not necessarily the
biological assembly.** A "dimer" entry may deposit a single chain. Build the
functional oligomer with ChimeraX `sym #1 assembly 1 copies true`, or expand
crystal neighbors in PyMOL with `symexp mate_, obj, sele, 5`.

## Common Workflows

### Quick Structure Inspection
Expand Down Expand Up @@ -273,6 +308,39 @@ ray 1200, 900
png output.png
```

Render presets are also available on the helper: `pymol_agent.py render file.pdb
out.png --preset publication|illustration|soft --color spectrum|chain|bfactor|plddt`.

### Turntable Movie (Headless)
```bash
# PyMOL ray-traces each frame (works with no display); ffmpeg encodes them.
python3 scripts/pymol_agent.py spin structure.pdb spin.mp4 --frames 60 --color plddt
# Degrades gracefully: with no ffmpeg, the frames are written and returned.
```
This is the macOS-correct path — ChimeraX needs a GPU/GUI context to render.

### ChimeraX GPU Rendering (Managed REST)
```bash
# Launches a GUI ChimeraX on an ephemeral port, renders via GPU, tears down.
python3 scripts/chimerax_rest.py render structure.pdb out.png --style surface --color bychain
python3 scripts/chimerax_rest.py spin structure.pdb out.mp4 --frames 72
```
Unlike `chimerax_agent.py` (analysis only, `--nogui`), this renders images and
defeats the 0-byte-PNG save race (gotcha 21).

### CA-only Backbone (de-novo designs)
```bash
# RFdiffusion / Genie backbones render as spaghetti without HELIX records.
python3 scripts/add_helix_records.py model.pdb -o model_ss.pdb --json
# Then render model_ss.pdb; in PyMOL also: set cartoon_trace_atoms, 1
```

### Cryo-EM Contour Level
```bash
# Sigma-based level for `volume`/`isomesh` (absolute level differs per map).
python3 scripts/map_info.py map.mrc --json # -> suggested_level at 1/1.5/2/3 sigma
```

## Good Demo Proteins

| UniProt / PDB | Protein | Good for |
Expand Down Expand Up @@ -326,6 +394,10 @@ For multi-step workflows, write a summary JSON report at the end with:
| Compare two structures | `python3 scripts/compare_structures.py ref.pdb mobile.pdb --per-residue --json` |
| Get structure info via PyMOL | `python3 scripts/pymol_agent.py info file.pdb` |
| Render a structure headless | `python3 scripts/pymol_agent.py render file.pdb out.png` |
| Render a turntable movie | `python3 scripts/pymol_agent.py spin file.pdb out.mp4` |
| Render via ChimeraX GPU (REST) | `python3 scripts/chimerax_rest.py render file.pdb out.png` |
| Fix a CA-only backbone for cartoons | `python3 scripts/add_helix_records.py model.pdb` |
| Pick a cryo-EM contour level | `python3 scripts/map_info.py map.mrc --json` |
| Fetch an AlphaFold prediction | `python3 scripts/fetch_alphafold.py UNIPROT_ID --pae --json` |
| Align two structures (ChimeraX) | `python3 scripts/chimerax_agent.py align ref.pdb mobile.pdb` |
| Measure SASA | `python3 scripts/chimerax_agent.py sasa file.pdb` |
Expand Down
41 changes: 41 additions & 0 deletions references/chimerax.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,34 @@ except Exception:
curl "http://127.0.0.1:50888/run?command=remotecontrol+rest+stop"
```

### Managed rendering with `chimerax_rest.py`

`scripts/chimerax_rest.py` packages the full lifecycle so you don't manage the
process by hand: it launches a GUI ChimeraX on an ephemeral port (parallel-safe),
polls `version` until ready, drives commands over HTTP with JSON-envelope error
detection (`json true` surfaces command-level failures even on HTTP 200), and
guarantees teardown.

```bash
python3 scripts/chimerax_rest.py render structure.pdb out.png --color plddt
python3 scripts/chimerax_rest.py spin structure.pdb out.mp4 --frames 72
python3 scripts/chimerax_rest.py run "open 1ubq from pdb; cartoon; color bychain"
```

**The 0-byte-PNG save race.** REST `save` can return HTTP 200 before the GL
framebuffer is flushed, leaving a 0-byte file (worse under heavy cartoon
recompute). After `save`, issue `wait 1` and poll the output file for non-zero
size, retrying the save a few times:

```python
cx_run("wait 1")
cx_run(f"save {png} width 1200 height 900 supersample 3")
for _ in range(16):
if os.path.exists(png) and os.path.getsize(png) > 0:
break
time.sleep(0.5)
```

**CRITICAL: ChimeraX is NOT thread-safe.** Sending REST calls from Python
background threads causes `EXC_BAD_ACCESS` crashes on macOS. All REST calls
must happen from the main thread. If you need concurrency, use `asyncio`
Expand Down Expand Up @@ -215,6 +243,14 @@ open 21924 from emdb # Cryo-EM density map
directory when launched via subprocess may differ from yours, and unquoted paths
with spaces or semicolons can break command parsing.

**Asymmetric unit vs biological assembly.** Deposited coordinates are the
asymmetric unit, which is not always the functional oligomer (a "dimer" entry may
deposit one chain). Build the biological assembly explicitly:

```
sym #1 assembly 1 copies true # generate biological assembly 1
```

### Visualization
```
cartoon # Show cartoon ribbon
Expand All @@ -230,6 +266,11 @@ transparency #1 50 # 50% transparent
transparency #1 50 target c # Cartoon only (target: c=cartoon, s=surface, a=atoms)
```

**Color-name traps.** `gold`/`yellow` atom spheres often render visibly green —
use `orange` for a true gold read. And `color #1 cartoons #...` silently
mis-parses `cartoons` as a (missing) color name: the command is `cartoon`, then
`color #1 <color>` as separate steps.

### Presets
```
preset interactive # Quick visualization
Expand Down
60 changes: 60 additions & 0 deletions references/pymol.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,20 @@ result = cmd.cealign("target", "mobile") # NOTE: target FIRST, mobile SECOND
**Critical:** `cealign` argument order is **(target, mobile)** — the first argument
stays fixed, the second gets moved. This is opposite to `align` and `super`.

### Exploded side-by-side comparison

To show two structures as an unambiguous before/after panel, superpose them, then
move *only one object* aside with `camera=1` (so the shift is in screen space):

```python
cmd.super("design and name CA", "reference and name CA") # CA-only overlay
cmd.translate([22, 0, 0], object="design", camera=1) # pull one copy aside
cmd.rotate("y", 22, object="design", camera=1) # tilt it for depth
```

`camera=1` moves the object relative to the camera, not its own frame, so the
anchored structure stays put while the moved one reads as a separate panel.

## Measurement & Analysis

```
Expand Down Expand Up @@ -256,6 +270,52 @@ center selection # Center on selection
turn y, 45 # Rotate 45 degrees around Y
```

**`set auto_zoom, 0` first when you compose a manual view.** Otherwise each
`load`/`show` re-zooms and fights your `orient`/`zoom`/`turn` framing. Set it
before loading, frame last.

## Turntable Movies & Animation

PyMOL ray-traces each frame headlessly; ffmpeg encodes them. `pymol_agent.py spin`
packages this, but the core loop is:

```python
cmd.set("cache_frames", 0) # CRITICAL: else every frame is cached in RAM -> OOM
cmd.orient()
n = 60
for i in range(n):
cmd.ray(800, 600)
cmd.png(f"/tmp/frames/frame_{i:04d}.png")
cmd.turn("y", 360.0 / n)
```

Then encode (web-playable MP4, even dimensions, faststart):

```bash
ffmpeg -y -framerate 30 -i /tmp/frames/frame_%04d.png \
-c:v libx264 -crf 18 -pix_fmt yuv420p -movflags +faststart \
-vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" spin.mp4
```

`cmd.turn` after `cmd.orient()` rotates about the scene center, so the molecule
spins in place instead of drifting across the frame.

## Density Maps (PyMOL)

```python
# Simulate density from a model when you have no experimental map
cmd.map_new("sim_map", "gaussian", 1.0, "struct", 5)
cmd.isomesh("dens", "sim_map", 1.0, "struct", carve=2.5)

# Show an experimental map carved around the model (fast + local)
cmd.isomesh("dens", "emd_map", level, "struct", carve=2.5)
```

**Carve density around the model** (`carve=2.5`). Contouring a *whole* map is slow
and can hang in headless PyMOL (the headless build lacks the VTKm accelerator) —
do whole-map surfaces in ChimeraX instead. Use `scripts/map_info.py` to choose a
sigma-based contour level (absolute levels differ per map).

## Publication Settings

Standard block for high-quality renders:
Expand Down
Loading