Install
openclaw skills install @rockbenben/md-webopenclaw skills install @rockbenben/md-webUpload raw .md files to an S3-compatible storage bucket, where a pre-deployed Docsify server automatically renders them as web pages. This avoids sending long text in the conversation.
Uploaded content is publicly accessible, and publishing cannot be undone. Only use this skill when the user explicitly requests it:
/md-web)Before the first upload of a session, tell the user the document will be readable by anyone with the link, and wait for their go-ahead. Publishing to a public URL is not something to infer from "整理一下" or "看看效果" — if the user did not ask for a web page or a link, answer in chat instead.
Check if ~/.md-web/config.json exists (cross-platform: use the user's home directory). If it does NOT exist or has empty fields, follow the Configuration section below first.
One exception: an older install kept config.json in the skill's own directory rather than in the home directory. If ~/.md-web/config.json is absent but that legacy file is sitting next to upload.js, skip the wizard and run the upload — the script copies both it and .deployed into ~/.md-web/ and prints Config migrated to:. Running the wizard instead would ask the user for credentials that are already on disk.
Either use an existing .md file, or write the content to a temporary file. Choose the temp path based on the current platform (e.g., /tmp/ on Linux/macOS, %TEMP%\ on Windows — note Git Bash does not expand %TEMP%, so use $TEMP there). Use whichever path works in the current shell environment. Delete a temp file you created once the upload reports its URL.
Only the .md file itself is uploaded. Relative image references () will be broken on the page — tell the user to use absolute image URLs for documents that need pictures.
node "{SKILL_DIR}/upload.js" --setup
Run this before the first upload on a machine, and again after upgrading the skill —
it is what makes the published links work. It writes the viewer files (index.html
and assets/) to the bucket root, which is shared state that every published
document depends on, so it is a command of its own rather than something an upload
does on the side. It also applies the expire_days setting from config.json.
{SKILL_DIR}: the base directory of this skill (shown at the top when skill is loaded). Keep it inside quotes — a skills directory under a path with spaces breaks the shell otherwise.expire_days, bucket or public_url. It is safe to repeat..deployed in ~/.md-web/ already matches this bucket and these files; the upload command below reports when setup is needed.node "{SKILL_DIR}/upload.js" <local-file> <remote-key>
<remote-key>: a short ASCII, lowercase, hyphenated name with no spaces (e.g., api-docs.md, project-guide.md) — use this even when the document's own title is Chinese, because the key is what appears in the public URL. A timestamp is prepended automatically to avoid filename collisions, the extension is forced to .md, and the object lands under the md-web/ prefix.Warning: lifecycle — — the token lacks Admin Read & Write: grant the permission and re-run --setup, or set the rule in the Cloudflare Dashboard.Example success output:
api-docs- https://example.r2.dev/index.html#/md-web/20260305-091500-api-docs
This only needs to happen once. On subsequent runs, config.json already exists.
Tell the user this skill needs an S3-compatible storage bucket with public access. Point them to {SKILL_DIR}/README.md for detailed setup instructions (Cloudflare R2 / AWS S3 / other S3-compatible services), or {SKILL_DIR}/README.zh.md when the user works in Chinese — the same document in the other language, with identical steps.
Ask the user to provide these 5 required fields:
https:// (e.g., ACCOUNT_ID.r2.cloudflarestorage.com)https://docs.example.com); otherwise use the default R2.dev URL (e.g., https://pub-XXXX.r2.dev). Recommend custom domain for production use — R2.dev URLs have rate limits.If the user would rather not keep a long-lived secret in a file, say that access_key and secret_key can be left out of config.json and supplied as the MD_WEB_ACCESS_KEY / MD_WEB_SECRET_KEY environment variables instead — the config file wins when both are set.
Ask about optional settings:
auto for Cloudflare R2, or the actual region for AWS S3 (e.g., us-east-1). Default is auto.md-web/ key prefix; set 0 to have it remove that rule again. Either way the viewer files at the bucket root and unrelated objects are never touched, and rules the user set themselves are preserved: the script reads the bucket's lifecycle configuration, drops only its own rule, and writes the rest back unchanged. Changing this requires an Admin Read & Write token — with a narrower one the script warns and carries on, and the user can set the rule in the Cloudflare Dashboard instead.Write the config to ~/.md-web/config.json (create the ~/.md-web/ directory if it doesn't exist). Use the user's home directory ($HOME on Unix, %USERPROFILE% on Windows):
{
"access_key": "...",
"secret_key": "...",
"endpoint": "...",
"bucket": "...",
"region": "auto",
"public_url": "..."
}
Omit expire_days unless the user actually asked for auto-expiry — writing it in by default would put every user back on a token that needs bucket-admin rights.
.md file — Docsify handles rendering.This skill connects only to the S3 endpoint configured by the user in config.json. No data is sent to the skill author or any third-party service.
| Endpoint | Purpose | Data sent |
|---|---|---|
User's S3 endpoint (config.json → endpoint) | Upload .md files and Docsify server assets | File content, S3 auth headers |
~/.md-web/config.json (outside the skill directory, safe from upgrades) and are only sent to the user's own S3 endpoint for authentication. Two ways to reduce the exposure: put them in the MD_WEB_ACCESS_KEY / MD_WEB_SECRET_KEY environment variables instead of the file, or keep them in the file and let the script's chmod 600 stand (it applies on macOS/Linux; Windows file permissions are not changed). Protect the file — don't commit it or share it.md-web/ key prefix and any rule this skill manages is scoped to that prefix, so viewer files and unrelated objects are never expired. A dedicated bucket is still the clean answer: it keeps this skill's bucket-administration rights away from anything you actually care about.<details> blocks, alignment and inline images work. It is protected by two things: a route guard (docsify-server/assets/config.js) that only ever loads same-origin paths under md-web/, so a crafted link cannot make the viewer fetch a document from another origin, and a Content-Security-Policy that keeps 'unsafe-inline' out of script-src, so HTML inside a document cannot run script either. Treat the domain as public and untrusted regardless: it holds documents anyone can publish into your bucket.upload.js uses only Node.js built-in modules and all Docsify assets are bundled locally — no third-party dependencies, no CDN at runtime.By using this skill, markdown content is uploaded to your own S3-compatible storage bucket and made publicly accessible. No data is sent to the skill author or any third-party service. Only install if you trust the storage provider you configure.