physistool clientFrom pip install to a folded structure — CLI or Python.
The open-source physistool client is a thin, auditable front end to a confidential remote engine. You bring a sequence and whatever evidence you hold; it verifies the enclave's signed attestation, ships your input (optionally end-to-end encrypted), and returns an all-atom structure plus a quality report. Every command has an identical one-line Python SDK call — and nothing folds, or is charged, until you add --run.
Three ideas, and the rest is detail.
The client ships; the enclave folds
No IP lives in this package — the engine runs server-side inside an AWS Nitro Enclave. The client verifies the enclave's signed attestation against a published build measurement (--pcr0) before a single byte leaves your machine; with --encrypt the whole exchange is sealed so only that enclave can read your input.
Whatever you have, combined
A .pdb reference is refined; a bare .fasta is folded blind from the evidence you supply. Eleven typed adapters — templates, NOEs, disulfides, cross-links, coevolution, AI priors — are all repeatable and combine freely. The enclave pools them into one restraint field and folds.
Preview, then run
Every command is a dry-run preview first — inputs, mode, the exact outputs, and the credit cost — and folds only when you add --run. Billing is simple: 1 credit = 1 seed, so --best-of N costs N. The SDK fold() always executes (there is no preview) — the gate is the CLI's job.
AInstall once, log in once.
The package is pure Python (stdlib transport; cryptography is pulled in only when you use --encrypt). Create an account and accept the Terms of Service on the console, then store your API key locally. Installing the package runs no code and accepts nothing on your behalf.
# 1 · install — ships a single console command: physistool pip install physistool # 2 · terms + key (create the account & accept ToS on the console first) physistool --terms # prints the hosted Terms of Service URL physistool --login phk_xxxxxxxx # store the key in ~/.physis/config (0600) physistool --account # key status + backend + live credit balance # 3 · pin the enclave build so the client can verify the endpoint physistool --pcr0 # prints the published PCR0 (48-byte hex)
One command · physistool
The package installs a single console command, physistool. A leading fold word is optional: physistool fold target.pdb and physistool --sequence target.pdb are the same command. Today the umbrella runs physistool fold; sibling verbs (engineer, msa, search) land under the same command later.
BThe same fold, two ways to call it.
Everything the CLI does is available programmatically: from physis import fold. Each flag maps to a keyword argument. Start with a preview (no --run) on the CLI to confirm cost; the SDK's fold() executes directly. Run physistool --help-sdk for the full signature at any time.
# preview — lists mode, outputs, credit cost; folds nothing physistool fold target.pdb --out out.pdb # add --run to execute (charges best-of credits) physistool fold target.pdb --out out.pdb --run
from physis import fold, FoldError try: report = fold( sequence_path="target.pdb", out_path="out.pdb", ) except FoldError as e: print("fold failed:", e)
The CLI's dry-run preview is a billing-safety gate; the SDK has no preview — call fold() only when you mean it. fold() returns the parsed JSON report as a dict.
physistool fold query.fasta \ --input-template homolog.pdb \ --input-contacts noe.csv \ --input-disulfides ss.csv \ --best-of 4 --out out.pdb --run
report = fold( sequence_path="query.fasta", out_path="out.pdb", evidence={ "template_pdb": ["homolog.pdb"], "contacts": ["noe.csv"], "disulfides": ["ss.csv"], }, best_of=4, )
physistool fold q.fasta --input-coevolution aln.a3m \ --encrypt \ --expected-pcr0 $(physistool --pcr0) \ --out out.pdb --run
report = fold( sequence_path="q.fasta", out_path="out.pdb", evidence={"coevolution": ["aln.a3m"]}, encrypt=True, expected_pcr0="e5d0...f2880", # published build )
physistool --batch jobs.json --out results/ \ --best-of 2 --run
from physis.physis_client import fold_batch agg = fold_batch( "jobs.json", "results/", best_of=2, )
CWhat to fold, and the two files back.
The input's content picks the mode automatically. A run returns two distinct files: the structure and a separate quality report — a common point of confusion, so it is worth stating plainly.
| input / --sequencePDB | FASTA | The target. Given positionally (physistool fold target.pdb) or via --sequence. A PDB with coordinates → reference-guided refinement (full native metrics). A FASTA / bare sequence → blind fold — which requires at least one --input-* source or a --distogram-artifact. |
SDKsequence_path=… |
| --outPATH | The PDB structure. Where the returned all-atom coordinates are written. Required to --run. The quality report is a separate file — see below. Point it at a new subfolder (e.g. run1/fold.pdb) and the directory is created for you — the whole result bundle (report, HTML, CSVs) lands there too.In --batch this is the results-root directory, not a file. |
SDKout_path=… |
| --report-jsonPATH | The JSON quality report (metrics: ca_rmsd, held-out evaluation, conflicts, verdict) — a separate file from the --out PDB, not a copy of it. Defaults to the --out stem with a .json suffix, so a fold writes both out.pdb (structure) and out.json (report). A missing subfolder in this path is created for you, just like --out. |
SDKreport_path=… |
DBring whatever you have.
Eleven typed adapters cover the experimental and predicted data you are likely to hold. Every flag is repeatable and any mix combines freely. In the SDK they are one evidence dict, keyed by the wire name shown on the right; each value is a list of paths. The client only ships the raw files — the enclave resolves them into the distogram it folds from.
| Structural & predicted templates | ||
| --input-templatePDB | Homolog / template PDB, aligned then turned into distance restraints. | keytemplate_pdb |
| --input-aiPDB | A predicted structure from any AI model — AlphaFold, ESMFold, RoseTTAFold, Boltz, a custom or in-house model — used as a geometry-only template. It is model-agnostic: only the PDB geometry is read, so the format is what matters, not which model produced it. pLDDT and PAE are deliberately ignored, so no AI-confidence bias enters the fold. alias: --input-af2 | keyaf2_pdb |
| Distance & contact restraints | ||
| --input-contactsCSV | Distance-restraint CSV, NOE-aware. The general-purpose contact channel. | keycontacts |
| --input-ambiguousCSV | Ambiguous contacts as OR-restraints (a group is satisfied by any one member). | keyambiguous_contacts |
| --input-disulfidesCSV | Disulfide locks (i,j) → sharp, tight CA–CA priors. | keydisulfides |
| --input-crosslinkCSV | Crosslinking-MS pairs; linker reach becomes a soft CA–CA upper bound. | keycrosslink |
| --input-restraintsTXT | Free-text NOE / distance restraints — the catch-all for ad-hoc lists. | keyrestraints |
| NMR exchange formats | ||
| --input-nefNEF | NMR Exchange Format distance restraints (NOE upper bounds). | keynef |
| --input-starSTR | NMR-STAR distance restraints (BMRB / PDB). | keynmr_star |
| Evolutionary & predicted signal | ||
| --input-coevolutionCSV | A3M | A precomputed coevolution CSV or a raw MSA .a3m — the enclave extracts the top couplings. | keycoevolution |
| --input-casp-rrRR | CASP-RR contact / distance predictions. | keycasp_rr |
| --distogram-artifactJSON | A pre-built portable artifact (the production input contract). When set it is used as-is and the typed --input-* sources are ignored — it already is an artifact. | SDKdistogram_artifact |
| --template-sigmaÅ · def 2.5 | Gaussian width when converting templates to restraints. Larger = softer / less trusting. | SDKtemplate_sigma |
| --noe-modedef auto | How NOE contacts are shaped: auto, gaussian, flatbottom, or onesided (true one-sided upper bounds). | SDKnoe_mode |
| --soi-fillon | auto | smart | Opt-in Sea-of-Information gap fill for uncovered pairs — off by default. smart is quality-gated. Best on sparse / masked restraint sets. | SDKsoi_fill |
ERun more seeds, get more answers.
Folding is stochastic, so the strongest results come from several independent seeds, keeping the best. Two levers below are specialised: the distance-bin ceiling for extended (helical) targets, and the SS-aware helix prior for the GLP-1 / glucagon family.
| --best-ofN · def 1 | Run N seeds, keep the best by composite score. Also unlocks the ensemble confidence / PAE blocks in the report.Billing: N seeds = N credits. | SDKbest_of |
| --seedINT · def 0 | Base RNG seed for a reproducible run. With --best-of N the seeds are base … base+N-1. | SDKseed |
| --disto-max-binÅ | auto | off | Distance-bin ceiling for the distogram. auto (default on the own-distogram path) sizes the bins to an extended target's CA–CA extent — the correctness lever for isolated GLP-1-family helices, and bit-identical on globular targets. A number forces an explicit Å ceiling; off forces the historical 30 Å bins. | SDKdisto_max_bin |
| --helix-prior | The SS-aware helix prior — the GLP-1 / helical lever. Off by default → folds are bit-identical to the historical engine. | SDKhelix_prior |
| --helix-prior-ensemble | Per-seed helix-prior strength schedule. Requires --helix-prior and is only useful with --best-of N≥4 — each seed sweeps OFF + a range, and the blind winner selector keeps the best. | SDKhelix_prior_ensemble |
FThe one score you cannot game.
Hold back a slice of evidence the fold never saw; the enclave grades the finished model against it and writes an out-of-sample block into the report. It never shapes the fold — the only signal that catches a structure which satisfies its own inputs yet is still wrong.
| --held-out-inputCSV | An independent contacts CSV not used to build this fold. Scored post-fold for out-of-sample recall + broken contacts + a blind ruler-reliability tier. Distinct from --input-contacts, which does shape the fold. alias: --held-out-evidence | SDKheld_out_input |
| --held-out-thresholdÅ · def 10 | CA–CA distance under which a held-out contact counts as satisfied. | SDKheld_out_threshold |
| --held-out-msa-neffdef none | Optional MSA Neff — down-weights shallow-MSA coevolution rulers in the reliability score. | SDKheld_out_msa_neff |
GVerify the enclave, then send.
Against a real endpoint the client verifies the AWS-signed attestation and the published build measurement before any input leaves your machine — a mismatch aborts and sends nothing. By default an on-demand dispatcher launches a right-sized worker per command, so you rarely touch these at all.
| --endpointURL | Fold against a specific endpoint (direct / dev mode) — an explicit --endpoint also bypasses the dispatcher. Optional: by default the dispatcher resolves it for you. With the dispatcher disabled and no --endpoint, falls back to http://127.0.0.1:8787. | SDKendpoint |
| --dispatcherURL | On-demand worker lifecycle (Supabase edge function). On by default: launches a right-sized enclave worker, folds against it, then releases it. Set PHYSIS_DISPATCHER='' to disable, or pass an explicit --endpoint to bypass. | SDKCLI-only |
| --encrypt | End-to-end encryption (Stage C). Seals the input (and evidence + held-out file) to the enclave's X25519 key; the result comes back sealed to a fresh per-run key only you hold. Requires the cryptography package. | SDKencrypt |
| --expected-pcr0HEX | The published enclave build measurement (PCR0). Required to verify a real (non-stub) attestation before sending input. Pin it with --expected-pcr0 $(physistool --pcr0); falls back to PHYSIS_EXPECTED_PCR0. A stale pin fails closed (PCR0 mismatch) — it never silently trusts a different build. | SDKexpected_pcr0 |
Billing is enforced server-side
The armed enclave refuses any fold without a valid, backend-signed token — a run is charged only when it actually folds, and a job that fails to produce a result is refunded. No client-side flag can bypass this. Metering is automatic when an API key is stored; the SDK accepts metering=True to require it or metering=False for a local metering-free run.
Lost your connection mid-fold? Collect it later.
A fold takes real compute whether or not your link survives long enough to receive it. So an --encrypt run is stored sealed the moment it finishes — before the answer is even sent back — and stays collectable for 7 days:
physistool pending — what is waiting.
physistool fetch <reservation-id> — write it out, exactly where the interrupted run would have.
If a run is charged but not delivered, the CLI prints the exact fetch command to recover it. You are never both refunded and handed the result: if the refund goes through, there is nothing to collect.
Two honest limits. This needs --encrypt: we deliberately keep no readable structures at rest, so only sealed packages are stored — and what sits in that store is ciphertext we cannot open. And it works from the machine that started the fold, because the key that unseals the result is generated there, kept in ~/.physis/pending/, and never leaves it. Not even we can recover it for you — which is the point.
Run the enclave in your AWS.
For data-residency teams — pharma, NMR labs, integrative modelling — whose inputs must never leave their own cloud: run the same attested PhysisFold enclave on your own hardware. The guarantee is unchanged — your client verifies the same AWS-signed build measurement (PCR0) — and the engine never materialises in any form you, or anyone with the image, can extract.
| 1 · Launch | Boot the published loader image as a Nitro enclave in your own account. The image ships the engine encrypted — there is no plaintext engine anywhere on disk, so holding the image reveals nothing. |
| 2 · Attest | At boot the enclave attests to our key-release service. Only a genuine, unmodified enclave whose measurement matches the published PCR0 receives the key that decrypts the engine — decrypted in enclave memory only, never written to disk. A tampered or non-enclave image is refused: no key, nothing runs. |
| 3 · Fold | Your data folds locally, inside your VPC. Nothing leaves your cloud except the same server-side billing token every fold already carries. |
| 4 · Point the client | Aim the same client at your own enclave — no client changes, just an endpoint and the pinned measurement. |
physistool fold target.pdb \ --endpoint https://enclave.internal.your-lab.example \ --expected-pcr0 <published BYOC PCR0> --encrypt --run
The client verifies the AWS attestation and the pinned PCR0 before any input leaves your machine — a mismatch aborts and sends nothing. An explicit --endpoint bypasses the hosted dispatcher and talks straight to your enclave.
HOne fold, or ten thousand.
The execution gate keeps you safe on single runs; the batch manifest folds many sequences in one request, each reserving credits against its own input hash so an interrupt only bills what actually started.
| --run | The execution gate. Without it, every command is a dry-run preview that folds nothing and charges nothing. With it, the fold goes through the credit gate. | SDKfold() always runs |
| --batchMANIFEST | Fold many sequences from a JSON manifest in one request (mutually exclusive with a single input). --out is the results-root directory; outputs go to <out>/<id>/<id>.{pdb,json} unless a job sets its own out. The flags (best-of / seed / helix / evidence knobs / encrypt) are batch-wide defaults that any job may override per-id. | SDKfold_batch() |
| pending | List folds waiting to be collected — runs that were computed and charged but never delivered (a dropped connection, a closed laptop). Shows each reservation id, when it started and where it was headed. Reads local state only: no worker, no network, no charge. | SDKCLI-only |
| fetchRESERVATION-ID | Collect one of them. Pulls the sealed package, unseals it locally and writes the full bundle where the interrupted run would have — override with --out / --report-json. Never re-charges. Needs the original run to have used --encrypt, and to be run on the same machine (the unseal key never left it). Kept 7 days. | SDKfetch() |
| --help-sdk | Print the programmatic (Python SDK) usage — the fold() / fold_batch() entry points and how each flag maps to a keyword argument — and exit. | SDKprints this |
[
{ "id": "insulin_refine", "sequence": "2hiu.pdb",
"input_template": ["4ins.pdb", "1trz.pdb"], "input_disulfides": "ss.csv",
"best_of": 8, "helix_prior": true, "out": "refined/insulin.pdb" },
{ "id": "denovo_msa", "sequence": "target.fasta",
"input_coevolution": ["target.a3m"], "held_out_input": "holdout.csv",
"best_of": 4, "noe_mode": "flatbottom" },
{ "id": "prebuilt", "sequence": "p3.fasta",
"distogram_artifact": "p3.distogram.json", "seed": 7 }
]
Three jobs, three configs in one budget: insulin_refine spends 8 seeds with the helix prior and writes to its own refined/ folder; denovo_msa folds blind from an MSA with 4 seeds and flat-bottom NOEs; prebuilt pins a seed and inherits every batch default. The credit cost is the sum of each job's effective best-of — here 8 + 4 + N, where N is whatever --best-of the batch runs with (its default is 1, so 8 + 4 + 1 = 13).
Manifest fields, exactly
Each job object accepts: sequence (required) — a path, .pdb→refine / .fasta→blind; id (optional output subdir; defaults to the sequence's basename); distogram_artifact (a pre-built artifact — when present, evidence fields are ignored); any input_<name> evidence field; and held_out_input.
Valid evidence keys are the underscore names: input_template, input_contacts, input_ambiguous, input_disulfides, input_ai (or input_af2), input_coevolution, input_crosslink, input_restraints, input_nef, input_star, input_casp_rr. Each value is a single path or a list of paths. Relative paths resolve against the manifest's own directory.
Per-job overrides. The CLI flags (--best-of, --seed, --disto-max-bin, --helix-prior(-ensemble), the evidence knobs, --held-out-threshold/--held-out-msa-neff, --encrypt) are the batch-wide defaults — but any job may override them per-id by carrying the same-named field: best_of, seed, helix_prior, helix_prior_ensemble, disto_max_bin, template_sigma, noe_mode, soi_fill, held_out_threshold, held_out_msa_neff, encrypt. A per-job out further sets where that job writes — a file path (refined/insulin.pdb) fixes the whole bundle's directory + stem, a directory drops <id>.pdb inside; relative to the results root, created if missing. The credit cost is the sum of each job's effective best_of. A blind (.fasta) job must still carry evidence or a distogram_artifact.
IKeys, balance, profiles.
The account surface runs without folding — all state lives in ~/.physis/config (0600). Terms-of-Service acceptance is a clickwrap on the console (server-side); this open-source client only prints the hosted Terms URL.
| --loginAPI_KEY | Store an API key (phk_…) under the profile named by --profile. | SDKconfig |
| --account | Print key status + backend + terms URL + client version + live credit balance, then exit. | SDKconfig |
| --terms | Print the Terms of Service URL and exit. | SDKconfig |
| --pcr0 | Print the published enclave build's PCR0 (bare hex, pipeable) and exit. | SDKconfig |
| --profileNAME · def default | Which profile --login writes to — keep more than one key. | SDKconfig |
| --use-profileNAME | Switch the active API-key profile and exit. | SDKconfig |
| --logout | Remove all stored API keys from ~/.physis/config. | SDKconfig |
JA structure, and a verdict.
Every --run returns the all-atom PDB to --out and a machine-readable JSON report alongside it. In the SDK, fold() returns that report as a dict — read ca_rmsd, the conflict metrics, and the held-out block straight from Python.
The structure
The final all-atom model — backbone and sidechains, reconstructed and energy-minimised.
The report
Metrics, conflicts, confidence / PAE, the held-out block, and an automated verdict — the dict fold() returns.
The full bundle
The interactive HTML, value-data layer and PyMOL script the engine produces are documented on the Output page →
Install it, and fold something you understand.
The fastest way to learn the client is to point it at a target you already know. Create an account, buy a few credits, and fold — CLI or Python, blind by construction, with the full report attached. Run physistool --help for the flag reference and physistool --help-sdk for the programmatic one.