@moldesk/registry 0.0.1 → 0.0.3
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.
- package/dist/errors.d.ts +14 -0
- package/dist/errors.js +14 -0
- package/dist/index.d.ts +7 -14
- package/dist/index.js +4 -29
- package/dist/loader.d.ts +5 -0
- package/dist/loader.js +128 -0
- package/dist/loader.test.d.ts +1 -0
- package/dist/loader.test.js +72 -0
- package/dist/models/bindcraft2/manifest.yaml +178 -0
- package/dist/models/boltz/manifest.yaml +155 -0
- package/dist/models/diffdock/manifest.yaml +219 -0
- package/dist/models/ligandmpnn/manifest.yaml +67 -0
- package/dist/models/opendde/manifest.yaml +169 -0
- package/dist/models/proteinmpnn/manifest.yaml +43 -0
- package/dist/runtime-selection.d.ts +24 -0
- package/dist/runtime-selection.js +54 -0
- package/dist/runtime-selection.test.d.ts +1 -0
- package/dist/runtime-selection.test.js +84 -0
- package/dist/schema.d.ts +1226 -0
- package/dist/schema.js +337 -0
- package/dist/schema.test.d.ts +1 -0
- package/dist/schema.test.js +335 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.js +1 -0
- package/package.json +8 -5
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface MoldeskErrorData {
|
|
2
|
+
code: string;
|
|
3
|
+
message: string;
|
|
4
|
+
remediation?: string;
|
|
5
|
+
cause?: unknown;
|
|
6
|
+
details?: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
export declare class MoldeskError extends Error {
|
|
9
|
+
readonly code: string;
|
|
10
|
+
readonly remediation?: string;
|
|
11
|
+
readonly cause?: unknown;
|
|
12
|
+
readonly details?: Record<string, unknown>;
|
|
13
|
+
constructor(data: MoldeskErrorData);
|
|
14
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export class MoldeskError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
remediation;
|
|
4
|
+
cause;
|
|
5
|
+
details;
|
|
6
|
+
constructor(data) {
|
|
7
|
+
super(data.message);
|
|
8
|
+
this.name = "MoldeskError";
|
|
9
|
+
this.code = data.code;
|
|
10
|
+
this.remediation = data.remediation;
|
|
11
|
+
this.cause = data.cause;
|
|
12
|
+
this.details = data.details;
|
|
13
|
+
}
|
|
14
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
compatibility?: {
|
|
9
|
-
cpu?: boolean;
|
|
10
|
-
gpu?: "required" | "recommended" | "unsupported";
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
export declare function listAvailableModels(): ModelManifest[];
|
|
14
|
-
export declare function listInstalledModels(): ModelManifest[];
|
|
1
|
+
export { MoldeskError } from "./errors.js";
|
|
2
|
+
export type { MoldeskErrorData } from "./errors.js";
|
|
3
|
+
export { allowedCommandTokens, commandSpecSchema, modelManifestV1Schema, } from "./schema.js";
|
|
4
|
+
export type { AssetSpec, CommandSpec, HardwareRequirements, InputSpec, ModelCategory, ModelManifestV1, ModelStatus, OutputSpec, PlatformId, PostInstallHook, PythonRequirement, PythonRuntimeSpec, DockerRuntimeSpec, RequirementLevel, RuntimeKind, RuntimeSpec, SourceSpec, } from "./schema.js";
|
|
5
|
+
export type { LegacyModelManifest } from "./types.js";
|
|
6
|
+
export { getModelsDir, listAvailableModels, loadManifestFile, parseManifest, } from "./loader.js";
|
|
7
|
+
export { detectHostPlatformId, effectiveRuntimeSource, selectPythonRuntime, } from "./runtime-selection.js";
|
package/dist/index.js
CHANGED
|
@@ -1,29 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
function repoModelsDir() {
|
|
7
|
-
// packages/registry/src -> repo root -> models
|
|
8
|
-
return path.resolve(__dirname, "../../../models");
|
|
9
|
-
}
|
|
10
|
-
export function listAvailableModels() {
|
|
11
|
-
const modelsDir = repoModelsDir();
|
|
12
|
-
if (!fs.existsSync(modelsDir))
|
|
13
|
-
return [];
|
|
14
|
-
return fs
|
|
15
|
-
.readdirSync(modelsDir, { withFileTypes: true })
|
|
16
|
-
.filter((entry) => entry.isDirectory())
|
|
17
|
-
.map((entry) => {
|
|
18
|
-
const manifestPath = path.join(modelsDir, entry.name, "manifest.yaml");
|
|
19
|
-
if (!fs.existsSync(manifestPath))
|
|
20
|
-
return null;
|
|
21
|
-
const raw = fs.readFileSync(manifestPath, "utf-8");
|
|
22
|
-
return YAML.parse(raw);
|
|
23
|
-
})
|
|
24
|
-
.filter((manifest) => manifest !== null);
|
|
25
|
-
}
|
|
26
|
-
export function listInstalledModels() {
|
|
27
|
-
// No models are installed yet — installation support lands with `moldesk install`.
|
|
28
|
-
return [];
|
|
29
|
-
}
|
|
1
|
+
export { MoldeskError } from "./errors.js";
|
|
2
|
+
export { allowedCommandTokens, commandSpecSchema, modelManifestV1Schema, } from "./schema.js";
|
|
3
|
+
export { getModelsDir, listAvailableModels, loadManifestFile, parseManifest, } from "./loader.js";
|
|
4
|
+
export { detectHostPlatformId, effectiveRuntimeSource, selectPythonRuntime, } from "./runtime-selection.js";
|
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type ModelManifestV1 } from "./schema.js";
|
|
2
|
+
export declare function parseManifest(raw: unknown, manifestPath: string): ModelManifestV1;
|
|
3
|
+
export declare function loadManifestFile(manifestPath: string): ModelManifestV1;
|
|
4
|
+
export declare function listAvailableModels(modelsDir?: string): ModelManifestV1[];
|
|
5
|
+
export declare function getModelsDir(): string;
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import YAML from "yaml";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { MoldeskError } from "./errors.js";
|
|
7
|
+
import { modelManifestV1Schema } from "./schema.js";
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
function packagedModelsDir() {
|
|
10
|
+
return path.resolve(__dirname, "models");
|
|
11
|
+
}
|
|
12
|
+
function sourceModelsDir() {
|
|
13
|
+
// packages/registry/src -> repo root -> models (dev fallback only)
|
|
14
|
+
return path.resolve(__dirname, "../../../models");
|
|
15
|
+
}
|
|
16
|
+
function resolveModelsDir() {
|
|
17
|
+
const override = process.env["MOLDESK_MODELS_DIR"];
|
|
18
|
+
if (override && fs.existsSync(override))
|
|
19
|
+
return override;
|
|
20
|
+
if (fs.existsSync(packagedModelsDir()))
|
|
21
|
+
return packagedModelsDir();
|
|
22
|
+
if (fs.existsSync(sourceModelsDir()))
|
|
23
|
+
return sourceModelsDir();
|
|
24
|
+
throw new MoldeskError({
|
|
25
|
+
code: "REGISTRY_NOT_FOUND",
|
|
26
|
+
message: "MoleculeDesk model registry is missing from this installation.",
|
|
27
|
+
remediation: "Reinstall @moldesk/cli. Package maintainers should verify that @moldesk/registry includes dist/models.",
|
|
28
|
+
details: { packagedModelsDir: packagedModelsDir(), sourceModelsDir: sourceModelsDir() },
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function toMoldeskError(manifestPath, error) {
|
|
32
|
+
if (error instanceof z.ZodError) {
|
|
33
|
+
const first = error.issues[0];
|
|
34
|
+
const field = first && first.path.length > 0 ? first.path.join(".") : "(root)";
|
|
35
|
+
return new MoldeskError({
|
|
36
|
+
code: "INVALID_MANIFEST",
|
|
37
|
+
message: `Invalid manifest ${manifestPath}: ${field}: ${first?.message ?? "validation failed"}`,
|
|
38
|
+
remediation: "Fix the manifest field and re-run the registry build. See docs/v0.1-implementation-spec.md Step 1.",
|
|
39
|
+
details: { manifestPath, field, issues: error.issues },
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return new MoldeskError({
|
|
43
|
+
code: "INVALID_MANIFEST",
|
|
44
|
+
message: `Invalid manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
45
|
+
remediation: "Ensure the file is valid YAML matching ModelManifestV1.",
|
|
46
|
+
details: { manifestPath },
|
|
47
|
+
cause: error,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export function parseManifest(raw, manifestPath) {
|
|
51
|
+
if (typeof raw !== "object" || raw === null) {
|
|
52
|
+
throw new MoldeskError({
|
|
53
|
+
code: "INVALID_MANIFEST",
|
|
54
|
+
message: `Invalid manifest ${manifestPath}: root must be a mapping`,
|
|
55
|
+
remediation: "Ensure the manifest is a YAML mapping with schemaVersion: 1.",
|
|
56
|
+
details: { manifestPath },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const record = raw;
|
|
60
|
+
if (record["schemaVersion"] !== 1) {
|
|
61
|
+
throw new MoldeskError({
|
|
62
|
+
code: "UNKNOWN_SCHEMA_VERSION",
|
|
63
|
+
message: `Unknown schema version in ${manifestPath}: ${String(record["schemaVersion"])}`,
|
|
64
|
+
remediation: "Set schemaVersion: 1. Only v1 manifests are supported in v0.1.",
|
|
65
|
+
details: { manifestPath, schemaVersion: record["schemaVersion"] },
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if ("version" in record && !("modelVersion" in record)) {
|
|
69
|
+
throw new MoldeskError({
|
|
70
|
+
code: "INVALID_MANIFEST",
|
|
71
|
+
message: `Invalid manifest ${manifestPath}: ambiguous top-level "version" field; use modelVersion + adapterVersion`,
|
|
72
|
+
remediation: "Rename version to modelVersion and add adapterVersion.",
|
|
73
|
+
details: { manifestPath, field: "version" },
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
return modelManifestV1Schema.parse(raw);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
throw toMoldeskError(manifestPath, error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export function loadManifestFile(manifestPath) {
|
|
84
|
+
let raw;
|
|
85
|
+
try {
|
|
86
|
+
raw = YAML.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
throw new MoldeskError({
|
|
90
|
+
code: "INVALID_MANIFEST",
|
|
91
|
+
message: `Invalid manifest ${manifestPath}: YAML parse failed`,
|
|
92
|
+
remediation: "Fix YAML syntax.",
|
|
93
|
+
details: { manifestPath },
|
|
94
|
+
cause: error,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return parseManifest(raw, manifestPath);
|
|
98
|
+
}
|
|
99
|
+
export function listAvailableModels(modelsDir) {
|
|
100
|
+
const dir = modelsDir ?? resolveModelsDir();
|
|
101
|
+
if (!fs.existsSync(dir))
|
|
102
|
+
return [];
|
|
103
|
+
const manifests = [];
|
|
104
|
+
const seen = new Set();
|
|
105
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
106
|
+
if (!entry.isDirectory())
|
|
107
|
+
continue;
|
|
108
|
+
const manifestPath = path.join(dir, entry.name, "manifest.yaml");
|
|
109
|
+
if (!fs.existsSync(manifestPath))
|
|
110
|
+
continue;
|
|
111
|
+
const manifest = loadManifestFile(manifestPath);
|
|
112
|
+
if (seen.has(manifest.name)) {
|
|
113
|
+
throw new MoldeskError({
|
|
114
|
+
code: "DUPLICATE_MODEL_ID",
|
|
115
|
+
message: `Duplicate model id "${manifest.name}" in ${manifestPath}`,
|
|
116
|
+
remediation: "Rename one model so every manifest name is unique.",
|
|
117
|
+
details: { manifestPath, name: manifest.name },
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
seen.add(manifest.name);
|
|
121
|
+
manifests.push(manifest);
|
|
122
|
+
}
|
|
123
|
+
manifests.sort((a, b) => a.name.localeCompare(b.name));
|
|
124
|
+
return manifests;
|
|
125
|
+
}
|
|
126
|
+
export function getModelsDir() {
|
|
127
|
+
return resolveModelsDir();
|
|
128
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
5
|
+
import YAML from "yaml";
|
|
6
|
+
import { MoldeskError } from "./errors.js";
|
|
7
|
+
import { listAvailableModels } from "./loader.js";
|
|
8
|
+
const tempDirs = [];
|
|
9
|
+
function makeTempDir(prefix) {
|
|
10
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
11
|
+
tempDirs.push(dir);
|
|
12
|
+
return dir;
|
|
13
|
+
}
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
for (const dir of tempDirs.splice(0))
|
|
16
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
17
|
+
});
|
|
18
|
+
function writeManifest(dir, name, overrides = {}) {
|
|
19
|
+
const base = {
|
|
20
|
+
schemaVersion: 1,
|
|
21
|
+
name,
|
|
22
|
+
displayName: name,
|
|
23
|
+
modelVersion: "1.0.0",
|
|
24
|
+
adapterVersion: "0.1.0",
|
|
25
|
+
description: `${name} model`,
|
|
26
|
+
category: "other",
|
|
27
|
+
status: "beta",
|
|
28
|
+
runtimes: [{ kind: "python", python: "3.11", installer: "uv", requirements: [{ name: "torch" }] }],
|
|
29
|
+
hardware: {},
|
|
30
|
+
input: { formats: [".pdb"], required: true },
|
|
31
|
+
outputs: [{ id: "out", glob: "*.txt", required: true }],
|
|
32
|
+
...overrides,
|
|
33
|
+
};
|
|
34
|
+
const modelDir = path.join(dir, name);
|
|
35
|
+
fs.mkdirSync(modelDir, { recursive: true });
|
|
36
|
+
fs.writeFileSync(path.join(modelDir, "manifest.yaml"), YAML.stringify(base));
|
|
37
|
+
}
|
|
38
|
+
describe("listAvailableModels", () => {
|
|
39
|
+
it("discovers validated manifests sorted by name", () => {
|
|
40
|
+
const dir = makeTempDir("moldesk-registry-");
|
|
41
|
+
writeManifest(dir, "zebra");
|
|
42
|
+
writeManifest(dir, "alpha");
|
|
43
|
+
const models = listAvailableModels(dir);
|
|
44
|
+
expect(models.map((m) => m.name)).toEqual(["alpha", "zebra"]);
|
|
45
|
+
});
|
|
46
|
+
it("throws DUPLICATE_MODEL_ID on duplicate names", () => {
|
|
47
|
+
const dir = makeTempDir("moldesk-dup-");
|
|
48
|
+
writeManifest(dir, "dir-a", { name: "same" });
|
|
49
|
+
writeManifest(dir, "dir-b", { name: "same" });
|
|
50
|
+
try {
|
|
51
|
+
listAvailableModels(dir);
|
|
52
|
+
expect.unreachable();
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
expect(error).toBeInstanceOf(MoldeskError);
|
|
56
|
+
expect(error.code).toBe("DUPLICATE_MODEL_ID");
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
it("loads default manifests relative to the module, not cwd", () => {
|
|
60
|
+
const originalCwd = process.cwd();
|
|
61
|
+
const unrelatedCwd = makeTempDir("moldesk-unrelated-cwd-");
|
|
62
|
+
try {
|
|
63
|
+
process.chdir(unrelatedCwd);
|
|
64
|
+
const models = listAvailableModels();
|
|
65
|
+
const names = models.map((m) => m.name).sort();
|
|
66
|
+
expect(names).toEqual(["bindcraft2", "boltz", "diffdock", "ligandmpnn", "opendde", "proteinmpnn"]);
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
process.chdir(originalCwd);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
schemaVersion: 1
|
|
2
|
+
name: bindcraft2
|
|
3
|
+
displayName: BindCraft2
|
|
4
|
+
modelVersion: 1.0.3
|
|
5
|
+
adapterVersion: 0.1.0
|
|
6
|
+
description: Bounded local protein-binder campaigns with AlphaFold and ProteinMPNN/HyperMPNN.
|
|
7
|
+
category: sequence-design
|
|
8
|
+
status: planned
|
|
9
|
+
license: BindCraft2 Source-Available License (Hosting-Restricted)
|
|
10
|
+
homepage: https://github.com/PacesaLab/BindCraft2
|
|
11
|
+
source:
|
|
12
|
+
repository: https://github.com/PacesaLab/BindCraft2
|
|
13
|
+
revision: 5bac63cd2d4e7ed3d5077ba4fc5966e0352038e4
|
|
14
|
+
# Linux dependency resolution passed; no live accelerator verification yet.
|
|
15
|
+
runtimes:
|
|
16
|
+
- kind: python
|
|
17
|
+
python: "3.12"
|
|
18
|
+
installer: uv
|
|
19
|
+
platforms: [linux-x64]
|
|
20
|
+
estimatedDownloadBytes: 10000000000
|
|
21
|
+
estimatedDiskBytes: 20000000000
|
|
22
|
+
nvidiaGpu: required
|
|
23
|
+
cuda:
|
|
24
|
+
level: required
|
|
25
|
+
minDriverCudaVersion: "12.1"
|
|
26
|
+
binaryOnly: [jaxlib, jax-cuda12-plugin, jax-cuda12-pjrt, cuequivariance-ops-cu12]
|
|
27
|
+
requirements:
|
|
28
|
+
- name: bindcraft
|
|
29
|
+
source: https://github.com/PacesaLab/BindCraft2
|
|
30
|
+
revision: 5bac63cd2d4e7ed3d5077ba4fc5966e0352038e4
|
|
31
|
+
extras: [cuda12]
|
|
32
|
+
- name: absl-py
|
|
33
|
+
version: "2.5.0"
|
|
34
|
+
- name: biotite
|
|
35
|
+
version: "1.7.1"
|
|
36
|
+
- name: biotraj
|
|
37
|
+
version: "1.2.2"
|
|
38
|
+
- name: certifi
|
|
39
|
+
version: "2026.7.22"
|
|
40
|
+
- name: charset-normalizer
|
|
41
|
+
version: "3.5.2"
|
|
42
|
+
- name: contourpy
|
|
43
|
+
version: "1.4.0"
|
|
44
|
+
- name: cuequivariance
|
|
45
|
+
version: "0.11.1"
|
|
46
|
+
- name: cuequivariance-jax
|
|
47
|
+
version: "0.11.1"
|
|
48
|
+
- name: cuequivariance-ops-cu12
|
|
49
|
+
version: "0.11.1"
|
|
50
|
+
hashes: ["dfb05a8a87ba657e5aa0019a27ceaccfd0152c69646ce5039bcc9eafc9fc0c33"]
|
|
51
|
+
- name: cycler
|
|
52
|
+
version: "0.12.1"
|
|
53
|
+
- name: dm-haiku
|
|
54
|
+
version: "0.0.17"
|
|
55
|
+
- name: einops
|
|
56
|
+
version: "0.8.2"
|
|
57
|
+
- name: fonttools
|
|
58
|
+
version: "4.66.1"
|
|
59
|
+
- name: idna
|
|
60
|
+
version: "3.20"
|
|
61
|
+
- name: jax
|
|
62
|
+
version: "0.11.2"
|
|
63
|
+
- name: jax-cuda12-pjrt
|
|
64
|
+
version: "0.11.2"
|
|
65
|
+
hashes: ["2133b3afc63307c016ae4980f166b2b3de199759363ead74f7d550eaae953463"]
|
|
66
|
+
- name: jax-cuda12-plugin
|
|
67
|
+
version: "0.11.2"
|
|
68
|
+
hashes: ["ae67a4cc49b34c575713a8311f7597f6700ec5a2b6afbdbc3db5550fb022873c"]
|
|
69
|
+
- name: jaxlib
|
|
70
|
+
version: "0.11.2"
|
|
71
|
+
hashes: ["6338a1f0956f60d02529404ac33a8070015a52635cdb6bbb15d0d199757077bb"]
|
|
72
|
+
- name: jmp
|
|
73
|
+
version: "0.0.4"
|
|
74
|
+
- name: kiwisolver
|
|
75
|
+
version: "1.5.1"
|
|
76
|
+
- name: matplotlib
|
|
77
|
+
version: "3.11.2"
|
|
78
|
+
- name: ml-collections
|
|
79
|
+
version: "1.1.0"
|
|
80
|
+
- name: ml-dtypes
|
|
81
|
+
version: "0.6.0"
|
|
82
|
+
- name: mpmath
|
|
83
|
+
version: "1.3.0"
|
|
84
|
+
- name: msgpack
|
|
85
|
+
version: "1.2.3"
|
|
86
|
+
- name: networkx
|
|
87
|
+
version: "3.7"
|
|
88
|
+
- name: numpy
|
|
89
|
+
version: "2.5.3"
|
|
90
|
+
- name: nvidia-cublas-cu12
|
|
91
|
+
version: "12.9.2.10"
|
|
92
|
+
- name: nvidia-cuda-cccl-cu12
|
|
93
|
+
version: "12.9.27"
|
|
94
|
+
- name: nvidia-cuda-cupti-cu12
|
|
95
|
+
version: "12.9.79"
|
|
96
|
+
- name: nvidia-cuda-nvcc-cu12
|
|
97
|
+
version: "12.9.86"
|
|
98
|
+
- name: nvidia-cuda-nvrtc-cu12
|
|
99
|
+
version: "12.9.86"
|
|
100
|
+
- name: nvidia-cuda-runtime-cu12
|
|
101
|
+
version: "12.9.79"
|
|
102
|
+
- name: nvidia-cudnn-cu12
|
|
103
|
+
version: "9.27.0.42"
|
|
104
|
+
- name: nvidia-cufft-cu12
|
|
105
|
+
version: "11.4.1.4"
|
|
106
|
+
- name: nvidia-cusolver-cu12
|
|
107
|
+
version: "11.7.5.82"
|
|
108
|
+
- name: nvidia-cusparse-cu12
|
|
109
|
+
version: "12.5.10.65"
|
|
110
|
+
- name: nvidia-ml-py
|
|
111
|
+
version: "13.615.71"
|
|
112
|
+
- name: nvidia-nccl-cu12
|
|
113
|
+
version: "2.32.3"
|
|
114
|
+
- name: nvidia-nvjitlink-cu12
|
|
115
|
+
version: "12.9.86"
|
|
116
|
+
- name: nvidia-nvshmem-cu12
|
|
117
|
+
version: "3.8.0"
|
|
118
|
+
- name: opt-einsum
|
|
119
|
+
version: "3.4.0"
|
|
120
|
+
- name: optax
|
|
121
|
+
version: "0.2.8"
|
|
122
|
+
- name: packaging
|
|
123
|
+
version: "26.3"
|
|
124
|
+
- name: pillow
|
|
125
|
+
version: "12.3.0"
|
|
126
|
+
- name: platformdirs
|
|
127
|
+
version: "4.12.3"
|
|
128
|
+
- name: pyparsing
|
|
129
|
+
version: "3.3.3"
|
|
130
|
+
- name: python-dateutil
|
|
131
|
+
version: "2.9.0.post0"
|
|
132
|
+
- name: pyyaml
|
|
133
|
+
version: "6.0.3"
|
|
134
|
+
- name: requests
|
|
135
|
+
version: "2.34.2"
|
|
136
|
+
- name: scipy
|
|
137
|
+
version: "1.18.1"
|
|
138
|
+
- name: six
|
|
139
|
+
version: "1.17.0"
|
|
140
|
+
- name: sympy
|
|
141
|
+
version: "1.14.0"
|
|
142
|
+
- name: tabulate
|
|
143
|
+
version: "0.10.0"
|
|
144
|
+
- name: tqdm
|
|
145
|
+
version: "4.70.1"
|
|
146
|
+
- name: urllib3
|
|
147
|
+
version: "2.8.0"
|
|
148
|
+
hardware:
|
|
149
|
+
platforms: [linux-x64]
|
|
150
|
+
nvidiaGpu: required
|
|
151
|
+
cuda:
|
|
152
|
+
level: required
|
|
153
|
+
minDriverCudaVersion: "12.1"
|
|
154
|
+
minRamGb: 24
|
|
155
|
+
minDiskGb: 25
|
|
156
|
+
assets:
|
|
157
|
+
- id: alphafold-parameters
|
|
158
|
+
url: https://storage.googleapis.com/alphafold/alphafold_params_2022-12-06.tar?generation=1670353726160664
|
|
159
|
+
source: DeepMind AlphaFold parameters 2022-12-06
|
|
160
|
+
license: CC-BY-4.0
|
|
161
|
+
sha256: 36d4b0220f3c735f3296d301152b738c9776d16981d054845a68a1370b26cfe3
|
|
162
|
+
sizeBytes: 5587968000
|
|
163
|
+
target: alphafold
|
|
164
|
+
archive: tar
|
|
165
|
+
input:
|
|
166
|
+
formats: [.json]
|
|
167
|
+
required: true
|
|
168
|
+
outputs:
|
|
169
|
+
- { id: campaign, glob: moldesk-campaign.json, required: true }
|
|
170
|
+
- { id: metadata, glob: campaign_metadata.json, required: true }
|
|
171
|
+
- { id: trajectories, glob: "1_Trajectories/!_Trajectories.csv", required: true }
|
|
172
|
+
- { id: trajectory_structures, glob: "1_Trajectories/*/*.cif", required: false }
|
|
173
|
+
- { id: refolded, glob: "2_Refolded/!_Refolded.csv", required: false }
|
|
174
|
+
- { id: refolded_structures, glob: "2_Refolded/*.cif", required: false }
|
|
175
|
+
- { id: ranked, glob: "3_Ranked/!_Ranked.csv", required: false }
|
|
176
|
+
- { id: accepted_structures, glob: "3_Ranked/*.cif", required: false }
|
|
177
|
+
- { id: upstream_summary, glob: summary.csv, required: true }
|
|
178
|
+
- { id: summary, glob: moldesk-summary.json, required: false }
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
schemaVersion: 1
|
|
2
|
+
name: boltz
|
|
3
|
+
displayName: Boltz-2
|
|
4
|
+
modelVersion: 2.2.1
|
|
5
|
+
adapterVersion: 0.2.0
|
|
6
|
+
description: Joint biomolecular structure and binding-affinity prediction (Boltz team, MIT).
|
|
7
|
+
category: structure-prediction
|
|
8
|
+
status: beta
|
|
9
|
+
license: MIT
|
|
10
|
+
homepage: https://github.com/jwohlwend/boltz
|
|
11
|
+
source:
|
|
12
|
+
repository: https://github.com/jwohlwend/boltz
|
|
13
|
+
revision: cb04aeccdd480fd4db707f0bbafde538397fa2ac
|
|
14
|
+
# Darwin/MPS was verified end-to-end with a real install + prediction on
|
|
15
|
+
# 2026-09-23 (see models/boltz/README.md for full evidence: process device
|
|
16
|
+
# banner, checksummed outputs, negative-path test). Linux/CUDA is
|
|
17
|
+
# structurally implemented and unit-tested but not live-verified — no NVIDIA
|
|
18
|
+
# hardware was available to run it; do not treat it as verified per rule 13.
|
|
19
|
+
adapterVerification:
|
|
20
|
+
lastVerifiedAt: "2026-09-23T11:22:33.984Z"
|
|
21
|
+
platforms:
|
|
22
|
+
- darwin-arm64
|
|
23
|
+
notes: >-
|
|
24
|
+
Real moldesk install + moldesk run on Apple M3 (macOS, Darwin 25.6.0),
|
|
25
|
+
re-verified after fixing two P1 review findings (checkpoints now
|
|
26
|
+
populated/checksum-verified at install time via manifest `assets:`, not
|
|
27
|
+
lazily on first run; CUDA raised from recommended to required to match
|
|
28
|
+
the mandatory CUDA probe) and three P2 findings (verifyInstallation now
|
|
29
|
+
asserts the exact pinned boltz-community version, absence of official
|
|
30
|
+
boltz, and CLI mps-accelerator support; YAML input validation uses a
|
|
31
|
+
real parser, not a regex; distribution version is explicitly asserted
|
|
32
|
+
since git-sourced installs don't get PyPI hash enforcement). Installed
|
|
33
|
+
boltz-community==2.10.12 + torch==2.14.0 (not official boltz), ran
|
|
34
|
+
boltz-fix-macos-libomp, verifyInstallation's MPS probe passed with a
|
|
35
|
+
real tensor round-trip plus the strengthened assertions above. A live
|
|
36
|
+
prediction against examples/boltz/protein.yaml completed in ~88s (all
|
|
37
|
+
checkpoints already cache-verified, zero network downloads during the
|
|
38
|
+
run — confirmed via log inspection) with PyTorch Lightning reporting
|
|
39
|
+
"GPU available: True (mps), used: True". Outputs: a parseable mmCIF and
|
|
40
|
+
confidence JSON, both checksummed in run.json. Negative tests: (1)
|
|
41
|
+
--param accelerator=gpu on this CUDA-less install failed closed
|
|
42
|
+
instantly with an actionable error; (2) a malformed YAML job
|
|
43
|
+
("sequences: [") was rejected with a real parser error before any run
|
|
44
|
+
started. Linux/CUDA path not covered by this verification — no NVIDIA
|
|
45
|
+
hardware available.
|
|
46
|
+
runtimes:
|
|
47
|
+
# Linux/CUDA: official `jwohlwend/boltz`. `--accelerator` on this pinned CLI only
|
|
48
|
+
# accepts gpu|cpu|tpu (no "mps" choice) — verified against src/boltz/main.py at
|
|
49
|
+
# this revision. `nvidiaGpu`/`cuda` are `required`, not `recommended`: the
|
|
50
|
+
# adapter's verifyInstallation runs a mandatory CUDA probe on every non-Darwin
|
|
51
|
+
# install (torch.cuda.is_available(), device count, CUDA build) with no CPU
|
|
52
|
+
# verification path implemented — declaring CUDA merely "recommended" would
|
|
53
|
+
# contradict what install actually enforces and let a CPU-only Linux host pass
|
|
54
|
+
# compatibility checks only to fail install. A genuine CPU-only Linux path is
|
|
55
|
+
# not implemented in this pass; `--param accelerator=cpu` is exposed by the
|
|
56
|
+
# pinned CLI but running it still requires this install to pass its CUDA probe.
|
|
57
|
+
- kind: python
|
|
58
|
+
python: "3.11"
|
|
59
|
+
installer: uv
|
|
60
|
+
platforms:
|
|
61
|
+
- linux-x64
|
|
62
|
+
source:
|
|
63
|
+
repository: https://github.com/jwohlwend/boltz
|
|
64
|
+
revision: cb04aeccdd480fd4db707f0bbafde538397fa2ac
|
|
65
|
+
requirements:
|
|
66
|
+
- name: boltz
|
|
67
|
+
version: 2.2.1
|
|
68
|
+
source: https://github.com/jwohlwend/boltz
|
|
69
|
+
revision: cb04aeccdd480fd4db707f0bbafde538397fa2ac
|
|
70
|
+
extras:
|
|
71
|
+
- cuda
|
|
72
|
+
nvidiaGpu: required
|
|
73
|
+
cuda:
|
|
74
|
+
level: required
|
|
75
|
+
# Darwin/MPS: `Novel-Therapeutics/boltz-community` fork, which adds an "mps"
|
|
76
|
+
# `--accelerator` choice (verified against src/boltz/main.py at this revision) and
|
|
77
|
+
# ships the `boltz-fix-macos-libomp` console script this runtime entry's
|
|
78
|
+
# `postInstall` runs after dependency install. No `nvidiaGpu`/`cuda` here: this
|
|
79
|
+
# platform-runtime entry genuinely has no CUDA requirement.
|
|
80
|
+
- kind: python
|
|
81
|
+
python: "3.11"
|
|
82
|
+
installer: uv
|
|
83
|
+
platforms:
|
|
84
|
+
- darwin-arm64
|
|
85
|
+
source:
|
|
86
|
+
repository: https://github.com/Novel-Therapeutics/boltz-community
|
|
87
|
+
revision: 401f18150cc7184b7e1bb37239a25035ef6b3a57
|
|
88
|
+
requirements:
|
|
89
|
+
- name: boltz-community
|
|
90
|
+
version: 2.10.12
|
|
91
|
+
source: https://github.com/Novel-Therapeutics/boltz-community
|
|
92
|
+
revision: 401f18150cc7184b7e1bb37239a25035ef6b3a57
|
|
93
|
+
# Newest stable PyPI torch as of 2026-09-23, satisfies boltz-community's own
|
|
94
|
+
# `torch>=2.2` pyproject constraint and its README's documented "PyTorch 2.6+"
|
|
95
|
+
# compatibility statement. cp311 wheel to match this entry's `python: "3.11"`.
|
|
96
|
+
# No credible MPS-blocking regression found for 2.14.0 on shipping macOS
|
|
97
|
+
# versions (see models/boltz/README.md for research notes).
|
|
98
|
+
- name: torch
|
|
99
|
+
version: "2.14.0"
|
|
100
|
+
hashes:
|
|
101
|
+
- ae530ddd3f3b94248b77f1fd3313c4f3405bd0d17283d505b81574816767133a
|
|
102
|
+
postInstall:
|
|
103
|
+
- boltz-fix-macos-libomp
|
|
104
|
+
# Boltz-2's own CLI (both distributions, identical logic) lazily downloads these
|
|
105
|
+
# from HuggingFace's *mutable* `resolve/main/...` URLs on first prediction — that
|
|
106
|
+
# both defers download past install time and has no fixed content to verify
|
|
107
|
+
# against. Since upstream provides no immutable/checksum-pinned download itself,
|
|
108
|
+
# these assets are instead pinned here to an exact HuggingFace repo commit
|
|
109
|
+
# (boltz-community/boltz-2 @ 6fdef46d763fee7fbb83ca5501ccceff43b85607) with sha256
|
|
110
|
+
# digests read from that commit's `X-Linked-ETag` (HF's convention for an LFS
|
|
111
|
+
# file's sha256) and independently confirmed by hashing a real download of each
|
|
112
|
+
# file byte-for-byte. Materialized by the existing checksum-verified asset
|
|
113
|
+
# pipeline into `assets/boltz-cache/`, which is what the adapter passes as
|
|
114
|
+
# `--cache` — so by the time a prediction runs, Boltz's own downloader finds
|
|
115
|
+
# every file already present and verified, and performs no network access.
|
|
116
|
+
assets:
|
|
117
|
+
- id: boltz2-ccd
|
|
118
|
+
url: https://huggingface.co/boltz-community/boltz-2/resolve/6fdef46d763fee7fbb83ca5501ccceff43b85607/mols.tar
|
|
119
|
+
source: https://huggingface.co/boltz-community/boltz-2
|
|
120
|
+
sha256: 39e076d96dbec6b4e86982bbda16f3a53a2a60c9bdc17828d88f6f9a0c7d1fd7
|
|
121
|
+
sizeBytes: 1855662080
|
|
122
|
+
archive: tar
|
|
123
|
+
target: boltz-cache
|
|
124
|
+
- id: boltz2-conf-checkpoint
|
|
125
|
+
url: https://huggingface.co/boltz-community/boltz-2/resolve/6fdef46d763fee7fbb83ca5501ccceff43b85607/boltz2_conf.ckpt
|
|
126
|
+
source: https://huggingface.co/boltz-community/boltz-2
|
|
127
|
+
sha256: 090e82ac8c92f5e943fa1b39e7410a44027bea7243c0bbb3caa67a77fc1428e1
|
|
128
|
+
sizeBytes: 2286561469
|
|
129
|
+
target: boltz-cache/boltz2_conf.ckpt
|
|
130
|
+
- id: boltz2-affinity-checkpoint
|
|
131
|
+
url: https://huggingface.co/boltz-community/boltz-2/resolve/6fdef46d763fee7fbb83ca5501ccceff43b85607/boltz2_aff.ckpt
|
|
132
|
+
source: https://huggingface.co/boltz-community/boltz-2
|
|
133
|
+
sha256: dcc5cd3722b1c9eaa34267e4ae32f55cbbf1963f4c19319381ccfa30fdd2ca9e
|
|
134
|
+
sizeBytes: 2062139170
|
|
135
|
+
target: boltz-cache/boltz2_aff.ckpt
|
|
136
|
+
hardware:
|
|
137
|
+
platforms:
|
|
138
|
+
- darwin-arm64
|
|
139
|
+
- linux-x64
|
|
140
|
+
input:
|
|
141
|
+
formats:
|
|
142
|
+
- .yaml
|
|
143
|
+
- .yml
|
|
144
|
+
- .fasta
|
|
145
|
+
required: true
|
|
146
|
+
outputs:
|
|
147
|
+
- id: structures
|
|
148
|
+
glob: "boltz_results_*/predictions/*/*.cif"
|
|
149
|
+
required: true
|
|
150
|
+
- id: confidence
|
|
151
|
+
glob: "boltz_results_*/predictions/*/confidence_*.json"
|
|
152
|
+
required: true
|
|
153
|
+
- id: affinity
|
|
154
|
+
glob: "boltz_results_*/predictions/*/affinity_*.json"
|
|
155
|
+
required: false
|