dyno-phi 0.2.3__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. dyno_phi-0.3.0/.gitignore +125 -0
  2. dyno_phi-0.3.0/CHANGELOG.md +53 -0
  3. dyno_phi-0.3.0/PKG-INFO +208 -0
  4. dyno_phi-0.3.0/README.md +177 -0
  5. dyno_phi-0.3.0/examples/README.md +25 -0
  6. dyno_phi-0.3.0/examples/async_concurrent.py +31 -0
  7. dyno_phi-0.3.0/examples/compose_dag.py +22 -0
  8. dyno_phi-0.3.0/examples/download_results.py +21 -0
  9. dyno_phi-0.3.0/examples/pipelines/fold_and_analyze.yaml +10 -0
  10. dyno_phi-0.3.0/examples/pipelines/mpnn_esmfold_alphafold.yaml +15 -0
  11. dyno_phi-0.3.0/examples/quickstart/README.md +10 -0
  12. dyno_phi-0.3.0/examples/quickstart/trp_cage.fasta +2 -0
  13. dyno_phi-0.3.0/examples/run_pipeline.py +23 -0
  14. dyno_phi-0.3.0/examples/submit_fold.py +17 -0
  15. dyno_phi-0.3.0/pyproject.toml +95 -0
  16. dyno_phi-0.3.0/src/phi/__init__.py +41 -0
  17. dyno_phi-0.3.0/src/phi/_schema_validation.py +169 -0
  18. dyno_phi-0.3.0/src/phi/_transport.py +215 -0
  19. dyno_phi-0.3.0/src/phi/_version.py +1 -0
  20. dyno_phi-0.3.0/src/phi/async_client.py +121 -0
  21. dyno_phi-0.3.0/src/phi/cli/__init__.py +5 -0
  22. dyno_phi-0.3.0/src/phi/cli/__main__.py +4 -0
  23. dyno_phi-0.3.0/src/phi/cli/commands/__init__.py +0 -0
  24. dyno_phi-0.3.0/src/phi/cli/commands/artifacts.py +104 -0
  25. dyno_phi-0.3.0/src/phi/cli/commands/auth.py +166 -0
  26. dyno_phi-0.3.0/src/phi/cli/commands/datasets.py +244 -0
  27. dyno_phi-0.3.0/src/phi/cli/commands/documents.py +299 -0
  28. dyno_phi-0.3.0/src/phi/cli/commands/export.py +108 -0
  29. dyno_phi-0.3.0/src/phi/cli/commands/jobs.py +218 -0
  30. dyno_phi-0.3.0/src/phi/cli/commands/logs.py +186 -0
  31. dyno_phi-0.3.0/src/phi/cli/commands/models.py +115 -0
  32. dyno_phi-0.3.0/src/phi/cli/commands/pipeline.py +115 -0
  33. dyno_phi-0.3.0/src/phi/cli/commands/projects.py +106 -0
  34. dyno_phi-0.3.0/src/phi/cli/commands/quickstart.py +118 -0
  35. dyno_phi-0.3.0/src/phi/cli/commands/quota.py +61 -0
  36. dyno_phi-0.3.0/src/phi/cli/commands/runs.py +308 -0
  37. dyno_phi-0.3.0/src/phi/cli/commands/use.py +54 -0
  38. dyno_phi-0.3.0/src/phi/cli/completion.py +43 -0
  39. dyno_phi-0.3.0/src/phi/cli/document_sync.py +256 -0
  40. dyno_phi-0.3.0/src/phi/cli/errors.py +63 -0
  41. dyno_phi-0.3.0/src/phi/cli/main.py +108 -0
  42. dyno_phi-0.3.0/src/phi/cli/params.py +190 -0
  43. dyno_phi-0.3.0/src/phi/cli/render.py +76 -0
  44. dyno_phi-0.3.0/src/phi/cli/state.py +141 -0
  45. dyno_phi-0.3.0/src/phi/client.py +121 -0
  46. dyno_phi-0.3.0/src/phi/config.py +100 -0
  47. dyno_phi-0.3.0/src/phi/errors.py +133 -0
  48. dyno_phi-0.3.0/src/phi/files.py +265 -0
  49. dyno_phi-0.3.0/src/phi/graph.py +455 -0
  50. dyno_phi-0.3.0/src/phi/models/__init__.py +7 -0
  51. dyno_phi-0.3.0/src/phi/models/_generated.py +65 -0
  52. dyno_phi-0.3.0/src/phi/models/artifacts.py +23 -0
  53. dyno_phi-0.3.0/src/phi/models/common.py +7 -0
  54. dyno_phi-0.3.0/src/phi/models/datasets.py +90 -0
  55. dyno_phi-0.3.0/src/phi/models/designs.py +48 -0
  56. dyno_phi-0.3.0/src/phi/models/documents.py +58 -0
  57. dyno_phi-0.3.0/src/phi/models/imports.py +29 -0
  58. dyno_phi-0.3.0/src/phi/models/job_types.py +22 -0
  59. dyno_phi-0.3.0/src/phi/models/jobs.py +105 -0
  60. dyno_phi-0.3.0/src/phi/models/logs.py +18 -0
  61. dyno_phi-0.3.0/src/phi/models/projects.py +29 -0
  62. dyno_phi-0.3.0/src/phi/models/quota.py +25 -0
  63. dyno_phi-0.3.0/src/phi/models/run_admin.py +14 -0
  64. dyno_phi-0.3.0/src/phi/models/runs.py +148 -0
  65. dyno_phi-0.3.0/src/phi/models/sequences.py +5 -0
  66. dyno_phi-0.3.0/src/phi/models/tool_configs.py +14 -0
  67. dyno_phi-0.3.0/src/phi/profiles.py +83 -0
  68. dyno_phi-0.3.0/src/phi/py.typed +0 -0
  69. dyno_phi-0.3.0/src/phi/resources/__init__.py +106 -0
  70. dyno_phi-0.3.0/src/phi/resources/artifacts.py +143 -0
  71. dyno_phi-0.3.0/src/phi/resources/datasets.py +427 -0
  72. dyno_phi-0.3.0/src/phi/resources/designs.py +181 -0
  73. dyno_phi-0.3.0/src/phi/resources/documents.py +640 -0
  74. dyno_phi-0.3.0/src/phi/resources/files.py +37 -0
  75. dyno_phi-0.3.0/src/phi/resources/imports.py +27 -0
  76. dyno_phi-0.3.0/src/phi/resources/job_types.py +118 -0
  77. dyno_phi-0.3.0/src/phi/resources/jobs.py +440 -0
  78. dyno_phi-0.3.0/src/phi/resources/logs.py +140 -0
  79. dyno_phi-0.3.0/src/phi/resources/projects.py +118 -0
  80. dyno_phi-0.3.0/src/phi/resources/quota.py +65 -0
  81. dyno_phi-0.3.0/src/phi/resources/run_admin.py +51 -0
  82. dyno_phi-0.3.0/src/phi/resources/runs.py +288 -0
  83. dyno_phi-0.3.0/src/phi/resources/sequences.py +415 -0
  84. dyno_phi-0.3.0/src/phi/resources/tool_configs.py +23 -0
  85. dyno_phi-0.3.0/src/phi/resources/uploads.py +28 -0
  86. dyno_phi-0.3.0/src/phi/schema_cache.py +66 -0
  87. dyno_phi-0.3.0/src/phi/waiters.py +249 -0
  88. dyno_phi-0.3.0/tests/__init__.py +0 -0
  89. dyno_phi-0.3.0/tests/cli/__init__.py +0 -0
  90. dyno_phi-0.3.0/tests/cli/conftest.py +20 -0
  91. dyno_phi-0.3.0/tests/cli/test_artifacts.py +201 -0
  92. dyno_phi-0.3.0/tests/cli/test_auth.py +268 -0
  93. dyno_phi-0.3.0/tests/cli/test_cli_scaffold.py +326 -0
  94. dyno_phi-0.3.0/tests/cli/test_completion.py +122 -0
  95. dyno_phi-0.3.0/tests/cli/test_datasets.py +263 -0
  96. dyno_phi-0.3.0/tests/cli/test_document_sync.py +277 -0
  97. dyno_phi-0.3.0/tests/cli/test_documents.py +278 -0
  98. dyno_phi-0.3.0/tests/cli/test_export.py +162 -0
  99. dyno_phi-0.3.0/tests/cli/test_jobs.py +338 -0
  100. dyno_phi-0.3.0/tests/cli/test_json_contract.py +408 -0
  101. dyno_phi-0.3.0/tests/cli/test_logs.py +271 -0
  102. dyno_phi-0.3.0/tests/cli/test_models_cmd.py +84 -0
  103. dyno_phi-0.3.0/tests/cli/test_params.py +326 -0
  104. dyno_phi-0.3.0/tests/cli/test_pipeline.py +251 -0
  105. dyno_phi-0.3.0/tests/cli/test_projects.py +160 -0
  106. dyno_phi-0.3.0/tests/cli/test_quickstart.py +198 -0
  107. dyno_phi-0.3.0/tests/cli/test_quota.py +93 -0
  108. dyno_phi-0.3.0/tests/cli/test_runs.py +391 -0
  109. dyno_phi-0.3.0/tests/conftest.py +32 -0
  110. dyno_phi-0.3.0/tests/live/__init__.py +0 -0
  111. dyno_phi-0.3.0/tests/live/conftest.py +260 -0
  112. dyno_phi-0.3.0/tests/live/test_live_artifacts_logs.py +161 -0
  113. dyno_phi-0.3.0/tests/live/test_live_auth_discovery.py +126 -0
  114. dyno_phi-0.3.0/tests/live/test_live_datasets_export.py +150 -0
  115. dyno_phi-0.3.0/tests/live/test_live_errors.py +111 -0
  116. dyno_phi-0.3.0/tests/live/test_live_jobs.py +162 -0
  117. dyno_phi-0.3.0/tests/live/test_live_pipelines.py +177 -0
  118. dyno_phi-0.3.0/tests/live/test_live_quickstart_sdk.py +130 -0
  119. dyno_phi-0.3.0/tests/test_artifacts.py +81 -0
  120. dyno_phi-0.3.0/tests/test_config.py +142 -0
  121. dyno_phi-0.3.0/tests/test_datasets.py +400 -0
  122. dyno_phi-0.3.0/tests/test_designs.py +178 -0
  123. dyno_phi-0.3.0/tests/test_docs_examples.py +154 -0
  124. dyno_phi-0.3.0/tests/test_documents.py +290 -0
  125. dyno_phi-0.3.0/tests/test_errors.py +103 -0
  126. dyno_phi-0.3.0/tests/test_files.py +340 -0
  127. dyno_phi-0.3.0/tests/test_graph.py +413 -0
  128. dyno_phi-0.3.0/tests/test_imports.py +69 -0
  129. dyno_phi-0.3.0/tests/test_job_types.py +157 -0
  130. dyno_phi-0.3.0/tests/test_jobs.py +455 -0
  131. dyno_phi-0.3.0/tests/test_logs.py +144 -0
  132. dyno_phi-0.3.0/tests/test_packaging.py +152 -0
  133. dyno_phi-0.3.0/tests/test_parity.py +46 -0
  134. dyno_phi-0.3.0/tests/test_projects.py +201 -0
  135. dyno_phi-0.3.0/tests/test_quota.py +105 -0
  136. dyno_phi-0.3.0/tests/test_run_admin.py +74 -0
  137. dyno_phi-0.3.0/tests/test_runs.py +432 -0
  138. dyno_phi-0.3.0/tests/test_schema_validation.py +98 -0
  139. dyno_phi-0.3.0/tests/test_sequences.py +383 -0
  140. dyno_phi-0.3.0/tests/test_tool_configs.py +42 -0
  141. dyno_phi-0.3.0/tests/test_transport.py +351 -0
  142. dyno_phi-0.3.0/tests/test_uploads.py +56 -0
  143. dyno_phi-0.3.0/tests/test_waiters.py +318 -0
  144. dyno_phi-0.2.3/.claude/settings.json +0 -10
  145. dyno_phi-0.2.3/.claude/skills/phi/SKILL.md +0 -304
  146. dyno_phi-0.2.3/.claude-plugin/marketplace.json +0 -26
  147. dyno_phi-0.2.3/.github/workflows/ci.yml +0 -34
  148. dyno_phi-0.2.3/.github/workflows/publish.yml +0 -72
  149. dyno_phi-0.2.3/.gitignore +0 -49
  150. dyno_phi-0.2.3/.pre-commit-config.yaml +0 -27
  151. dyno_phi-0.2.3/CHANGELOG.md +0 -73
  152. dyno_phi-0.2.3/CLI-REFERENCE.md +0 -792
  153. dyno_phi-0.2.3/LICENSE +0 -21
  154. dyno_phi-0.2.3/PKG-INFO +0 -267
  155. dyno_phi-0.2.3/README.md +0 -226
  156. dyno_phi-0.2.3/biomodals/TEMPLATE_NEW_BIOMODAL.py +0 -391
  157. dyno_phi-0.2.3/biomodals/__init__.py +0 -13
  158. dyno_phi-0.2.3/biomodals/base.py +0 -400
  159. dyno_phi-0.2.3/biomodals/modal_af2rank.py +0 -639
  160. dyno_phi-0.2.3/biomodals/modal_align_structures.py +0 -676
  161. dyno_phi-0.2.3/biomodals/modal_alphafold.py +0 -683
  162. dyno_phi-0.2.3/biomodals/modal_bindcraft.py +0 -1191
  163. dyno_phi-0.2.3/biomodals/modal_boltz.py +0 -484
  164. dyno_phi-0.2.3/biomodals/modal_boltzgen.py +0 -862
  165. dyno_phi-0.2.3/biomodals/modal_chai1.py +0 -361
  166. dyno_phi-0.2.3/biomodals/modal_esm2_predict_masked.py +0 -289
  167. dyno_phi-0.2.3/biomodals/modal_esmfold.py +0 -663
  168. dyno_phi-0.2.3/biomodals/modal_ligandmpnn.py +0 -362
  169. dyno_phi-0.2.3/biomodals/modal_proteinmpnn.py +0 -783
  170. dyno_phi-0.2.3/biomodals/modal_rf3.py +0 -673
  171. dyno_phi-0.2.3/biomodals/modal_rfdiffusion3.py +0 -1919
  172. dyno_phi-0.2.3/biomodals/modal_rso.py +0 -432
  173. dyno_phi-0.2.3/biomodals/modal_tm_score.py +0 -417
  174. dyno_phi-0.2.3/biomodals/utils/__init__.py +0 -1
  175. dyno_phi-0.2.3/biomodals/utils/extract_chain_as_mol2.py +0 -73
  176. dyno_phi-0.2.3/biomodals/utils/extract_ligands.py +0 -240
  177. dyno_phi-0.2.3/examples/README.md +0 -65
  178. dyno_phi-0.2.3/examples/binders/pdl1/binder_009.pdb +0 -1343
  179. dyno_phi-0.2.3/examples/binders/pdl1/binder_047.pdb +0 -1309
  180. dyno_phi-0.2.3/examples/binders/pdl1/binder_106.pdb +0 -1532
  181. dyno_phi-0.2.3/examples/binders/pdl1/binder_188.pdb +0 -1194
  182. dyno_phi-0.2.3/examples/binders/pdl1/binder_246.pdb +0 -1438
  183. dyno_phi-0.2.3/examples/fixtures/pdl1/5O45.pdb +0 -5146
  184. dyno_phi-0.2.3/examples/fixtures/pdl1/pdl1_pdb_19_132.pdb +0 -3094
  185. dyno_phi-0.2.3/phi-plugin/.claude-plugin/plugin.json +0 -11
  186. dyno_phi-0.2.3/phi-plugin/README.md +0 -55
  187. dyno_phi-0.2.3/phi-plugin/skills/phi/SKILL.md +0 -304
  188. dyno_phi-0.2.3/pyproject.toml +0 -128
  189. dyno_phi-0.2.3/src/phi/__init__.py +0 -4
  190. dyno_phi-0.2.3/src/phi/_version.py +0 -1
  191. dyno_phi-0.2.3/src/phi/api.py +0 -158
  192. dyno_phi-0.2.3/src/phi/cli.py +0 -89
  193. dyno_phi-0.2.3/src/phi/commands/__init__.py +0 -1
  194. dyno_phi-0.2.3/src/phi/commands/auth.py +0 -85
  195. dyno_phi-0.2.3/src/phi/commands/datasets.py +0 -142
  196. dyno_phi-0.2.3/src/phi/commands/filter.py +0 -86
  197. dyno_phi-0.2.3/src/phi/commands/jobs.py +0 -154
  198. dyno_phi-0.2.3/src/phi/commands/models.py +0 -177
  199. dyno_phi-0.2.3/src/phi/commands/research.py +0 -90
  200. dyno_phi-0.2.3/src/phi/commands/structure.py +0 -197
  201. dyno_phi-0.2.3/src/phi/commands/tutorial.py +0 -88
  202. dyno_phi-0.2.3/src/phi/config.py +0 -162
  203. dyno_phi-0.2.3/src/phi/display.py +0 -414
  204. dyno_phi-0.2.3/src/phi/download.py +0 -253
  205. dyno_phi-0.2.3/src/phi/parser.py +0 -672
  206. dyno_phi-0.2.3/src/phi/polling.py +0 -124
  207. dyno_phi-0.2.3/src/phi/research.py +0 -216
  208. dyno_phi-0.2.3/src/phi/structure.py +0 -106
  209. dyno_phi-0.2.3/src/phi/types.py +0 -33
  210. dyno_phi-0.2.3/src/phi/upload.py +0 -146
  211. dyno_phi-0.2.3/tests/__init__.py +0 -1
  212. dyno_phi-0.2.3/tests/test_api.py +0 -125
  213. dyno_phi-0.2.3/tests/test_config.py +0 -109
  214. dyno_phi-0.2.3/tests/test_display.py +0 -47
  215. dyno_phi-0.2.3/tests/test_download.py +0 -75
  216. dyno_phi-0.2.3/tests/test_research.py +0 -117
  217. dyno_phi-0.2.3/tests/test_structure.py +0 -149
  218. dyno_phi-0.2.3/tests/test_upload.py +0 -73
