mlclaw 0.4.10 → 0.5.0

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 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
3
  ARG BROKERKIT_PLUGIN_VERSION=0.4.1
4
- ARG BROKERKIT_VERSION=hf-broker/v0.5.2
5
- ARG MLCLAW_RUNTIME_IMAGE=ghcr.io/huggingface/mlclaw:0.4.10-openclaw-2026.7.1
4
+ ARG BROKERKIT_VERSION=hf-broker/v0.6.2
5
+ ARG MLCLAW_RUNTIME_IMAGE=ghcr.io/huggingface/mlclaw:0.5.0-openclaw-2026.7.1
6
6
 
7
7
  FROM golang:1.26.5-bookworm AS hf-broker-build
8
8
  ARG BROKERKIT_VERSION
@@ -43,6 +43,7 @@ RUN apt-get update \
43
43
  && rm -rf /var/lib/apt/lists/*
44
44
  RUN python3 -m pip install --break-system-packages --no-cache-dir \
45
45
  "huggingface_hub==1.19.0" \
46
+ "hf-xet==1.5.2" \
46
47
  "datasets==5.0.0" \
47
48
  "safetensors==0.8.0" \
48
49
  "fastapi==0.137.1" \
package/README.md CHANGED
@@ -384,8 +384,15 @@ across Space rebuilds, local container replacement, and gateway migration. The
384
384
  Space does not use `HF_TOKEN` or `HUGGINGFACE_HUB_TOKEN` secrets. Its broad
385
385
  credential is stored as `MLCLAW_BROKER_HF_TOKEN`, written to a broker-owned
386
386
  `0600` file during startup, and removed from child-process environments.
387
- OpenClaw uses only the generated broker agent credential. Broker grant and
388
- event state and encrypted control credentials live under the root-owned
387
+ OpenClaw uses only the generated broker agent credential. At startup, ML Claw
388
+ asks HF Broker to render the active policy with the exact deployment state
389
+ bucket protected. Agent requests against that bucket are denied before an
390
+ approval is created. Other repository paths and bucket key prefixes can use
391
+ operator-approved grants lasting up to 24 hours or seven days; the installed
392
+ `hf-broker` skill explains request, wait, recovery, write, read, and revocation
393
+ workflows.
394
+
395
+ Broker grant and event state and encrypted control credentials live under the root-owned
389
396
  `/var/lib/mlclaw-protected` tree. They are included in the durable snapshot
390
397
  through a root-only `.mlclaw-protected` staging step, then restored outside the
391
398
  agent-owned live directory before OpenClaw starts. Rebuildable Git mirrors, the
@@ -23,6 +23,7 @@
23
23
  "python": {
24
24
  "packages": {
25
25
  "huggingface_hub": "1.19.0",
26
+ "hf_xet": "1.5.2",
26
27
  "datasets": "5.0.0",
27
28
  "safetensors": "0.8.0"
28
29
  }
@@ -30,7 +31,15 @@
30
31
  "skills": {
31
32
  "source": "https://github.com/huggingface/skills",
32
33
  "revision": "89d91fd4d0e6d4330471ba35f1c388489e94b496",
34
+ "managed": [
35
+ {
36
+ "name": "hf-broker",
37
+ "source": "https://github.com/osolmaz/brokerkit",
38
+ "revision": "hf-broker/v0.6.2"
39
+ }
40
+ ],
33
41
  "installed": [
42
+ "hf-broker",
34
43
  "hf-cli",
35
44
  "huggingface-spaces",
36
45
  "huggingface-datasets",
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: hf-broker
3
+ description: Use ML Claw's HF Broker for protected Hugging Face repository and bucket reads, writes, temporary grants, recovery, and revocation. Use instead of asking for or exposing a Hugging Face access token.
4
+ metadata:
5
+ { "openclaw": { "emoji": "🤗", "requires": { "bins": ["hf-broker"] } } }
6
+ ---
7
+
8
+ # Hugging Face Broker
9
+
10
+ Use the preconfigured HF Broker for protected Hugging Face operations. Never
11
+ ask for, print, copy, or export the broker's Hugging Face token. Do not run
12
+ `hf auth login` to work around a broker decision.
13
+
14
+ ## Choose a workflow
15
+
16
+ Use the advertised `hf_*` MCP tools for ordinary typed operations and grant
17
+ management. Use `hf-broker client` when a local file must enter or leave the
18
+ protected stream store. The runtime already provides the broker endpoint and a
19
+ limited agent credential.
20
+
21
+ Every mutation needs a stable request ID. Reuse it only for an exact retry of
22
+ the same operation. If a response is lost, recover the existing operation or
23
+ grant instead of submitting another mutation.
24
+
25
+ ## Request reusable write access
26
+
27
+ Request a temporary grant only when repeated writes are needed. Keep the scope
28
+ as narrow as possible. A day is 1,440 minutes and a week is 10,080 minutes.
29
+ These repeated-write examples explicitly request the deployment policy's
30
+ 25-use ceiling; the operator may approve a smaller use budget.
31
+
32
+ For one bucket key prefix:
33
+
34
+ ```sh
35
+ hf-broker client grant request bucket.object.write OWNER/BUCKET \
36
+ --key 'artifacts/**' \
37
+ --minutes 10080 \
38
+ --max-uses 25 \
39
+ --reason "Write the requested artifacts for one week" \
40
+ --request-id STABLE-GRANT-REQUEST-ID
41
+ ```
42
+
43
+ For one repository path prefix:
44
+
45
+ ```sh
46
+ hf-broker client grant request repo.commit.create OWNER/REPO \
47
+ --type dataset \
48
+ --path 'data/**' \
49
+ --minutes 1440 \
50
+ --max-uses 25 \
51
+ --reason "Update the requested dataset path for one day" \
52
+ --request-id STABLE-GRANT-REQUEST-ID
53
+ ```
54
+
55
+ Normal append-only Git pushes can also use a scoped `git.push.append` grant.
56
+ Keep the repository type, ref, and path selectors exact. Force pushes, ref
57
+ deletion, repository deletion, visibility changes, and access management stay
58
+ short-lived or single-use.
59
+
60
+ A pending grant requires an operator decision. Keep waiting on the same grant
61
+ rather than creating another request:
62
+
63
+ ```sh
64
+ hf-broker client grant wait --wait-timeout 15m GRANT-ID
65
+ hf-broker client grant get GRANT-ID
66
+ ```
67
+
68
+ MCP grant calls use bounded waits. If `hf_grant_request` or `hf_grant_wait`
69
+ returns `pending`, call `hf_grant_wait` again with the same grant ID. Use
70
+ `hf_grant_cancel` for an unapproved request and `hf_grant_revoke` when reusable
71
+ access is no longer needed.
72
+
73
+ ## Write and read bucket objects
74
+
75
+ Upload a local file through the broker's stream store. File bytes do not belong
76
+ in MCP JSON, chat messages, plans, approvals, or logs.
77
+
78
+ ```sh
79
+ hf-broker client bucket object write \
80
+ --target-json '{"kind":"bucket","namespace":"OWNER","name":"BUCKET"}' \
81
+ --arguments-json '{"path":"artifacts/result.bin"}' \
82
+ --source ./result.bin \
83
+ --media-type application/octet-stream \
84
+ --reason "Upload the requested result" \
85
+ --request-id STABLE-WRITE-REQUEST-ID \
86
+ --wait=true \
87
+ --wait-timeout 15m
88
+ ```
89
+
90
+ Set `"overwrite":true` only when replacing the currently observed object is
91
+ intentional. The broker checks the bound precondition again before commit.
92
+
93
+ Read into a new destination and let the client verify the returned stream:
94
+
95
+ ```sh
96
+ hf-broker client bucket object read \
97
+ --target-json '{"kind":"bucket","namespace":"OWNER","name":"BUCKET"}' \
98
+ --arguments-json '{"path":"artifacts/result.bin"}' \
99
+ --output ./downloaded-result.bin \
100
+ --reason "Read the requested result" \
101
+ --wait=true \
102
+ --wait-timeout 15m
103
+ ```
104
+
105
+ Use `hf_bucket_object_list` or the matching client command to inspect only the
106
+ approved bucket prefix. Do not use the ML Claw state bucket for agent work. Its
107
+ exact target is denied by deployment policy, and approval cannot override that
108
+ deny.
109
+
110
+ ## Recover operations
111
+
112
+ A timeout may leave a durable operation pending. Continue with its operation ID
113
+ or recover it by request ID:
114
+
115
+ ```sh
116
+ hf-broker client operation get OPERATION-ID
117
+ hf-broker client operation wait --wait-timeout 15m OPERATION-ID
118
+ hf-broker client operation cancel OPERATION-ID
119
+ ```
120
+
121
+ If the operation ID was lost, call the `hf_operation_list` MCP tool with the
122
+ stable `request_id`, then continue with the returned operation ID.
123
+
124
+ Stop only after a terminal result, explicit cancellation, or an unrecoverable
125
+ broker error. Revocation and expiry prevent later matching writes from reaching
126
+ Hugging Face.
@@ -140,6 +140,13 @@ conflict is durable: inspect the existing operation instead of restarting the
140
140
  broker. Protected actions appear in the ML Claw BrokerKit control and may also
141
141
  be sent through configured OpenClaw channels.
142
142
 
143
+ For repeated repository or bucket writes, request the narrowest temporary grant
144
+ with \`hf_grant_request\`. A bounded wait may return a pending grant; continue
145
+ with \`hf_grant_wait\` using the same grant ID. Revoke the grant when the work is
146
+ finished. Use the installed \`hf-broker\` client for local file upload and
147
+ verified download streams. Never use the deployment state bucket for agent
148
+ work; its exact target is denied by policy.
149
+
143
150
  After repository creation, use the brokered Git transport for repository
144
151
  contents. The limited broker credential is not a Hugging Face Hub token; do
145
152
  not report it as missing Hub access.
@@ -210,11 +217,21 @@ function assertToolingManifest(value) {
210
217
  if (!skills || !Array.isArray(skills.installed) || !skills.installed.every((skill) => typeof skill === "string")) {
211
218
  throw new Error("HF tooling manifest must list installed skills");
212
219
  }
220
+ if (!Array.isArray(skills.managed) || !skills.managed.every(isManagedSkillSource)) {
221
+ throw new Error("HF tooling manifest must list managed skill sources");
222
+ }
213
223
  const python = record.python;
214
224
  if (!python || typeof python.packages !== "object" || python.packages === null) {
215
225
  throw new Error("HF tooling manifest must list Python packages");
216
226
  }
217
227
  }
228
+ function isManagedSkillSource(value) {
229
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
230
+ const source = value;
231
+ return [source.name, source.source, source.revision].every(
232
+ (field) => typeof field === "string" && field.trim().length > 0
233
+ );
234
+ }
218
235
  async function copyMissingTree(sourceRoot, targetRoot) {
219
236
  const copied = [];
220
237
  await assertDirectory(sourceRoot, "HF tooling templates");
package/dist/mlclaw.mjs CHANGED
@@ -15383,9 +15383,9 @@ function nextLink(header) {
15383
15383
 
15384
15384
  // src/mlclaw/release-config.generated.ts
15385
15385
  var RELEASE_CONFIG = {
15386
- "packageVersion": "0.4.10",
15386
+ "packageVersion": "0.5.0",
15387
15387
  "openclawVersion": "2026.7.1",
15388
- "brokerkitVersion": "hf-broker/v0.5.2",
15388
+ "brokerkitVersion": "hf-broker/v0.6.2",
15389
15389
  "brokerkitPluginVersion": "0.4.1",
15390
15390
  "runtimeImageRepository": "ghcr.io/huggingface/mlclaw"
15391
15391
  };
@@ -15530,6 +15530,7 @@ RUN apt-get update \\
15530
15530
  && rm -rf /var/lib/apt/lists/*
15531
15531
  RUN python3 -m pip install --break-system-packages --no-cache-dir \\
15532
15532
  "huggingface_hub==1.19.0" \\
15533
+ "hf-xet==1.5.2" \\
15533
15534
  "datasets==5.0.0" \\
15534
15535
  "safetensors==0.8.0" \\
15535
15536
  "fastapi==0.137.1" \\
package/entrypoint.sh CHANGED
@@ -9,6 +9,8 @@ export MLCLAW_OPENCLAW_UID="$OPENCLAW_UID"
9
9
  export MLCLAW_OPENCLAW_GID="$OPENCLAW_GID"
10
10
  HF_BROKER_ENABLED=0
11
11
  HF_BROKER_RUN_DIR="/run/mlclaw-hf-broker"
12
+ HF_BROKER_POLICY_DIR="$HF_BROKER_RUN_DIR/policy"
13
+ HF_BROKER_SCOPE_FILE="$HF_BROKER_POLICY_DIR/scope.json"
12
14
  STATE_HF_TOKEN=""
13
15
  RESTORED_PROTECTED_STATE_DIR="$LIVE_DIR/.mlclaw-protected"
14
16
  PROTECTED_STATE_DIR="/var/lib/mlclaw-protected"
@@ -50,6 +52,8 @@ prepare_hf_broker() {
50
52
 
51
53
  export MLCLAW_HF_BROKER_URL="http://127.0.0.1:7863"
52
54
  export MLCLAW_HF_BROKER_AGENT_SECRET_FILE="$agent_secret_file"
55
+ export HF_BROKER_AGENT_ENDPOINT="tcp://127.0.0.1:7863"
56
+ export HF_BROKER_SHARED_SECRET_FILE="$agent_secret_file"
53
57
  if [ "${MLCLAW_GATEWAY_LOCATION:-}" = "local" ]; then
54
58
  export MLCLAW_TRUSTED_HF_TOKEN_FILE="$token_file"
55
59
  fi
@@ -81,6 +85,32 @@ restore_protected_state() {
81
85
  chmod 0700 "$PROTECTED_STATE_DIR/control" "$HF_BROKER_STATE_DIR"
82
86
  }
83
87
 
88
+ render_hf_broker_policy() {
89
+ if [ "$HF_BROKER_ENABLED" != "1" ]; then
90
+ return
91
+ fi
92
+
93
+ local state_bucket="${OPENCLAW_HF_STATE_BUCKET:-}"
94
+ local protected_target=()
95
+ if [ -n "$state_bucket" ]; then
96
+ protected_target=(--protect-bucket "$state_bucket")
97
+ fi
98
+
99
+ install -d -m 0700 -o hf-broker -g hf-broker "$HF_BROKER_POLICY_DIR"
100
+ gosu hf-broker:hf-broker /usr/local/bin/hf-broker policy render \
101
+ --preset request-all-agent-operations \
102
+ --client default \
103
+ --profile-out "$HF_BROKER_POLICY_DIR/profile.json" \
104
+ --output "$HF_BROKER_SCOPE_FILE" \
105
+ --manifest-out "$HF_BROKER_POLICY_DIR/manifest.json" \
106
+ --replace \
107
+ "${protected_target[@]}"
108
+ gosu hf-broker:hf-broker /usr/local/bin/hf-broker doctor policy \
109
+ --profile "$HF_BROKER_POLICY_DIR/profile.json" \
110
+ --scope "$HF_BROKER_SCOPE_FILE" \
111
+ --manifest "$HF_BROKER_POLICY_DIR/manifest.json"
112
+ }
113
+
84
114
  start_hf_broker() {
85
115
  if [ "$HF_BROKER_ENABLED" != "1" ]; then
86
116
  return
@@ -95,7 +125,8 @@ start_hf_broker() {
95
125
  HF_BROKER_OPERATOR_SECRETS_FILE="$HF_BROKER_RUN_DIR/operator-secrets.conf" \
96
126
  HF_BROKER_AGENT_ENDPOINT=tcp://127.0.0.1:7863 \
97
127
  HF_BROKER_OPERATOR_ENDPOINT=tcp://127.0.0.1:7864 \
98
- HF_BROKER_SCOPE_FILE=/app/hf-broker.scope.json \
128
+ HF_BROKER_SCOPE_FILE="$HF_BROKER_SCOPE_FILE" \
129
+ HF_BROKER_XET_PYTHON=/usr/bin/python3 \
99
130
  HF_BROKER_STATE_DIR="$HF_BROKER_STATE_DIR" \
100
131
  gosu hf-broker:hf-broker /usr/local/bin/hf-broker &
101
132
  HF_BROKER_PID=$!
@@ -172,6 +203,7 @@ mkdir -p "$LIVE_DIR" "$WORKSPACE_DIR" "$STATE_DIR"
172
203
  chown_openclaw_live
173
204
  install -d -m 0710 -o root -g hf-broker "$PROTECTED_STATE_DIR"
174
205
  install -d -m 0700 -o root -g root "$PROTECTED_STATE_DIR/control"
206
+ render_hf_broker_policy
175
207
  start_hf_broker
176
208
 
177
209
  if [ -n "${OPENCLAW_AGENT_NAME:-}" ]; then
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "mlclaw",
3
- "version": "0.4.10",
3
+ "version": "0.5.0",
4
4
  "license": "MIT",
5
5
  "config": {
6
6
  "openclawVersion": "2026.7.1",
7
- "brokerkitVersion": "hf-broker/v0.5.2",
7
+ "brokerkitVersion": "hf-broker/v0.6.2",
8
8
  "brokerkitPluginVersion": "0.4.1",
9
9
  "runtimeImageRepository": "ghcr.io/huggingface/mlclaw"
10
10
  },