Spaces:
Sleeping
Sleeping
Remove Telegram env vars, clean up README and .env.example
Browse files- Remove TELEGRAM_BOT_TOKEN/BOT_NAME/ALLOW_USER from sync_hf.py
(can be configured in Control UI instead)
- Remove duplicate Configuration table and Local Development section
- Add OpenClaw full env var support statement in README and .env.example
- Remove CSP headers claim from Security section
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- .env.example +64 -0
- README.md +10 -34
- scripts/sync_hf.py +2 -40
.env.example
CHANGED
|
@@ -135,3 +135,67 @@ OPENROUTER_API_KEY=sk-or-v1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
| 135 |
# OPENCLAW_HTTP_PROXY=
|
| 136 |
# OPENCLAW_HTTPS_PROXY=
|
| 137 |
# OPENCLAW_NO_PROXY=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
# OPENCLAW_HTTP_PROXY=
|
| 136 |
# OPENCLAW_HTTPS_PROXY=
|
| 137 |
# OPENCLAW_NO_PROXY=
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
# ═══════════════════════════════════════════════════════════════════════════
|
| 141 |
+
# OpenClaw 官方环境变量
|
| 142 |
+
# ═══════════════════════════════════════════════════════════════════════════
|
| 143 |
+
#
|
| 144 |
+
# HuggingClaw 启动 OpenClaw 时透传整个环境(env=os.environ.copy()),
|
| 145 |
+
# 因此 OpenClaw 官方文档中列出的 **所有** 环境变量在 HF Spaces / Docker 中
|
| 146 |
+
# 设置后均可直接生效。
|
| 147 |
+
# 官方完整列表见:https://openclawdoc.com/docs/reference/environment-variables
|
| 148 |
+
#
|
| 149 |
+
# 常见类别(仅列举部分):
|
| 150 |
+
# API Keys: OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEY, MISTRAL_API_KEY,
|
| 151 |
+
# COHERE_API_KEY, OPENROUTER_API_KEY
|
| 152 |
+
# Server: OPENCLAW_API_PORT, OPENCLAW_WS_PORT, OPENCLAW_METRICS_PORT,
|
| 153 |
+
# OPENCLAW_HOST, OPENCLAW_TLS_*
|
| 154 |
+
# App: OPENCLAW_CONFIG, OPENCLAW_DATA_DIR, OPENCLAW_LOG_LEVEL,
|
| 155 |
+
# OPENCLAW_LOG_FORMAT, OPENCLAW_LOG_FILE, OPENCLAW_ENV
|
| 156 |
+
# Memory: OPENCLAW_MEMORY_BACKEND, OPENCLAW_REDIS_URL, OPENCLAW_SQLITE_PATH
|
| 157 |
+
# Network: OPENCLAW_HTTP_PROXY, OPENCLAW_HTTPS_PROXY, OPENCLAW_NO_PROXY,
|
| 158 |
+
# OPENCLAW_OUTBOUND_MODE
|
| 159 |
+
# Secrets: OPENCLAW_SECRETS_BACKEND, OPENCLAW_SECRETS_KEY, VAULT_ADDR, VAULT_TOKEN
|
| 160 |
+
# Ollama: OLLAMA_HOST, OLLAMA_NUM_PARALLEL, OLLAMA_KEEP_ALIVE
|
| 161 |
+
# Browser: OPENCLAW_BROWSER_EXECUTABLE, OPENCLAW_BROWSER_HEADLESS
|
| 162 |
+
#
|
| 163 |
+
# ═══════════════════════════════════════════════════════════════════════════
|
| 164 |
+
#
|
| 165 |
+
# ═══════════════════════════════════════════════════════════════════════════
|
| 166 |
+
# HuggingClaw 新增变量一览(仅本仓库脚本使用)
|
| 167 |
+
# ═══════════════════════════════════════════════════════════════════════════
|
| 168 |
+
#
|
| 169 |
+
# ─── 安全 / 控制台 ───────────────────────────────────────────────────────
|
| 170 |
+
# OPENCLAW_PASSWORD [推荐] 控制台密码,未设则默认 huggingclaw
|
| 171 |
+
#
|
| 172 |
+
# ─── 持久化 (HuggingFace Dataset) ───────────────────────────────────────
|
| 173 |
+
# HF_TOKEN [必填] HF 访问令牌,需具备写入权限
|
| 174 |
+
# OPENCLAW_DATASET_REPO [必填] 备份用 Dataset 仓库,如 your-name/openclaw-data
|
| 175 |
+
# AUTO_CREATE_DATASET [可选] 是否自动创建仓库,默认 true
|
| 176 |
+
# SYNC_INTERVAL [可选] 备份间隔(秒),默认 120
|
| 177 |
+
# HF_HUB_DOWNLOAD_TIMEOUT [可选] 下载超时(秒),默认 300
|
| 178 |
+
# HF_HUB_UPLOAD_TIMEOUT [可选] 上传超时(秒),默认 600
|
| 179 |
+
#
|
| 180 |
+
# ─── LLM / 对话 API(至少配置其一以启用 AI 对话)────────────────────────
|
| 181 |
+
# OPENAI_API_KEY [推荐] OpenAI 或兼容端点 API Key
|
| 182 |
+
# OPENAI_BASE_URL [可选] 兼容 API 基地址,默认 https://api.openai.com/v1
|
| 183 |
+
# OPENROUTER_API_KEY [可选] OpenRouter,200+ 模型、免费额度
|
| 184 |
+
# ANTHROPIC_API_KEY [可选] Anthropic Claude
|
| 185 |
+
# GOOGLE_API_KEY [可选] Google / Gemini
|
| 186 |
+
# MISTRAL_API_KEY [可选] Mistral
|
| 187 |
+
# COHERE_API_KEY [可选] Cohere
|
| 188 |
+
# OPENCLAW_DEFAULT_MODEL [可选] 默认模型 ID
|
| 189 |
+
#
|
| 190 |
+
# ─── 消息渠道 ─────────────────────────────────────────────────────────
|
| 191 |
+
# Telegram、WhatsApp 等消息渠道均可在 Control UI 中配置,无需环境变量。
|
| 192 |
+
#
|
| 193 |
+
# ─── HuggingFace Spaces 运行时(HF 自动注入,一般无需手动设)────────────
|
| 194 |
+
# SPACE_HOST 当前 Space 域名,如 xxx.hf.space
|
| 195 |
+
# SPACE_ID 仓库 ID,如 username/HuggingClaw
|
| 196 |
+
#
|
| 197 |
+
# ─── 性能与运行 ───────────────────────────────────────────────────────
|
| 198 |
+
# NODE_MEMORY_LIMIT [可选] Node 堆内存上限(MB),默认 512
|
| 199 |
+
# TZ [可选] 时区,如 Asia/Shanghai
|
| 200 |
+
#
|
| 201 |
+
# ════════════���══════════════════════════════════════════════════════════════
|
README.md
CHANGED
|
@@ -42,7 +42,14 @@ tags:
|
|
| 42 |
<br/><br/>
|
| 43 |
|
| 44 |
[](LICENSE)
|
| 45 |
-
[) |
|
| 100 |
-
| **Performance** | `NODE_MEMORY_LIMIT` | Tune Node.js memory usage |
|
| 101 |
-
| **Locale** | `TZ` | Set timezone for logs |
|
| 102 |
-
|
| 103 |
-
For local development, copy the template and fill in your values:
|
| 104 |
-
|
| 105 |
-
```bash
|
| 106 |
-
cp .env.example .env
|
| 107 |
-
# Edit .env with your values
|
| 108 |
-
```
|
| 109 |
-
|
| 110 |
-
## Local Development
|
| 111 |
-
|
| 112 |
-
```bash
|
| 113 |
-
git clone https://huggingface.co/spaces/tao-shen/HuggingClaw
|
| 114 |
-
cd HuggingClaw
|
| 115 |
-
|
| 116 |
-
# Configure
|
| 117 |
-
cp .env.example .env
|
| 118 |
-
# Edit .env — at minimum set HF_TOKEN and OPENCLAW_DATASET_REPO
|
| 119 |
-
|
| 120 |
-
# Build and run
|
| 121 |
-
docker build -t huggingclaw .
|
| 122 |
-
docker run --rm -p 7860:7860 --env-file .env huggingclaw
|
| 123 |
-
```
|
| 124 |
-
|
| 125 |
-
Open `http://localhost:7860` in your browser.
|
| 126 |
|
| 127 |
## Security
|
| 128 |
|
| 129 |
- **Password-protected** — the Control UI requires a password to connect and manage the instance
|
| 130 |
- **Secrets stay server-side** — API keys and tokens are never exposed to the browser
|
| 131 |
-
- **CSP headers** — Content Security Policy restricts script and resource loading
|
| 132 |
- **Private backups** — the Dataset repo is created as private by default
|
| 133 |
|
| 134 |
> **Tip:** Change the default password from `huggingclaw` to something unique by setting the `OPENCLAW_PASSWORD` secret.
|
|
|
|
| 42 |
<br/><br/>
|
| 43 |
|
| 44 |
[](LICENSE)
|
| 45 |
+
[](https://huggingface.co)
|
| 46 |
+
[](https://huggingface.co/spaces/tao-shen/HuggingClaw)
|
| 47 |
+
[](https://github.com/openclaw/openclaw)
|
| 48 |
+
[](https://www.docker.com/)
|
| 49 |
+
[](https://openclawdoc.com/docs/reference/environment-variables)
|
| 50 |
+
[](https://www.whatsapp.com/)
|
| 51 |
+
[](https://telegram.org/)
|
| 52 |
+
[](https://huggingface.co/spaces)
|
| 53 |
</div>
|
| 54 |
|
| 55 |
---
|
|
|
|
| 97 |
|
| 98 |
## Configuration
|
| 99 |
|
| 100 |
+
HuggingClaw supports **all OpenClaw environment variables** — it passes the entire environment to the OpenClaw process (`env=os.environ.copy()`), so any variable from the [OpenClaw docs](https://openclawdoc.com/docs/reference/environment-variables) (API Keys, Server, Memory, Network, Ollama, Secrets Manager, etc.) works out of the box in HF Spaces.
|
| 101 |
|
| 102 |
+
HuggingClaw adds a few variables of its own for persistence and deployment: `HF_TOKEN`, `OPENCLAW_DATASET_REPO`, `AUTO_CREATE_DATASET`, `SYNC_INTERVAL`, `OPENCLAW_PASSWORD`, `OPENCLAW_DEFAULT_MODEL`, etc. For the full list, see [`.env.example`](.env.example).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
|
| 104 |
## Security
|
| 105 |
|
| 106 |
- **Password-protected** — the Control UI requires a password to connect and manage the instance
|
| 107 |
- **Secrets stay server-side** — API keys and tokens are never exposed to the browser
|
|
|
|
| 108 |
- **Private backups** — the Dataset repo is created as private by default
|
| 109 |
|
| 110 |
> **Tip:** Change the default password from `huggingclaw` to something unique by setting the `OPENCLAW_PASSWORD` secret.
|
scripts/sync_hf.py
CHANGED
|
@@ -57,11 +57,6 @@ APP_DIR = Path("/app/openclaw")
|
|
| 57 |
# Use ".openclaw" - directly read/write the .openclaw folder in dataset
|
| 58 |
DATASET_PATH = ".openclaw"
|
| 59 |
|
| 60 |
-
# Telegram credentials (backward-compatible; prefer configuring via Control UI)
|
| 61 |
-
TELEGRAM_BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "")
|
| 62 |
-
TELEGRAM_BOT_NAME = os.environ.get("TELEGRAM_BOT_NAME", "")
|
| 63 |
-
TELEGRAM_ALLOW_USER = os.environ.get("TELEGRAM_ALLOW_USER", "")
|
| 64 |
-
|
| 65 |
# OpenAI-compatible API (OpenAI, OpenRouter, or any compatible endpoint)
|
| 66 |
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "")
|
| 67 |
OPENAI_BASE_URL = os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1").rstrip("/")
|
|
@@ -146,14 +141,12 @@ class OpenClawFullSync:
|
|
| 146 |
print("[SYNC] Persistence disabled - skipping restore")
|
| 147 |
self._ensure_default_config()
|
| 148 |
self._patch_config()
|
| 149 |
-
self._ensure_telegram_credentials()
|
| 150 |
return
|
| 151 |
|
| 152 |
if not self.dataset_exists:
|
| 153 |
print(f"[SYNC] Dataset {HF_REPO_ID} does not exist - starting fresh")
|
| 154 |
self._ensure_default_config()
|
| 155 |
self._patch_config()
|
| 156 |
-
self._ensure_telegram_credentials()
|
| 157 |
return
|
| 158 |
|
| 159 |
print(f"[SYNC] ▶ Restoring ~/.openclaw from dataset {HF_REPO_ID} ...")
|
|
@@ -165,8 +158,7 @@ class OpenClawFullSync:
|
|
| 165 |
if not openclaw_files:
|
| 166 |
print(f"[SYNC] No {DATASET_PATH}/ folder in dataset. Starting fresh.")
|
| 167 |
self._ensure_default_config()
|
| 168 |
-
|
| 169 |
-
return
|
| 170 |
|
| 171 |
print(f"[SYNC] Found {len(openclaw_files)} files under {DATASET_PATH}/ in dataset")
|
| 172 |
|
|
@@ -194,7 +186,7 @@ class OpenClawFullSync:
|
|
| 194 |
print(f"[SYNC] ✗ Restore failed: {e}")
|
| 195 |
traceback.print_exc()
|
| 196 |
|
| 197 |
-
# Patch config
|
| 198 |
self._patch_config()
|
| 199 |
self._ensure_telegram_credentials()
|
| 200 |
self._debug_list_files()
|
|
@@ -435,36 +427,6 @@ class OpenClawFullSync:
|
|
| 435 |
print(f"[SYNC] Failed to patch config: {e}")
|
| 436 |
traceback.print_exc()
|
| 437 |
|
| 438 |
-
def _ensure_telegram_credentials(self):
|
| 439 |
-
"""Configure Telegram bot token and allowed users."""
|
| 440 |
-
creds_dir = OPENCLAW_HOME / "credentials"
|
| 441 |
-
creds_dir.mkdir(parents=True, exist_ok=True)
|
| 442 |
-
|
| 443 |
-
if TELEGRAM_BOT_TOKEN:
|
| 444 |
-
bot_file = creds_dir / "telegram-bot-token.json"
|
| 445 |
-
with open(bot_file, "w") as f:
|
| 446 |
-
json.dump({"token": TELEGRAM_BOT_TOKEN, "bot": TELEGRAM_BOT_NAME}, f, indent=2)
|
| 447 |
-
print(f"[SYNC] Telegram bot configured: {TELEGRAM_BOT_NAME}")
|
| 448 |
-
|
| 449 |
-
allow_file = creds_dir / "telegram-allowFrom.json"
|
| 450 |
-
if not allow_file.exists():
|
| 451 |
-
with open(allow_file, "w") as f:
|
| 452 |
-
json.dump([TELEGRAM_ALLOW_USER], f, indent=2)
|
| 453 |
-
print(f"[SYNC] Created telegram-allowFrom.json for {TELEGRAM_ALLOW_USER}")
|
| 454 |
-
else:
|
| 455 |
-
try:
|
| 456 |
-
with open(allow_file, "r") as f:
|
| 457 |
-
data = json.load(f)
|
| 458 |
-
if not isinstance(data, list):
|
| 459 |
-
data = [TELEGRAM_ALLOW_USER]
|
| 460 |
-
elif TELEGRAM_ALLOW_USER not in data:
|
| 461 |
-
data.append(TELEGRAM_ALLOW_USER)
|
| 462 |
-
with open(allow_file, "w") as f:
|
| 463 |
-
json.dump(data, f, indent=2)
|
| 464 |
-
except Exception:
|
| 465 |
-
with open(allow_file, "w") as f:
|
| 466 |
-
json.dump([TELEGRAM_ALLOW_USER], f, indent=2)
|
| 467 |
-
|
| 468 |
def _debug_list_files(self):
|
| 469 |
print(f"[SYNC] Local ~/.openclaw tree:")
|
| 470 |
try:
|
|
|
|
| 57 |
# Use ".openclaw" - directly read/write the .openclaw folder in dataset
|
| 58 |
DATASET_PATH = ".openclaw"
|
| 59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
# OpenAI-compatible API (OpenAI, OpenRouter, or any compatible endpoint)
|
| 61 |
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "")
|
| 62 |
OPENAI_BASE_URL = os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1").rstrip("/")
|
|
|
|
| 141 |
print("[SYNC] Persistence disabled - skipping restore")
|
| 142 |
self._ensure_default_config()
|
| 143 |
self._patch_config()
|
|
|
|
| 144 |
return
|
| 145 |
|
| 146 |
if not self.dataset_exists:
|
| 147 |
print(f"[SYNC] Dataset {HF_REPO_ID} does not exist - starting fresh")
|
| 148 |
self._ensure_default_config()
|
| 149 |
self._patch_config()
|
|
|
|
| 150 |
return
|
| 151 |
|
| 152 |
print(f"[SYNC] ▶ Restoring ~/.openclaw from dataset {HF_REPO_ID} ...")
|
|
|
|
| 158 |
if not openclaw_files:
|
| 159 |
print(f"[SYNC] No {DATASET_PATH}/ folder in dataset. Starting fresh.")
|
| 160 |
self._ensure_default_config()
|
| 161 |
+
return
|
|
|
|
| 162 |
|
| 163 |
print(f"[SYNC] Found {len(openclaw_files)} files under {DATASET_PATH}/ in dataset")
|
| 164 |
|
|
|
|
| 186 |
print(f"[SYNC] ✗ Restore failed: {e}")
|
| 187 |
traceback.print_exc()
|
| 188 |
|
| 189 |
+
# Patch config after restore
|
| 190 |
self._patch_config()
|
| 191 |
self._ensure_telegram_credentials()
|
| 192 |
self._debug_list_files()
|
|
|
|
| 427 |
print(f"[SYNC] Failed to patch config: {e}")
|
| 428 |
traceback.print_exc()
|
| 429 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 430 |
def _debug_list_files(self):
|
| 431 |
print(f"[SYNC] Local ~/.openclaw tree:")
|
| 432 |
try:
|