@@ -0,0 +1,125 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+ *.pyd
6
+ .Python
7
+
8
+ # Virtual environments
9
+ .venv/
10
+ .venv-install/
11
+ venv/
12
+ env/
13
+ dockq-venv/
14
+
15
+ # Distribution / packaging
16
+ dist/
17
+ build/
18
+ *.egg-info/
19
+ *.egg
20
+
21
+ # Testing
22
+ .pytest_cache/
23
+ .coverage
24
+ htmlcov/
25
+ .tox/
26
+
27
+ # Type checking
28
+ .mypy_cache/
29
+ .dmypy.json
30
+ .pyright/
31
+
32
+ # Environment files — never commit secrets
33
+ .env
34
+ .env.local
35
+ .env.*.local
36
+ *.env
37
+
38
+ # GCP service account keys
39
+ *.json
40
+ !pyproject.json
41
+ !.cursor/environment.json
42
+ !tests/fixtures/metrics/ipsae_nonzero_multisubchain.json
43
+ !tests/fixtures/bindcraft/run_metadata.json
44
+ !clients/phi/tests/fixtures/job_types.json
45
+ !clients/phi/tests/fixtures/run_pipelines.json
46
+ !experiments/campaigns/y7_design/config/score_hit_calibration.json
47
+ # Anchored to the repo root so it only blocks a top-level credential dir,
48
+ # not source packages that happen to be named `secrets/`.
49
+ /secrets/
50
+
51
+ # Team-facing engineering docs live in docs/ (committed).
52
+ # Local-only scratchpads / agent ephemera go in .scratch/.
53
+ .scratch/
54
+ scratch/
55
+
56
+ # IDE
57
+ .vscode/
58
+ .idea/
59
+ *.swp
60
+ *.swo
61
+
62
+ # Agent-only Cursor rule — local edit-time tooling, not a committed
63
+ # team artifact. The team-facing version of the same content lives in
64
+ # docs/model-integration-watchlist.md.
65
+ .cursor/rules/model-integration.mdc
66
+
67
+ # macOS
68
+ .DS_Store
69
+
70
+ # Alembic auto-generated (keep versions/ tracked)
71
+ alembic/versions/*.pyc
72
+
73
+ # Terraform state and local overrides
74
+ infrastructure/**/.terraform/
75
+ infrastructure/**/terraform.tfstate
76
+ infrastructure/**/terraform.tfstate.backup
77
+ infrastructure/**/*.tfvars
78
+ !infrastructure/**/terraform.tfvars.example
79
+ # Committed env var files — no secrets here; image_tag is always CI-supplied
80
+ !infrastructure/terraform/staging.tfvars
81
+ !infrastructure/terraform/production.tfvars
82
+ infrastructure/**/.terraform.lock.hcl
83
+
84
+ # Cloud Build local artifacts
85
+ cloudbuild/*.log
86
+ /runners/capsid-fold-esmfold2-base/source-artifact.zip
87
+ /runners/capsid-fold-esmfold2-base/source-artifact.sha256
88
+
89
+ # Docker
90
+ .dockerignore.local
91
+
92
+ *.pdb
93
+ !tests/fixtures/metrics/ipsae_nonzero_multisubchain.pdb
94
+ !examples/bindcraft2/*.pdb
95
+ *.cif
96
+ !examples/bindcraft2/*.cif
97
+ *.csv
98
+
99
+ # Large binary data / experiment outputs — use GCS, not git
100
+ *.parquet
101
+ *.pq
102
+ *.npz
103
+
104
+ # Canvas HTML dashboards (generated, not source-controlled)
105
+ canvas/
106
+
107
+ # Y4 campaign data and validation packages (binary + large CSVs)
108
+ experiments/campaigns/y4_agent_designs/data/
109
+ experiments/campaigns/y4_agent_designs/*.zip
110
+ experiments/campaigns/y4_agent_designs/y4_validation_package_*/
111
+
112
+ # CXCR3 campaign pipeline scratch — BoltzGen staging, fold inputs, large score tables
113
+ experiments/cxcr3_vhh_design/data/designs/.staging/
114
+ experiments/cxcr3_vhh_design/data/designs/**/.harvested_*
115
+ experiments/cxcr3_vhh_design/data/control_folds/
116
+ experiments/cxcr3_vhh_design/data/control_folds_templated/
117
+ experiments/cxcr3_vhh_design/data/scored/wave1_designs.tsv
118
+ experiments/cxcr3_vhh_design/data/scored/wave1_keep.tsv
119
+ experiments/cxcr3_vhh_design/data/scored/wave1_keep_sequences.tsv
120
+ experiments/cxcr3_vhh_design/data/scored/refold_manifest*.tsv
121
+
122
+ # Agent-development guide is account/app-specific (DynoPhiAgent). Other
123
+ # contributors run different agents/apps, so keep it local-only, not in the
124
+ # shared repo.
125
+ docs/agent-development.md
@@ -0,0 +1,53 @@
1
+ # Changelog
2
+
3
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
4
+ package follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The
5
+ version is read from `src/phi/_version.py`; a release is the tag `client-v<version>`
6
+ on `dynotx/phi-api`, which `.github/workflows/publish-client.yml` builds and publishes.
7
+
8
+ ## [0.3.0] - 2026-10-17
9
+
10
+ The first release of the Phi SDK and CLI on PyPI, published from `clients/phi` in
11
+ `dynotx/phi-api`. It was distributed as `phi-client` 0.0.1 from this repository
12
+ over git during the internal preview.
13
+
14
+ `dyno-phi` 0.2.x on PyPI was an earlier, unrelated client of a retired API. 0.3.0
15
+ replaces it under the same name; nothing from 0.2.x carries over.
16
+
17
+ ### Added
18
+
19
+ - `PhiClient` and `AsyncPhiClient` with the same resources and signatures:
20
+ `projects`, `datasets`, `sequences`, `designs`, `jobs`, `job_types`, `runs`,
21
+ `run_admin`, `artifacts`, `files`, `uploads`, `logs`, `quota`, `tool_configs`,
22
+ `imports`, `documents`.
23
+ - Typed request and response models, local JSON Schema validation of `params` and
24
+ `inputs` for every job type (`client.job_types.validate_params`), waiters for
25
+ jobs and runs, and a typed error taxonomy (`PhiError` and its subclasses).
26
+ - The `phi` CLI behind the `[cli]` extra, every command taking `--json`:
27
+ `auth`, `projects`, `datasets`, `docs`, `models`, `jobs`, `runs`, `pipeline`,
28
+ `artifacts`, `export`, `logs`, `quota`, `use`, `quickstart`.
29
+ - Profiles in `~/.config/phi/config.toml`, selected with `--profile` or
30
+ `PHI_PROFILE`.
31
+ - A Claude Code skill (`skills/phi/SKILL.md`) that drives the CLI.
32
+
33
+ ### Changed from `dyno-phi` 0.2.x
34
+
35
+ - Environment: `PHI_API` is the base URL and `PHI_KEY` or `PHI_API_KEY` the key
36
+ (`DYNO_API_BASE_URL` and `DYNO_API_KEY` are not read). `PHI_ORG` names the
37
+ organization for a static key; a Clerk key carries its own.
38
+ - Command tree: `phi <group> <command>` as listed above. `phi upload`, `phi filter`,
39
+ `phi research`, `phi notes`, `phi tutorial`, the filter presets and the
40
+ per-model commands (`phi esmfold`, `phi alphafold`, ...) are gone; a model runs
41
+ as `phi jobs submit <JOB_TYPE>` and a chain of models as `phi runs submit` or
42
+ `phi pipeline run`. `phi quickstart` is the walkthrough.
43
+ - State: `.phi/state.json` holds the active project and dataset and the last job
44
+ and run, nothing else; the API key is never written there.
45
+ - Python 3.12 or newer. The SDK depends on `httpx` and `pydantic` alone; the CLI's
46
+ dependencies install only with the `[cli]` extra.
47
+ - Web app: results open at `design.dynotx.com`; the dashboard URLs the old client
48
+ printed no longer exist.
49
+
50
+ Versioning note: the client stays below 1.0 while the API it speaks to is itself
51
+ pre-1.0 (0.1.x) and the request shapes can still change between releases. 0.3.0
52
+ is the first release on this line only because 0.2.x was already taken on PyPI
53
+ by the earlier client; it is not a continuation of it.
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.5
2
+ Name: dyno-phi
3
+ Version: 0.3.0
4
+ Summary: Phi — Python SDK and CLI for the Phi protein design API
5
+ Project-URL: Homepage, https://design.dynotx.com
6
+ Project-URL: Documentation, https://design.dynotx.com/docs
7
+ Project-URL: Source, https://github.com/dynotx/phi-api/tree/main/clients/phi
8
+ Project-URL: Changelog, https://github.com/dynotx/phi-api/blob/main/clients/phi/CHANGELOG.md
9
+ Project-URL: Issues, https://github.com/dynotx/phi-api/issues
10
+ Author: Dyno Therapeutics
11
+ License-Expression: MIT
12
+ Keywords: binder-design,bioinformatics,cli,protein-design,protein-engineering,sdk,structure-prediction
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.12
23
+ Requires-Dist: httpx>=0.27
24
+ Requires-Dist: pydantic>=2.9
25
+ Provides-Extra: cli
26
+ Requires-Dist: click>=8.1; extra == 'cli'
27
+ Requires-Dist: pyyaml>=6; extra == 'cli'
28
+ Requires-Dist: rich>=13; extra == 'cli'
29
+ Requires-Dist: typer>=0.12; extra == 'cli'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # dyno-phi
33
+
34
+ Python SDK and CLI for the [Phi](https://design.dynotx.com) protein design API.
35
+ The `phi` package exposes synchronous (`PhiClient`) and asynchronous
36
+ (`AsyncPhiClient`) clients; the CLI ships behind the `[cli]` extra so the SDK
37
+ stays light. It is published to PyPI from `clients/phi` in
38
+ [`dynotx/phi-api`](https://github.com/dynotx/phi-api).
39
+
40
+ ## Install
41
+
42
+ The CLI as an isolated tool on your `PATH`:
43
+
44
+ ```bash
45
+ uv tool install "dyno-phi[cli]"
46
+ ```
47
+
48
+ `uv tool` provisions its own Python, which covers the client's **Python 3.12+**
49
+ requirement on stock macOS, where the system Python is 3.9. Re-run with
50
+ `--upgrade` to upgrade. `pip install "dyno-phi[cli]"` into a Python 3.12+ of
51
+ your own does the same. From a `phi-api` checkout, `just install-cli` runs the
52
+ first form and `just install-cli-dev` installs the working tree.
53
+
54
+ The SDK inside an existing project, without the CLI's dependencies:
55
+
56
+ ```bash
57
+ uv add dyno-phi # or: pip install dyno-phi
58
+ ```
59
+
60
+ Check the install with `phi --version`. `dyno-phi` 0.2.x was an earlier,
61
+ unrelated client of a retired API; if `phi --version` prints `0.2.x`, that
62
+ client is first on your `PATH` (`which -a phi` lists every match) and
63
+ `pip install --upgrade "dyno-phi[cli]"` in the Python that owns it replaces it.
64
+ Coming from 0.2.x: the key is `PHI_API_KEY` (or `PHI_KEY`) and the base URL
65
+ `PHI_API`, the commands are `phi <group> <command>` as listed under
66
+ [CLI](#cli), and Python 3.12+ is required; see
67
+ [`CHANGELOG.md`](https://github.com/dynotx/phi-api/blob/main/clients/phi/CHANGELOG.md).
68
+
69
+ If `uv`'s tool directory is behind another `phi` on `PATH`, sourcing uv's shell
70
+ shim is not enough to move it: the shim prepends the directory only when `PATH`
71
+ does not already contain it, and on macOS `path_helper` appends inherited
72
+ entries behind `/etc/paths.d`, so in a shell that inherits a `PATH` naming the
73
+ directory it stays last. Pin the order at the end of `~/.zshrc`:
74
+
75
+ ```zsh
76
+ typeset -U path PATH
77
+ path=("$HOME/.local/bin" $path)
78
+ ```
79
+
80
+ ## Authentication
81
+
82
+ Both the SDK and the CLI read connection settings from the environment, falling
83
+ back to `~/.config/phi/config.toml`:
84
+
85
+ | Variable | Purpose |
86
+ |---|---|
87
+ | `PHI_API` | Base URL of the API. Its host selects the environment class — `hosted`, `staging`, or `local`. |
88
+ | `PHI_KEY` / `PHI_API_KEY` | API key. |
89
+ | `PHI_ORG` | Organization ID. Required with a static key. |
90
+
91
+ ```bash
92
+ export PHI_API=https://phi-api-staging-917387676927.us-central1.run.app
93
+ export PHI_KEY=... # static staging key
94
+ export PHI_ORG=dynotx # literal static tenant, not the Clerk org
95
+ ```
96
+
97
+ With a Clerk key (`ak_...`) the tenant comes from the key, so `PHI_ORG` is
98
+ ignored; it is required only for a static key.
99
+
100
+ Pass `base_url=`, `api_key=`, and `org=` to the client constructor to override
101
+ the environment.
102
+
103
+ ## 60-second quickstart
104
+
105
+ ```bash
106
+ phi quickstart
107
+ ```
108
+
109
+ Creates the `quickstart` project, folds the Trp-cage mini-protein with `ESMFOLD`,
110
+ waits, and downloads the results. The manual equivalent is:
111
+
112
+ ```bash
113
+ phi jobs submit ESMFOLD --input sequences=@sequence.fasta --wait --out quickstart-output
114
+ ```
115
+
116
+ ## SDK usage
117
+
118
+ Submit a job and wait for it, closing the client on exit:
119
+
120
+ ```python
121
+ from phi import PhiClient
122
+
123
+ with PhiClient() as client:
124
+ submitted = client.jobs.submit("ESMFOLD", inputs={"sequences": ["NLYIQWLKDGGPSSGRPPPS"]})
125
+ job = client.jobs.wait(submitted.job_id)
126
+ print(job.status, job.outputs)
127
+ ```
128
+
129
+ `AsyncPhiClient` mirrors the same surface for concurrent work:
130
+
131
+ ```python
132
+ import asyncio
133
+
134
+ from phi import AsyncPhiClient
135
+
136
+
137
+ async def fold(sequences: list[str]) -> list[str]:
138
+ async with AsyncPhiClient() as client:
139
+ submitted = await asyncio.gather(
140
+ *(client.jobs.submit("ESMFOLD", inputs={"sequences": [seq]}) for seq in sequences)
141
+ )
142
+ jobs = await asyncio.gather(*(client.jobs.wait(job.job_id) for job in submitted))
143
+ return [job.status for job in jobs]
144
+
145
+
146
+ asyncio.run(fold(["NLYIQWLKDGGPSSGRPPPS", "GSHMKELVLALYDYQEKSPRE"]))
147
+ ```
148
+
149
+ Runnable end-to-end scripts live in [`examples/`](examples/): single fold job,
150
+ named pipeline, ad-hoc DAG, artifact download, and concurrent async submission.
151
+
152
+ ### Job types and local validation
153
+
154
+ `client.job_types` lists the job types the API advertises and the JSON Schema for
155
+ each one's `params` and `inputs`. Schemas are cached on disk per host for 24 hours;
156
+ pass `refresh=True` to refetch.
157
+
158
+ ```python
159
+ client.job_types.validate_params("PROTEINMPNN", {"num_seq_per_target": 8})
160
+ ```
161
+
162
+ `validate_params` and `validate_inputs` raise `PhiValidationError` on a bad key,
163
+ type, enum value, or numeric range. They are a **shallow pre-flight check**:
164
+ top-level keys only, with no descent into nested objects or array items. The
165
+ server validates fully, so a clean pass locally is not a guarantee the request
166
+ will be accepted.
167
+
168
+ ### Knowledge documents
169
+
170
+ `client.documents` and `AsyncPhiClient.documents` list, read, search, write, and
171
+ review tenant-scoped Markdown documents. Use `iter_documents()` and
172
+ `iter_versions()` to follow cursor pages. Updates take the active digest as
173
+ `if_digest`; a stale value raises `PhiConflictError`. `propose()` creates a draft
174
+ that remains outside active reads and search until a document writer calls
175
+ `activate()`.
176
+
177
+ ## CLI
178
+
179
+ Every command reads the same environment and accepts `--json` for scripting.
180
+
181
+ | Group | Commands |
182
+ |---|---|
183
+ | `auth` | `login`, `whoami`, `logout`, `profiles` |
184
+ | `projects` | `list`, `create`, `show`, `update`, `archive` |
185
+ | `datasets` | `list`, `create`, `show`, `update`, `delete`, `copy`, `export`, `sequences` |
186
+ | `docs` | `list`, `read`, `search`, `add`, `update`, `history`, `propose`, `activate`, `sync` |
187
+ | `models` | `list`, `show`, `schema` |
188
+ | `jobs` | `submit`, `list`, `status`, `cancel`, `wait`, `embeddings` |
189
+ | `runs` | `submit`, `estimate`, `list`, `status`, `timeline`, `dag`, `cancel`, `resume` |
190
+ | `pipeline` | `run`, `validate`, `estimate` |
191
+ | `artifacts` | `list`, `download` |
192
+ | `export` | `sequences`, `designs`, `structure`, `pae` |
193
+ | `logs` | `show`, `download`, `settings` |
194
+ | `quota` | (summary), `history` |
195
+ | `use` | Set the active project |
196
+ | `quickstart` | Run the end-to-end ESMFOLD example |
197
+
198
+ `phi docs sync <dir> --dry-run` safely plans publication from a clean knowledge
199
+ checkout. Without `--dry-run` it publishes only Git-tracked files in the
200
+ authored Markdown layer after the checkout's deny-list guard passes, defaults
201
+ platform documents to internal access, and skips unchanged content and access.
202
+ It does not delete remote-only documents.
203
+
204
+ ## Full reference
205
+
206
+ See [`docs/sdk-and-cli.md`](https://github.com/dynotx/phi-api/blob/main/docs/sdk-and-cli.md)
207
+ for environment and profile resolution, sync/async parity, the complete CLI
208
+ reference, the error taxonomy and how a release is cut.
@@ -0,0 +1,177 @@
1
+ # dyno-phi
2
+
3
+ Python SDK and CLI for the [Phi](https://design.dynotx.com) protein design API.
4
+ The `phi` package exposes synchronous (`PhiClient`) and asynchronous
5
+ (`AsyncPhiClient`) clients; the CLI ships behind the `[cli]` extra so the SDK
6
+ stays light. It is published to PyPI from `clients/phi` in
7
+ [`dynotx/phi-api`](https://github.com/dynotx/phi-api).
8
+
9
+ ## Install
10
+
11
+ The CLI as an isolated tool on your `PATH`:
12
+
13
+ ```bash
14
+ uv tool install "dyno-phi[cli]"
15
+ ```
16
+
17
+ `uv tool` provisions its own Python, which covers the client's **Python 3.12+**
18
+ requirement on stock macOS, where the system Python is 3.9. Re-run with
19
+ `--upgrade` to upgrade. `pip install "dyno-phi[cli]"` into a Python 3.12+ of
20
+ your own does the same. From a `phi-api` checkout, `just install-cli` runs the
21
+ first form and `just install-cli-dev` installs the working tree.
22
+
23
+ The SDK inside an existing project, without the CLI's dependencies:
24
+
25
+ ```bash
26
+ uv add dyno-phi # or: pip install dyno-phi
27
+ ```
28
+
29
+ Check the install with `phi --version`. `dyno-phi` 0.2.x was an earlier,
30
+ unrelated client of a retired API; if `phi --version` prints `0.2.x`, that
31
+ client is first on your `PATH` (`which -a phi` lists every match) and
32
+ `pip install --upgrade "dyno-phi[cli]"` in the Python that owns it replaces it.
33
+ Coming from 0.2.x: the key is `PHI_API_KEY` (or `PHI_KEY`) and the base URL
34
+ `PHI_API`, the commands are `phi <group> <command>` as listed under
35
+ [CLI](#cli), and Python 3.12+ is required; see
36
+ [`CHANGELOG.md`](https://github.com/dynotx/phi-api/blob/main/clients/phi/CHANGELOG.md).
37
+
38
+ If `uv`'s tool directory is behind another `phi` on `PATH`, sourcing uv's shell
39
+ shim is not enough to move it: the shim prepends the directory only when `PATH`
40
+ does not already contain it, and on macOS `path_helper` appends inherited
41
+ entries behind `/etc/paths.d`, so in a shell that inherits a `PATH` naming the
42
+ directory it stays last. Pin the order at the end of `~/.zshrc`:
43
+
44
+ ```zsh
45
+ typeset -U path PATH
46
+ path=("$HOME/.local/bin" $path)
47
+ ```
48
+
49
+ ## Authentication
50
+
51
+ Both the SDK and the CLI read connection settings from the environment, falling
52
+ back to `~/.config/phi/config.toml`:
53
+
54
+ | Variable | Purpose |
55
+ |---|---|
56
+ | `PHI_API` | Base URL of the API. Its host selects the environment class — `hosted`, `staging`, or `local`. |
57
+ | `PHI_KEY` / `PHI_API_KEY` | API key. |
58
+ | `PHI_ORG` | Organization ID. Required with a static key. |
59
+
60
+ ```bash
61
+ export PHI_API=https://phi-api-staging-917387676927.us-central1.run.app
62
+ export PHI_KEY=... # static staging key
63
+ export PHI_ORG=dynotx # literal static tenant, not the Clerk org
64
+ ```
65
+
66
+ With a Clerk key (`ak_...`) the tenant comes from the key, so `PHI_ORG` is
67
+ ignored; it is required only for a static key.
68
+
69
+ Pass `base_url=`, `api_key=`, and `org=` to the client constructor to override
70
+ the environment.
71
+
72
+ ## 60-second quickstart
73
+
74
+ ```bash
75
+ phi quickstart
76
+ ```
77
+
78
+ Creates the `quickstart` project, folds the Trp-cage mini-protein with `ESMFOLD`,
79
+ waits, and downloads the results. The manual equivalent is:
80
+
81
+ ```bash
82
+ phi jobs submit ESMFOLD --input sequences=@sequence.fasta --wait --out quickstart-output
83
+ ```
84
+
85
+ ## SDK usage
86
+
87
+ Submit a job and wait for it, closing the client on exit:
88
+
89
+ ```python
90
+ from phi import PhiClient
91
+
92
+ with PhiClient() as client:
93
+ submitted = client.jobs.submit("ESMFOLD", inputs={"sequences": ["NLYIQWLKDGGPSSGRPPPS"]})
94
+ job = client.jobs.wait(submitted.job_id)
95
+ print(job.status, job.outputs)
96
+ ```
97
+
98
+ `AsyncPhiClient` mirrors the same surface for concurrent work:
99
+
100
+ ```python
101
+ import asyncio
102
+
103
+ from phi import AsyncPhiClient
104
+
105
+
106
+ async def fold(sequences: list[str]) -> list[str]:
107
+ async with AsyncPhiClient() as client:
108
+ submitted = await asyncio.gather(
109
+ *(client.jobs.submit("ESMFOLD", inputs={"sequences": [seq]}) for seq in sequences)
110
+ )
111
+ jobs = await asyncio.gather(*(client.jobs.wait(job.job_id) for job in submitted))
112
+ return [job.status for job in jobs]
113
+
114
+
115
+ asyncio.run(fold(["NLYIQWLKDGGPSSGRPPPS", "GSHMKELVLALYDYQEKSPRE"]))
116
+ ```
117
+
118
+ Runnable end-to-end scripts live in [`examples/`](examples/): single fold job,
119
+ named pipeline, ad-hoc DAG, artifact download, and concurrent async submission.
120
+
121
+ ### Job types and local validation
122
+
123
+ `client.job_types` lists the job types the API advertises and the JSON Schema for
124
+ each one's `params` and `inputs`. Schemas are cached on disk per host for 24 hours;
125
+ pass `refresh=True` to refetch.
126
+
127
+ ```python
128
+ client.job_types.validate_params("PROTEINMPNN", {"num_seq_per_target": 8})
129
+ ```
130
+
131
+ `validate_params` and `validate_inputs` raise `PhiValidationError` on a bad key,
132
+ type, enum value, or numeric range. They are a **shallow pre-flight check**:
133
+ top-level keys only, with no descent into nested objects or array items. The
134
+ server validates fully, so a clean pass locally is not a guarantee the request
135
+ will be accepted.
136
+
137
+ ### Knowledge documents
138
+
139
+ `client.documents` and `AsyncPhiClient.documents` list, read, search, write, and
140
+ review tenant-scoped Markdown documents. Use `iter_documents()` and
141
+ `iter_versions()` to follow cursor pages. Updates take the active digest as
142
+ `if_digest`; a stale value raises `PhiConflictError`. `propose()` creates a draft
143
+ that remains outside active reads and search until a document writer calls
144
+ `activate()`.
145
+
146
+ ## CLI
147
+
148
+ Every command reads the same environment and accepts `--json` for scripting.
149
+
150
+ | Group | Commands |
151
+ |---|---|
152
+ | `auth` | `login`, `whoami`, `logout`, `profiles` |
153
+ | `projects` | `list`, `create`, `show`, `update`, `archive` |
154
+ | `datasets` | `list`, `create`, `show`, `update`, `delete`, `copy`, `export`, `sequences` |
155
+ | `docs` | `list`, `read`, `search`, `add`, `update`, `history`, `propose`, `activate`, `sync` |
156
+ | `models` | `list`, `show`, `schema` |
157
+ | `jobs` | `submit`, `list`, `status`, `cancel`, `wait`, `embeddings` |
158
+ | `runs` | `submit`, `estimate`, `list`, `status`, `timeline`, `dag`, `cancel`, `resume` |
159
+ | `pipeline` | `run`, `validate`, `estimate` |
160
+ | `artifacts` | `list`, `download` |
161
+ | `export` | `sequences`, `designs`, `structure`, `pae` |
162
+ | `logs` | `show`, `download`, `settings` |
163
+ | `quota` | (summary), `history` |
164
+ | `use` | Set the active project |
165
+ | `quickstart` | Run the end-to-end ESMFOLD example |
166
+
167
+ `phi docs sync <dir> --dry-run` safely plans publication from a clean knowledge
168
+ checkout. Without `--dry-run` it publishes only Git-tracked files in the
169
+ authored Markdown layer after the checkout's deny-list guard passes, defaults
170
+ platform documents to internal access, and skips unchanged content and access.
171
+ It does not delete remote-only documents.
172
+
173
+ ## Full reference
174
+
175
+ See [`docs/sdk-and-cli.md`](https://github.com/dynotx/phi-api/blob/main/docs/sdk-and-cli.md)
176
+ for environment and profile resolution, sync/async parity, the complete CLI
177
+ reference, the error taxonomy and how a release is cut.
@@ -0,0 +1,25 @@
1
+ # phi examples
2
+
3
+ Runnable SDK scripts. Each reads connection settings from the environment
4
+ (`PHI_API`, `PHI_KEY` or `PHI_API_KEY`, and `PHI_ORG` for a static key) and can
5
+ be run directly:
6
+
7
+ ```bash
8
+ python examples/submit_fold.py
9
+ ```
10
+
11
+ | Script | What it shows |
12
+ |---|---|
13
+ | [`submit_fold.py`](submit_fold.py) | Submit one ESMFOLD job and wait for it to finish. |
14
+ | [`run_pipeline.py`](run_pipeline.py) | Run the named `SCORE_BACKBONES` pipeline seeded from a prior run. |
15
+ | [`compose_dag.py`](compose_dag.py) | Build an ad-hoc ProteinMPNN → ESMFold `PipelineGraph` and submit it as one job. |
16
+ | [`download_results.py`](download_results.py) | List a run's artifacts, download them, and read the manifest. |
17
+ | [`async_concurrent.py`](async_concurrent.py) | Submit several jobs concurrently with `AsyncPhiClient`. |
18
+
19
+ Scripts that need a project or run identifier take it as an argument, e.g.
20
+ `python examples/compose_dag.py <project_id>`.
21
+
22
+ Other assets in this directory:
23
+
24
+ - [`quickstart/`](quickstart/) — the input FASTA used by `phi quickstart`.
25
+ - [`pipelines/`](pipelines/) — graph YAML files for `phi pipeline run -f`.
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+
5
+ from phi import AsyncPhiClient
6
+
7
+ SEQUENCES = [
8
+ "NLYIQWLKDGGPSSGRPPPS",
9
+ "GSHMKELVLALYDYQEKSPRE",
10
+ "MKTAYIAKQRQISFVKSHFSRQ",
11
+ ]
12
+
13
+
14
+ async def main(sequences: list[str] = SEQUENCES, batch_id: str = "esmfold-sweep") -> list[str]:
15
+ async with AsyncPhiClient() as client:
16
+ # One batch_id ties the sweep together: GET /v1/batches/{batch_id} reads "n of N done".
17
+ submitted = await asyncio.gather(
18
+ *(
19
+ client.jobs.submit("ESMFOLD", inputs={"sequences": [seq]}, batch_id=batch_id)
20
+ for seq in sequences
21
+ )
22
+ )
23
+ jobs = await asyncio.gather(*(client.jobs.wait(job.job_id) for job in submitted))
24
+ statuses: list[str] = [job.status for job in jobs]
25
+ for job in jobs:
26
+ print(f"{job.job_id}: {job.status}")
27
+ return statuses
28
+
29
+
30
+ if __name__ == "__main__":
31
+ asyncio.run(main())
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+
5
+ from phi import PhiClient, PipelineGraph
6
+
7
+
8
+ def main(project_id: str) -> str:
9
+ graph = PipelineGraph()
10
+ design = graph.add("proteinmpnn")
11
+ fold = graph.add("esmfold")
12
+ graph.connect(design.sequences, fold.sequences)
13
+ graph.validate()
14
+
15
+ with PhiClient() as client:
16
+ submitted = client.jobs.submit_graph(graph, project_id=project_id)
17
+ print(f"{submitted.job_id}: {submitted.status} ({submitted.estimated_credits} credits)")
18
+ return submitted.job_id
19
+
20
+
21
+ if __name__ == "__main__":
22
+ main(sys.argv[1])
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ from phi import PhiClient
8
+
9
+
10
+ def main(run_id: str, out_dir: str | Path = "results") -> Path:
11
+ with PhiClient() as client:
12
+ artifacts = client.artifacts.list(run_id, suffix=".cif")
13
+ manifest_path = client.artifacts.download(artifacts, out_dir)
14
+ manifest = json.loads(manifest_path.read_text())
15
+ for entry in manifest:
16
+ print(f"{entry['status']:>10} {entry['path']}")
17
+ return manifest_path
18
+
19
+
20
+ if __name__ == "__main__":
21
+ main(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else "results")
@@ -0,0 +1,10 @@
1
+ nodes:
2
+ - id: fold
3
+ tool: esmfold
4
+ mode: ""
5
+ - id: score
6
+ tool: analysis
7
+ mode: ""
8
+ edges:
9
+ - from: fold.sequences
10
+ to: score.sequences