skills/fold/SKILL.md
Submits and manages FastFold protein folding jobs via the Jobs API (Boltz-2, OpenFold 3, Chai-1, IntelliFold, AlphaFold2, SimpleFold). Covers authentication, job payloads, modifications, constraints, webhooks, polling, and CIF/PDB URLs. Use when folding with FastFold, OpenFold 3/Chai-1/IntelliFold complexes, ligands/affinity, or scripting create → wait → results.
npx skillsauth add fastfold-ai/skills foldInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill guides correct use of the FastFold Jobs API: create fold jobs, wait for completion with polling, then fetch results (CIF/PDB URLs, metrics, viewer link).
Get an API key: Create a key in the FastFold dashboard. Keep it secret.
Use the key: Scripts read FASTFOLD_API_KEY from .env or environment.
Do not ask users to paste secrets in chat.
.env file (recommended): Scripts automatically load FASTFOLD_API_KEY from a .env file in the project root.export FASTFOLD_API_KEY="sk-..." (overrides .env).If FASTFOLD_API_KEY is not set:
references/.env.example to .env at the workspace root..env file and paste your FastFold API key after FASTFOLD_API_KEY=. You can create one at FastFold API Keys."Scripts live under skills/fold/scripts/ (this skill directory). Run them with python from that folder (or pass the full path):
cd skills/fold # or use paths like skills/fold/scripts/create_job.py
python scripts/create_job.py --name "My Job" --sequence MALW... [--model boltz-2] [--public]python scripts/create_job.py --payload job.jsonpython scripts/wait_for_completion.py <job_id> [--poll-interval 5] [--timeout 900]python scripts/wait_for_evolla_linked.py <job_id> --json [--evolla-timeout 300] [--max-not-found-polls 8] (defaults to one representative source sequence; add --all-sequences only when you explicitly need per-sequence polling)python scripts/wait_for_openmm_linked.py <job_id> --json [--webhook-timeout 600] [--workflow-timeout 2400]python scripts/fetch_results.py <job_id>python scripts/download_cif.py <job_id> [--out output.cif]python scripts/get_viewer_link.py <job_id>The agent should run these scripts for the user, not hand them a list of commands.
python scripts/<script>.py ...), never via path-discovery commands such as find./tmp; use wait_for_evolla_linked.py or wait_for_openmm_linked.py.--timeout, --evolla-timeout, --webhook-timeout, --workflow-timeout) instead of open-ended loops.workflowStatus == NOT_FOUND as a signal that webhook linkage is missing/delayed, not as a reason to keep polling indefinitely./v1/jobs with name, sequences, params (required)./v1/jobs/{jobId}/results until job.status is COMPLETED, FAILED, or STOPPED.COMPLETED jobs: read cif_url, pdb_url, metrics, viewer link, and persisted constraints (contact / pocket / bond) from the same /v1/jobs/{jobId}/results payload.Use this when users want automatic post-fold interpretation in natural language.
Most efficient path (single waiter command):
python scripts/wait_for_evolla_linked.py <job_id> --json --evolla-timeout 300 --max-not-found-polls 8Use this when users want automatic MD simulation after fold completion.
python scripts/wait_for_openmm_linked.py <job_id> --json --webhook-timeout 600 --workflow-timeout 2400openmm.workflowIdopenmm.summary (artifactCount, hasMetrics, metricsKeys)openmm.links.dashboard_url and openmm.links.py2dmol_urlWhat is Evolla?
Evolla-10B key details (paper-backed)
What the webhook is for
cif_url, pdb_url, metrics); it adds linked downstream workflows.webhooks.evolla.enabled (+ optional webhooks.evolla.initial_question)webhooks.openmm.enabled (+ optional OpenMM overrides)constraints.webhooks is intentionally extensible and may include more workflow options in future versions.Create jobs with:
constraints.webhooks.evolla.enabled = true
and optionally:
constraints.webhooks.evolla.initial_question = "What is the function of this protein?"
For OpenMM linkage:
constraints.webhooks.openmm.enabled = true
and optionally include OpenMM overrides (same shape as workflow_input):
preset, residue_profile, temp, ionic, pH, step_size_ns, sim_length_ns, box_mode, box_length, topol, ext_force, ext_force_expr, etc.
How to read webhook results (end-to-end):
GET /v1/jobs/{jobId}/results (job.status == COMPLETED).jobRunId and sequence IDs from that same response.GET /v1/workflows/evolla/linked-history?source_job_id=<jobId>&source_job_run_id=<jobRunId>&source_sequence_id=<sequenceId>workflowStatus is terminal (COMPLETED / FAILED / STOPPED) andlastAnswer is present.lastAnswer as the Evolla response for that sequence.If the waiter returns workflowStatus: "NOT_FOUND" for a sequence, stop polling and verify that the submitted job included:
constraints.webhooks.evolla.enabled: trueconstraints.webhooks.evolla.initial_questionField mapping (important):
/v1/jobs/{jobId}/results/v1/workflows/evolla/linked-historylastAnswerlastQuestionworkflowStatusIf a linked workflow is DRAFT, users can edit the draft initial question via:
PATCH /v1/workflows/evolla/{workflowId}/draft-question
body: { "question": "..." }Then wait for a follow-up run/answer as above.
For OpenMM-linked runs, use:
python scripts/wait_for_openmm_linked.py <job_id> --jsonThis waiter resolves fold completion, OpenMM webhook delivery linkage, linked workflow terminal status, and result links in one command.
Common mistakes the agent must avoid:
| ❌ Wrong | ✅ Correct |
|---|---|
| "model": "boltz-2" | "modelName": "boltz-2" |
| "computeAffinity": true | "property_type": "affinity" on the ligandSequence |
| "diffusionSamples": 1 | "diffusionSample": 1 |
| "ccd": "ATP" | "sequence": "ATP", "is_ccd": true |
| "ligandSequence": {"id": "L", "ccd": "ATP"} | "ligandSequence": {"sequence": "ATP", "is_ccd": true} |
| "modelName": "OpenFold-3" or "openfold-3" | "modelName": "openfold3" (exact string) |
| "modelName": "IntelliFold" | "modelName": "intellifold" (exact string) |
{
"name": "Boltz-2 Affinity Job",
"isPublic": false,
"sequences": [
{
"proteinChain": {
"sequence": "MTEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEYSAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHKE",
"chain_id": "A"
}
},
{
"ligandSequence": {
"sequence": "U4U",
"is_ccd": true,
"property_type": "affinity",
"chain_id": "B"
}
}
],
"params": {
"modelName": "boltz-2"
}
}
Key points:
property_type: "affinity" goes on the ligandSequence, not in paramsis_ccd: true marks a CCD code; omit for SMILES stringsmodelName is the correct field name (not model){
"name": "Boltz-2 Affinity SMILES",
"sequences": [
{
"proteinChain": {
"sequence": "PQITLWQRPLVTIKIGGQLKEALLDTGADDTVLEEMSLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNF",
"chain_id": "A"
}
},
{
"ligandSequence": {
"sequence": "CC1CN(CC(C1)NC(=O)C2=CC=CC=C2N)C(=O)NC(C)(C)C",
"property_type": "affinity",
"chain_id": "B"
}
}
],
"params": {
"modelName": "boltz-2"
}
}
{
"name": "Simple Boltz-2 Fold",
"sequences": [
{
"proteinChain": {
"sequence": "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPK",
"chain_id": "A"
}
}
],
"params": {
"modelName": "boltz-2"
}
}
Use modelName openfold3 (all lowercase). Tune diffusion sampling and seeds; do not use Boltz-only affinity params here.
{
"name": "OpenFold 3 protein–ligand",
"sequences": [
{
"proteinChain": {
"sequence": "MTEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEYSAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTKQAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHKE",
"chain_id": "A"
}
},
{
"ligandSequence": {
"sequence": "ATP",
"is_ccd": true,
"chain_id": "B"
}
}
],
"params": {
"modelName": "openfold3",
"diffusionSample": 5,
"numModelSeeds": 1
}
}
modifications is an array of { "res_idx": <1-based index>, "ccd": "<CCD code>" } on protein, RNA, or DNA chains.
{
"name": "OpenFold 3 PTM example",
"sequences": [
{
"proteinChain": {
"sequence": "MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQFEVVHSLAKWKRQTLGQHDFSAGEGLYTHMKALRPDEDRLSPLHSVYVDQWDWERVMGDGERQFSTLKSTVEAIWAGIKATEAAVSEEFGLAPFLPDQIHFVHSQELLSRYPDLDAKGRERAIAKDLGAVFLVGIGGKLSDGHRHDVRAPDYDDWSTPSELGHAGLNGDILVWNPVLEDAFELSSMGIRVDADTLKHQLALTGDEDRLELEWHQALLRGEMPQTIGGGIGQSRLTMLLLQLPHIGQVQAGVWPAAVRESVPSLL",
"chain_id": "A",
"modifications": [{ "res_idx": 5, "ccd": "SEP" }]
}
}
],
"params": {
"modelName": "openfold3",
"diffusionSample": 5,
"numModelSeeds": 2
}
}
{
"name": "Streptococcal protein G with Pocket",
"sequences": [
{
"proteinChain": {
"sequence": "MTYKLILNGKTLKGETTTEAVDAATAEKVFKQYANDNGVDGEWTYDDATKTFTVTE",
"chain_id": "A"
}
},
{
"ligandSequence": {
"sequence": "ATP",
"is_ccd": true,
"chain_id": "B"
}
}
],
"params": {
"modelName": "boltz-2"
},
"constraints": {
"pocket": [
{
"binder": { "chain_id": "B" },
"contacts": [
{ "chain_id": "A", "res_idx": 12 },
{ "chain_id": "A", "res_idx": 15 },
{ "chain_id": "A", "res_idx": 18 }
]
}
]
}
}
{
"name": "Monomer fold",
"sequences": [
{
"proteinChain": {
"sequence": "MGLSDGEWQLVLNVWGKVEADIPGHGQEVLIRLFKGHPETLERFDKFKHLK",
"chain_id": "A"
}
}
],
"params": {
"modelName": "monomer"
}
}
{
"name": "Multimer fold",
"sequences": [
{ "proteinChain": { "sequence": "MCNTNMSVSTEGAASTSQIP...", "chain_id": "A" } },
{ "proteinChain": { "sequence": "SQETFSGLWKLLPPE", "chain_id": "B" } }
],
"params": {
"modelName": "multimer"
}
}
esm1b)ESMFold is Meta's single-chain structure predictor that runs off ESM embeddings with OpenFold weights. Whenever the user says "ESM", "ESMFold", or "ESM-1b", submit with modelName: "esm1b". It is a real, supported FastFold model — do not claim it's unavailable.
{
"name": "ESMFold monomer",
"sequences": [
{ "proteinChain": { "sequence": "MGLSDGEWQLVLNVWGKVEADIPGHGQEVLIRLFKGHPETLERFDKFKHLK...", "chain_id": "A" } }
],
"params": {
"modelName": "esm1b"
}
}
Optional fields — omit to use defaults. Affinity-related keys apply only when a ligand has property_type: "affinity".
{
"params": {
"modelName": "boltz-2",
"recyclingSteps": 3,
"samplingSteps": 200,
"diffusionSample": 1,
"stepScale": 1.638,
"relaxPrediction": true,
"affinityMwCorrection": false,
"samplingStepsAffinity": 200,
"diffusionSamplesAffinity": 5
}
}
openfold3)diffusionSample — diffusion sample count for the OpenFold 3 run (server defaults apply if omitted).numModelSeeds — number of model seeds (integer ≥ 1).relaxPrediction — omit for OpenFold 3 (defaults to false); the runner does not apply structure relaxation like Boltz/AF2.recyclingSteps, samplingSteps, stepScale, or affinity fields (samplingStepsAffinity, diffusionSamplesAffinity, affinityMwCorrection) to affect OpenFold 3; those are for Boltz models.{
"params": {
"modelName": "openfold3",
"diffusionSample": 5,
"numModelSeeds": 1
}
}
chai1)numDiffnSamples - number of diffusion samples.numTrunkSamples - number of trunk samples.numTrunkRecycles - trunk recycles per sample.numDiffnTimesteps - diffusion timesteps.constraints.contact, constraints.pocket, and constraints.bond.{
"params": {
"modelName": "chai1",
"numDiffnSamples": 5,
"numTrunkSamples": 1,
"numTrunkRecycles": 3,
"numDiffnTimesteps": 200
}
}
intellifold)recyclingSteps, samplingSteps, and diffusionSample for optional runtime tuning (maps to IntelliFold CLI flags).relaxPrediction (same as OpenFold 3 / Boltz-style complex runs).{
"params": {
"modelName": "intellifold",
"recyclingSteps": 10,
"samplingSteps": 200,
"diffusionSample": 5
}
}
sequence is either a CCD code with "is_ccd": true or a SMILES string with is_ccd omitted/false."property_type": "affinity" on the ligandSequence object; never put computeAffinity in params.contact / pocket / bond): Set them in the job JSON under constraints (same request body as everything else). Boltz, Boltz-2, and IntelliFold use pocket/bond constraints in YAML. Chai-1 maps contact/pocket/bond into native restraints during inference. OpenFold 3 does not feed constraints into its inference input—only sequences and chain-level modifications—though the service may still persist constraints on the job for the UI or replay.constraints.webhooks.evolla.enabled: true enables Evolla auto-chat; optional constraints.webhooks.evolla.initial_question.constraints.webhooks.openmm.enabled: true enables OpenMM auto-simulation; optional OpenMM config overrides under constraints.webhooks.openmm.predictionPayload. Use results.cif_url(), results.metrics() once.predictionPayload. Use results[0].cif_url(), results[1].cif_url(), etc.PENDING – QueuedINITIALIZED – Ready to runRUNNING – ProcessingCOMPLETED – Success; artifacts and metrics availableFAILED – ErrorSTOPPED – Stopped before completionOnly use cif_url, pdb_url, metrics, and viewer link when status is COMPLETED.
https://cloud.fastfold.ai/job/<job_id>?shared=true
Or use: python scripts/get_viewer_link.py <job_id> (from this skill’s scripts/ directory)
job_id as UUID before using it in API paths or filenames.development
Run molecular dynamics (MD) simulations via the FastFold Workflows API. Today supports the CALVADOS+OpenMM workflow (calvados_openmm_v1) from either an existing fold job (AF structure + PAE auto-resolved) or manual PDB+PAE upload, then waits for completion, fetches metrics/plots/CSV artifacts, and extracts trajectory frames as PDB files. Use when running an MD simulation with FastFold, CALVADOS + OpenMM, reading MD metrics/plots, extracting frames, or scripting submit → wait → results for an MD run.
tools
Share markdown reports to the user's configured Slack agent_cli_report channel via Fastfold API, and persist the markdown as a library item.
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.