Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Given a PDB structure, produce a per-residue annotation table: which residues sit at a binding interface (vs a partner chain), which line a ligand pocket, which are buried (core) vs solvent-exposed (surface), and optionally secondary structure. This is the structural track drawn under a DMS heatmap and the structural prior SAE feature drops are read against. Use when you need to anchor a variant-interpretation or DMS analysis to the protein's actual physical context.
.claude/skills/tooluniverse-protein-structural-annotation-pdb/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-18 | ✗→✓ | ▲ Improved | — | — |
| case-23 | ✗→✓ | ▲ Improved | — | — |
| case-05 | ✗→✓ | ▲ Improved | — | — |
| case-12 | ✗→✓ | ▲ Improved | — | — |
| case-17 | ✗→✓ | ▲ Improved | — | — |
For each residue of a target protein chain, classify whether it sits at a binding interface, in a ligand pocket, is buried vs solvent-exposed, and (optionally) which secondary-structure element it belongs to. This is the annotation track that anchors any DMS heatmap or per-residue interpretation to the protein's actual physical context.
in the core — context that often distinguishes plausible mechanisms
(a feature drop at a ligand-pocket residue means something different from a drop at a surface residue)
Not for:
tooluniverse-computational-biophysics
tool (e.g. SwissDock) or PDBe's pre-computed pockets
| Input | Format | Example | |---|---|---| | PDB ID | 4 characters | 6VJJ (KRAS-RAF1-GTP analogue) | | Target chain | single character | A | | Partner chain(s) | list of chain IDs | ["B"] | | Ligand resnames | 3-letter PDB names | ["GNP", "MG"] |
Optional:
distance_cutoff (default 5.0 Å)core_rsa_cutoff (default 0.25)include_secondary_structure (default false; uses PDBe REST if true)pdb_content instead of pdb_id for local / predicted structuresIf you only have a UniProt accession or gene symbol, pick a structure first:
python# PDBe's curated UniProt→PDB mapping (recommended; ranks by coverage + resolution) PDBeSIFTS_get_best_structures(uniprot_accession="P01116") # Returns a ranked list of PDB IDs for KRAS with chain mapping # Or full list (unranked) PDBeSIFTS_get_all_structures(uniprot_accession="P01116") # RCSB advanced search (free-text, when you don't have a UniProt yet) RCSBAdvSearch_search_structures(query="KRAS GTP complex")
Pick the structure that contains the right complex: include the binding partner chain you care about, the relevant ligand, and a resolution adequate for distance-based classification (≤ 3 Å is a safe default).
pythonStructure_annotate_per_residue( pdb_id="6VJJ", target_chain="A", partner_chains=["B"], ligand_resnames=["GNP", "MG"], distance_cutoff=5.0, core_rsa_cutoff=0.25, include_secondary_structure=False, )
Returns annotations: List[{position, aa, dist_partner, dist_ligand, rsa, region, is_core, ss_element?}] for every residue of the target chain. For KRAS in 6VJJ, this yields 168 rows.
PDB residue numbers carry silent offsets — crystal constructs add N-terminal cloning residues, and published figures sometimes shift the track relative to the panel sequence. Always verify with a landmark:
python# Get the canonical reference sequence UniProt_get_sequence_by_accession(accession="P01116") # Then spot-check: KRAS canonical position 12 should be glycine assert annotations[11]["aa"] == "G" # 1-indexed position 12, 0-indexed index 11
If the landmark mismatches, record the offset explicitly (e.g. pdb_pos = uniprot_pos + offset) before any downstream join. Do not silently rebase positions.
If you set include_secondary_structure=True, the tool fetches per-residue helix/strand/coil from PDBe REST. Alternatively, use the dedicated PDBe secondary-structure tool separately:
pythonpdbe_get_entry_secondary_structure(pdb_id="6VJJ") # Returns per-chain helix + strand ranges
The returned table is keyed by 1-based canonical residue number. Typical downstream uses:
| Use case | Field to read | |---|---| | Is variant X in a pocket? | by_pos = {a["position"]: a for a in annotations}; by_pos[X]["region"] in ("ligand", "both") — index by position field, NOT list index (PDB residue numbers may not start at 1 or be contiguous) | | Build a DMS heatmap annotation track | [(r["position"], r["region"], r["is_core"], r.get("ss_element"))] | | Filter SAE hotspot features to ligand-binding residues | filter clusters by region == "ligand" | | Compare buried vs surface signal | group statistics by is_core |
| Region label | Biological meaning | Common functional role | |---|---|---| | interface | Within distance_cutoff of a partner chain | Protein-protein binding residue; variants often disrupt complex formation | | ligand | Within distance_cutoff of a ligand heavy atom | Pocket residue; variants often disrupt substrate / cofactor / drug binding | | both | Both | Allosteric or shared-surface residue | | other | Neither | Surface (if not is_core) or core (if is_core) — variants impact through stability or distal effects | | is_core=true | RSA < core_rsa_cutoff (0.25 by default) | Buried residue; variants often destabilize the fold |
alternative conformations or induced-fit binding. A residue may be at the pocket in one conformer and away in another. Pick the structure whose bound state matches your question.
disordered N/C termini. Always verify with a landmark before joining to a sequence or to another annotation source. The skill cannot detect silent offsets for you.
default. Tighten to 4.0 Å for stricter pocket calls; loosen to 6.0 Å to include 2nd-shell residues.
max-ASA reference is calibrated for a typical protein context. For real well-folded proteins values cluster in 0, 1.2]; reading them as a fraction is fine, but treat extreme values as a flag to inspect.
partner_chains=[] is permitted but then all dist_partner valuesare null — interface analysis is skipped entirely.
in the chain) are not detected as ligands — they are part of the chain.
| Tool | Role | Use it for | |---|---|---| | Structure_annotate_per_residue | This skill's atomic tool | The annotation itself | | PDBeSIFTS_get_best_structures | UniProt → ranked PDB list | Step 1 | | PDBeSIFTS_get_all_structures | UniProt → full PDB list | Step 1 | | RCSBAdvSearch_search_structures | Free-text RCSB search | Step 1 | | UniProt_get_sequence_by_accession | Canonical sequence | Step 3 (numbering verification) | | pdbe_get_entry_secondary_structure | SS alone | Step 4 alternative | | tooluniverse-residue-functional-mechanism-interpretation | Downstream consumer | Use this annotation as the structural evidence layer when interpreting DMS hotspots; the skill also plots an annotated DMS heatmap in its Step 7 |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-23 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-25 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-24 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 25 cases were attempted, and 21 counted toward the lift figure. The other 4 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +44 percentage points is the difference between those two pass rates over the 21 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.