mlclaw 0.4.5 → 0.4.7
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/Dockerfile +2 -2
- package/README.md +9 -10
- package/dist/mlclaw-space-runtime.js +1 -1
- package/dist/mlclaw.mjs +36 -16
- package/package.json +2 -2
package/Dockerfile
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
ARG OPENCLAW_VERSION=2026.7.1
|
|
2
2
|
ARG OPENCLAW_BASE_IMAGE=ghcr.io/openclaw/openclaw:${OPENCLAW_VERSION}
|
|
3
|
-
ARG BROKERKIT_PLUGIN_VERSION=0.3.
|
|
3
|
+
ARG BROKERKIT_PLUGIN_VERSION=0.3.3
|
|
4
4
|
ARG BROKERKIT_VERSION=hf-broker/v0.4.0
|
|
5
|
-
ARG MLCLAW_RUNTIME_IMAGE=ghcr.io/huggingface/mlclaw:0.4.
|
|
5
|
+
ARG MLCLAW_RUNTIME_IMAGE=ghcr.io/huggingface/mlclaw:0.4.7-openclaw-2026.7.1
|
|
6
6
|
|
|
7
7
|
FROM golang:1.26.5-bookworm AS hf-broker-build
|
|
8
8
|
ARG BROKERKIT_VERSION
|
package/README.md
CHANGED
|
@@ -5,8 +5,13 @@
|
|
|
5
5
|
# ML Claw
|
|
6
6
|
|
|
7
7
|
ML Claw deploys an OpenClaw agent on Hugging Face with durable state in a
|
|
8
|
-
private Storage Bucket. The default deployment is a
|
|
9
|
-
|
|
8
|
+
private Storage Bucket. The default deployment is a protected Hugging Face
|
|
9
|
+
Space: its source stays private, its app URL is reachable, and the browser
|
|
10
|
+
gateway is protected by ML Claw's Hugging Face OAuth session.
|
|
11
|
+
|
|
12
|
+
[ml-intern](https://github.com/huggingface/ml-intern) is Hugging Face's
|
|
13
|
+
open-source ML engineer for reading papers, training models, and shipping
|
|
14
|
+
models.
|
|
10
15
|
|
|
11
16
|
The browser never receives an OpenClaw gateway token. ML Claw authenticates the
|
|
12
17
|
signed-in Hugging Face user, then proxies HTTP and WebSocket traffic to
|
|
@@ -73,7 +78,7 @@ npx mlclaw@latest bootstrap --name mlclaw
|
|
|
73
78
|
|
|
74
79
|
This creates:
|
|
75
80
|
|
|
76
|
-
- a
|
|
81
|
+
- a protected Docker Space for the browser gateway when the account can host it;
|
|
77
82
|
- a private Storage Bucket for OpenClaw state after the Space is accepted;
|
|
78
83
|
- no explicit Space hardware request unless you pass `--hardware`;
|
|
79
84
|
- a Docker Space that starts from the prebuilt `ghcr.io/huggingface/mlclaw` image;
|
|
@@ -102,7 +107,7 @@ Open the Space, sign in with your Hugging Face account, and use the OpenClaw
|
|
|
102
107
|
browser gateway directly. The gateway includes a small ML Claw control link
|
|
103
108
|
for settings, status, credentials, and sign out.
|
|
104
109
|
|
|
105
|
-
|
|
110
|
+
Expose the Space source only when you explicitly want a public demo or template:
|
|
106
111
|
|
|
107
112
|
```bash
|
|
108
113
|
npx mlclaw@latest bootstrap --name mlclaw --public-space
|
|
@@ -386,12 +391,6 @@ Local gateways pass the broad credential only to the trusted state-sync
|
|
|
386
391
|
supervisor for bucket I/O and to the trusted MCP integration proxy through a
|
|
387
392
|
protected token file. Neither path passes it to OpenClaw.
|
|
388
393
|
|
|
389
|
-
## Related
|
|
390
|
-
|
|
391
|
-
[ml-intern](https://github.com/huggingface/ml-intern) is Hugging Face's
|
|
392
|
-
open-source ML engineer for reading papers, training models, and shipping
|
|
393
|
-
models.
|
|
394
|
-
|
|
395
394
|
## Costs
|
|
396
395
|
|
|
397
396
|
- Browser Space gateway: `cpu-basic` is enough for the default browser gateway.
|
|
@@ -8937,7 +8937,7 @@ function templatePage(config2) {
|
|
|
8937
8937
|
<img src="/assets/mlclaw.svg" alt="ML Claw" class="logo">
|
|
8938
8938
|
<h1>ML Claw</h1>
|
|
8939
8939
|
<p>Run the local bootstrapper to create a Hugging Face hosted OpenClaw agent for ML workflows.</p>
|
|
8940
|
-
<p class="notice">Do not set this up by only clicking Duplicate. The bootstrapper creates the
|
|
8940
|
+
<p class="notice">Do not set this up by only clicking Duplicate. The bootstrapper creates the protected Space, private Storage Bucket, OAuth settings, secrets, model configuration, and local manifest.</p>
|
|
8941
8941
|
<h2>With Node.js</h2>
|
|
8942
8942
|
<pre><code>npx mlclaw@latest bootstrap --name mlclaw</code></pre>
|
|
8943
8943
|
<h2>macOS or Linux without Node.js</h2>
|
package/dist/mlclaw.mjs
CHANGED
|
@@ -14968,7 +14968,7 @@ var HubApi = class {
|
|
|
14968
14968
|
organization: owner === me2.name ? null : owner,
|
|
14969
14969
|
type: "space",
|
|
14970
14970
|
sdk: "docker",
|
|
14971
|
-
|
|
14971
|
+
visibility: options?.visibility ?? "protected"
|
|
14972
14972
|
};
|
|
14973
14973
|
if (options?.hardware) {
|
|
14974
14974
|
payload.hardware = options.hardware;
|
|
@@ -15001,8 +15001,19 @@ var HubApi = class {
|
|
|
15001
15001
|
}
|
|
15002
15002
|
}
|
|
15003
15003
|
async getSpaceVisibility(repoId) {
|
|
15004
|
-
const
|
|
15005
|
-
|
|
15004
|
+
const [owner] = splitRepoId(repoId);
|
|
15005
|
+
const me2 = await this.whoami();
|
|
15006
|
+
let url = owner === me2.name ? `${this.hubUrl}/api/settings/repositories` : `${this.hubUrl}/api/organizations/${encodeURIComponent(owner)}/settings/repositories`;
|
|
15007
|
+
while (url) {
|
|
15008
|
+
const response = await this.request(url);
|
|
15009
|
+
const repositories = await response.json();
|
|
15010
|
+
const visibility = repositories.find((repo) => repo.id === repoId && repo.type === "space")?.visibility;
|
|
15011
|
+
if (visibility === "private" || visibility === "protected" || visibility === "public") {
|
|
15012
|
+
return visibility;
|
|
15013
|
+
}
|
|
15014
|
+
url = nextLink(response.headers.get("link"));
|
|
15015
|
+
}
|
|
15016
|
+
throw new Error(`Hub repository settings omitted Space visibility for ${repoId}`);
|
|
15006
15017
|
}
|
|
15007
15018
|
async updateSpaceVisibility(repoId, visibility) {
|
|
15008
15019
|
await this.requestJson(`/api/spaces/${repoId}/settings`, {
|
|
@@ -15375,7 +15386,7 @@ import fs12 from "node:fs";
|
|
|
15375
15386
|
import path13 from "node:path";
|
|
15376
15387
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
15377
15388
|
var DEFAULT_OPENCLAW_VERSION = "2026.7.1";
|
|
15378
|
-
var DEFAULT_BROKERKIT_PLUGIN_VERSION = "0.3.
|
|
15389
|
+
var DEFAULT_BROKERKIT_PLUGIN_VERSION = "0.3.3";
|
|
15379
15390
|
var DEFAULT_BROKERKIT_VERSION = "hf-broker/v0.4.0";
|
|
15380
15391
|
var DEFAULT_RUNTIME_IMAGE_REPOSITORY = "ghcr.io/huggingface/mlclaw";
|
|
15381
15392
|
var PACKAGE_METADATA = readPackageMetadata();
|
|
@@ -19848,7 +19859,7 @@ var manifestFields = {
|
|
|
19848
19859
|
}).strict().optional(),
|
|
19849
19860
|
credentialKeySha256: external_exports.string().regex(/^[a-f0-9]{64}$/).optional(),
|
|
19850
19861
|
tailscaleMode: external_exports.enum(["off", "direct", "serve"]).optional(),
|
|
19851
|
-
spaceVisibility: external_exports.enum(["private", "public"]).optional(),
|
|
19862
|
+
spaceVisibility: external_exports.enum(["private", "protected", "public"]).optional(),
|
|
19852
19863
|
spaceHardware: external_exports.string().min(1).max(128).optional(),
|
|
19853
19864
|
spaceSleepTime: external_exports.number().int().min(-1).optional(),
|
|
19854
19865
|
recoveredWithoutCredentialKey: external_exports.boolean().optional(),
|
|
@@ -20013,7 +20024,7 @@ var desiredStateSchema = external_exports.object({
|
|
|
20013
20024
|
runtimeImage: external_exports.string().min(1).max(1024),
|
|
20014
20025
|
space: external_exports.object({
|
|
20015
20026
|
repo: external_exports.string().min(3).max(256),
|
|
20016
|
-
visibility: external_exports.enum(["private", "public"]),
|
|
20027
|
+
visibility: external_exports.enum(["private", "protected", "public"]),
|
|
20017
20028
|
hardware: external_exports.string().min(1).max(128).optional(),
|
|
20018
20029
|
sleepTime: external_exports.number().int().min(-1).optional()
|
|
20019
20030
|
}).strict()
|
|
@@ -20067,7 +20078,7 @@ function deploymentIdentity(manifest, statePrefix = "openclaw-state") {
|
|
|
20067
20078
|
createdAt: manifest.createdAt
|
|
20068
20079
|
});
|
|
20069
20080
|
}
|
|
20070
|
-
function deploymentDesiredState(manifest, visibility = manifest.spaceVisibility ?? "
|
|
20081
|
+
function deploymentDesiredState(manifest, visibility = manifest.spaceVisibility ?? "protected") {
|
|
20071
20082
|
return desiredStateSchema.parse({
|
|
20072
20083
|
schemaVersion: 1,
|
|
20073
20084
|
deploymentId: manifest.deploymentId,
|
|
@@ -20751,7 +20762,7 @@ function createProgram(runtimeOverrides = {}) {
|
|
|
20751
20762
|
program2.name("mlclaw").description("Deploy OpenClaw to a Hugging Face Space and private bucket").showHelpAfterError().exitOverride((err) => {
|
|
20752
20763
|
throw err;
|
|
20753
20764
|
});
|
|
20754
|
-
program2.command("bootstrap", { isDefault: true }).alias("configure").description("Create or update a Hugging Face OpenClaw deployment").option("--owner <owner>", "Hugging Face user or organization").option("--name <name>", "Agent and runtime resource base name").option("--bucket <owner/bucket>", "State bucket to create or adopt").option("--gateway <local|space>", "Where the live gateway runs").option("--telegram-token <token>", "Optional Telegram bot token").option("--telegram-token-file <path>", "File containing TELEGRAM_BOT_TOKEN=... or a raw token").option("--telegram-user-id <id>", "Allowed Telegram user ID").option("--telegram-api-root <url>", "Telegram API root override").option("--telegram-proxy <url>", "Telegram proxy URL override").option("--hardware <flavor>", "Hugging Face Space hardware flavor").option("--sleep-time <seconds>", "Space sleep timeout in seconds; -1 means never sleep", parseInteger).option("--model <model>", "OpenClaw model identifier").option("--runtime-image <image>", "ML Claw runtime image").option("--bundled-runtime", "Generate a bundled Space runtime instead of using the prebuilt ML Claw image", false).option("--public-space", "
|
|
20765
|
+
program2.command("bootstrap", { isDefault: true }).alias("configure").description("Create or update a Hugging Face OpenClaw deployment").option("--owner <owner>", "Hugging Face user or organization").option("--name <name>", "Agent and runtime resource base name").option("--bucket <owner/bucket>", "State bucket to create or adopt").option("--gateway <local|space>", "Where the live gateway runs").option("--telegram-token <token>", "Optional Telegram bot token").option("--telegram-token-file <path>", "File containing TELEGRAM_BOT_TOKEN=... or a raw token").option("--telegram-user-id <id>", "Allowed Telegram user ID").option("--telegram-api-root <url>", "Telegram API root override").option("--telegram-proxy <url>", "Telegram proxy URL override").option("--hardware <flavor>", "Hugging Face Space hardware flavor").option("--sleep-time <seconds>", "Space sleep timeout in seconds; -1 means never sleep", parseInteger).option("--model <model>", "OpenClaw model identifier").option("--runtime-image <image>", "ML Claw runtime image").option("--bundled-runtime", "Generate a bundled Space runtime instead of using the prebuilt ML Claw image", false).option("--public-space", "Expose the Space source as well as the authenticated app", false).addOption(new Option("--gateway-token <token>").hideHelp()).option("--router-token <token>", "Hugging Face Router inference token for Space gateway model calls").option(
|
|
20755
20766
|
"--router-token-file <path>",
|
|
20756
20767
|
"File containing MLCLAW_ROUTER_TOKEN=..., HF_ROUTER_TOKEN=..., or a raw token"
|
|
20757
20768
|
).option("--broker-hf-token-file <path>", "File containing MLCLAW_BROKER_HF_TOKEN=... or a raw Hugging Face token").option("--docker-context <name>", "Docker context for local gateway mode").option("--container-runtime <auto|docker|podman>", "Local container runtime", "auto").option("--local-port <port>", "Loopback port for a local gateway", parseLocalPort).option("--tailscale <off|direct|serve>", "Tailnet access mode", parseTailscaleMode).option("--tailscale-port <port>", "Tailnet listener or Serve HTTPS port", parseLocalPort).option(
|
|
@@ -20802,7 +20813,7 @@ function createProgram(runtimeOverrides = {}) {
|
|
|
20802
20813
|
gateway.command("logs").argument("<agent>", "Agent name").option("--tail <lines>", "Number of log lines", parseInteger, 200).action(async (agent, opts) => {
|
|
20803
20814
|
await gatewayLogs(agent, opts, runtime);
|
|
20804
20815
|
});
|
|
20805
|
-
gateway.command("migrate").argument("<agent>", "Agent name").requiredOption("--to <local|space>", "Target gateway location").option("--hardware <flavor>", "Hugging Face Space hardware flavor").option("--sleep-time <seconds>", "Space sleep timeout in seconds; -1 means never sleep", parseInteger).option("--runtime-image <image>", "ML Claw runtime image").option("--bundled-runtime", "Generate a bundled Space runtime instead of using the prebuilt ML Claw image", false).option("--public-space", "
|
|
20816
|
+
gateway.command("migrate").argument("<agent>", "Agent name").requiredOption("--to <local|space>", "Target gateway location").option("--hardware <flavor>", "Hugging Face Space hardware flavor").option("--sleep-time <seconds>", "Space sleep timeout in seconds; -1 means never sleep", parseInteger).option("--runtime-image <image>", "ML Claw runtime image").option("--bundled-runtime", "Generate a bundled Space runtime instead of using the prebuilt ML Claw image", false).option("--public-space", "Expose the Space source as well as the authenticated app", false).option("--router-token <token>", "Hugging Face Router inference token for Space gateway model calls").option(
|
|
20806
20817
|
"--router-token-file <path>",
|
|
20807
20818
|
"File containing MLCLAW_ROUTER_TOKEN=..., HF_ROUTER_TOKEN=..., or a raw token"
|
|
20808
20819
|
).option("--docker-context <name>", "Docker context for local gateway startup when migrating to local").option("--container-runtime <auto|docker|podman>", "Local container runtime", "auto").option("--local-port <port>", "Loopback port for the local gateway", parseLocalPort).option("--tailscale <off|direct|serve>", "Tailnet access mode", parseTailscaleMode).option("--tailscale-port <port>", "Tailnet listener or Serve HTTPS port", parseLocalPort).option("--no-pull", "Do not docker pull before starting a local gateway").option("--takeover", "Start even if another live runtime lease is present", false).option("--yes", "Confirm paid hardware prompts for automation", false).action(async (agent, opts) => {
|
|
@@ -21353,7 +21364,7 @@ async function reconcileManifest(params) {
|
|
|
21353
21364
|
if (currentDesired && currentDesired.deploymentId !== requestedManifest.deploymentId) {
|
|
21354
21365
|
throw new Error(`bucket ${requestedManifest.bucket} desired state belongs to another deployment`);
|
|
21355
21366
|
}
|
|
21356
|
-
const visibility = params.visibility ?? requestedManifest.spaceVisibility ?? "
|
|
21367
|
+
const visibility = params.visibility ?? requestedManifest.spaceVisibility ?? "protected";
|
|
21357
21368
|
const candidate = deploymentDesiredState(requestedManifest, visibility);
|
|
21358
21369
|
const sameDesired = currentDesired && JSON.stringify({ ...currentDesired, generation: 0, updatedAt: "" }) === JSON.stringify({ ...candidate, generation: 0, updatedAt: "" });
|
|
21359
21370
|
if (currentDesired && currentDesired.generation > requestedManifest.desiredGeneration && !sameDesired) {
|
|
@@ -21543,7 +21554,7 @@ async function resolveBootstrapPlan(params) {
|
|
|
21543
21554
|
spacePlan = {
|
|
21544
21555
|
space: names.space,
|
|
21545
21556
|
exists,
|
|
21546
|
-
visibility: opts.publicSpace ? "public" :
|
|
21557
|
+
visibility: opts.publicSpace ? "public" : "protected",
|
|
21547
21558
|
...currentVisibility ? { currentVisibility } : {}
|
|
21548
21559
|
};
|
|
21549
21560
|
}
|
|
@@ -21824,7 +21835,7 @@ async function createOrAdoptSpace(params) {
|
|
|
21824
21835
|
}
|
|
21825
21836
|
params.runtime.stdout.log(`Creating ${params.spacePlan.visibility} Space ${params.spacePlan.space}`);
|
|
21826
21837
|
await params.hub.createDockerSpace(params.spacePlan.space, {
|
|
21827
|
-
|
|
21838
|
+
visibility: params.spacePlan.visibility,
|
|
21828
21839
|
...params.hardware ? { hardware: params.hardware } : {},
|
|
21829
21840
|
...typeof params.sleepTime === "number" ? { sleepTimeSeconds: params.sleepTime } : {}
|
|
21830
21841
|
});
|
|
@@ -22301,11 +22312,11 @@ async function deploySpaceGateway(params) {
|
|
|
22301
22312
|
const assertLease = params.assertLease ?? (async () => void 0);
|
|
22302
22313
|
if (!params.spacePrepared) {
|
|
22303
22314
|
runtime.stdout.log(
|
|
22304
|
-
params.spaceExists ? `Updating existing Space ${manifest.space}` : `Creating ${params.
|
|
22315
|
+
params.spaceExists ? `Updating existing Space ${manifest.space}` : `Creating ${params.visibility ?? "protected"} Space ${manifest.space}`
|
|
22305
22316
|
);
|
|
22306
22317
|
await assertLease();
|
|
22307
22318
|
await hub.createDockerSpace(manifest.space, {
|
|
22308
|
-
|
|
22319
|
+
visibility: params.visibility ?? "protected",
|
|
22309
22320
|
...params.hardware && !params.spaceExists ? { hardware: params.hardware } : {},
|
|
22310
22321
|
...typeof params.sleepTime === "number" ? { sleepTimeSeconds: params.sleepTime } : {}
|
|
22311
22322
|
});
|
|
@@ -22739,7 +22750,7 @@ async function gatewayMigrate(agent, opts, runtime) {
|
|
|
22739
22750
|
});
|
|
22740
22751
|
updated = {
|
|
22741
22752
|
...updated,
|
|
22742
|
-
spaceVisibility: opts.publicSpace ? "public" :
|
|
22753
|
+
spaceVisibility: opts.publicSpace ? "public" : "protected",
|
|
22743
22754
|
...paidHardware.kind === "explicit" ? { spaceHardware: paidHardware.hardware } : {},
|
|
22744
22755
|
...typeof paidHardware.sleepTime === "number" ? { spaceSleepTime: paidHardware.sleepTime } : {}
|
|
22745
22756
|
};
|
|
@@ -22770,7 +22781,7 @@ async function gatewayMigrate(agent, opts, runtime) {
|
|
|
22770
22781
|
manifest: updated,
|
|
22771
22782
|
secrets: deploymentSecrets2,
|
|
22772
22783
|
allowedUsers: me2.name,
|
|
22773
|
-
|
|
22784
|
+
visibility: updated.spaceVisibility === "public" ? "public" : "protected",
|
|
22774
22785
|
spaceExists,
|
|
22775
22786
|
assertLease,
|
|
22776
22787
|
...paidHardware.kind === "explicit" ? { hardware: paidHardware.hardware } : {},
|
|
@@ -23609,6 +23620,15 @@ async function doctor(repoId, opts, hub, runtime) {
|
|
|
23609
23620
|
}
|
|
23610
23621
|
return;
|
|
23611
23622
|
}
|
|
23623
|
+
const visibility = await hub.getSpaceVisibility(repoId);
|
|
23624
|
+
if (visibility !== "protected") {
|
|
23625
|
+
if (fix) {
|
|
23626
|
+
await hub.updateSpaceVisibility(repoId, "protected");
|
|
23627
|
+
fixed.push("set protected Space visibility");
|
|
23628
|
+
} else {
|
|
23629
|
+
issues.push(`Space visibility is ${visibility}; hosted gateways require protected visibility`);
|
|
23630
|
+
}
|
|
23631
|
+
}
|
|
23612
23632
|
const bucket = variables.get("OPENCLAW_HF_STATE_BUCKET")?.value ?? opts.bucket;
|
|
23613
23633
|
let signedInUser;
|
|
23614
23634
|
const currentUsername = async () => {
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mlclaw",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"config": {
|
|
6
6
|
"openclawVersion": "2026.7.1",
|
|
7
7
|
"brokerkitVersion": "hf-broker/v0.4.0",
|
|
8
|
-
"brokerkitPluginVersion": "0.3.
|
|
8
|
+
"brokerkitPluginVersion": "0.3.3",
|
|
9
9
|
"runtimeImageRepository": "ghcr.io/huggingface/mlclaw"
|
|
10
10
|
},
|
|
11
11
|
"repository": {
|