core/worker/skills/opch-sites/SKILL.md
Publish static sites from Chloe's workspace under `sites/` using a single `sites/sites.json` registry. Use when the user asks Chloe to create, update, publish, or expose one or more websites, especially from a monorepo.
npx skillsauth add mere/op-and-chloe opch-sitesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Chloe can publish static sites from her workspace. Every published site must live under sites/ in the worker workspace, and publishing is controlled by one registry file: sites/sites.json.
Use this structure:
sites/
sites.json
marketing/
dist/
index.html
docs/
build/
index.html
sites/.root is a path relative to sites/.sites/.Create sites/sites.json:
{
"sites": [
{
"name": "marketing",
"subdomain": "marketing",
"root": "marketing/dist"
},
{
"name": "docs",
"subdomain": "docs",
"root": "docs/build",
"basicauth": {
"user": "preview",
"bcrypt": "$2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG"
}
}
]
}
Fields per entry:
name: required, human-readable unique label for the site entry.subdomain: required, lowercase letters/numbers/hyphens only. The public hostname becomes <subdomain>.<base-domain>.root: required, directory path relative to sites/. It must point to a subdirectory, not sites/ itself.basicauth: optional. When set, the proxy requires HTTP Basic Auth for that site only. Must be an object with user (login name) and bcrypt (bcrypt modular-crypt hash). Generate the hash inside the worker with Python — no Docker or Caddy required:printf '%s' 'YOUR_PASSWORD' | python3 /opt/op-and-chloe/scripts/sites/hash_site_password.pybcrypt. Prefer stdin so the password does not appear in shell history or ps. Never put a plaintext password in sites.json.URL resolution (no extra flags): The proxy always applies a single try_files chain: exact path, then {path}.html, then {path}/index.html, then {path}/, then /index.html. That covers Next.js out/-style pages, folder indexes, and SPAs that need a root index.html fallback. Legacy spa / html_paths keys in JSON are ignored.
Host ops: If extensionless URLs 404 but *.html works after a stack git pull, the sites-reconciler container may still be the old long-running python … --interval process (never reloads script from disk). Recreate it with compose (--force-recreate sites-reconciler) so it runs reconciler-loop.sh and picks up SITES_* from --env-file /etc/openclaw/stack.env.
When asked to publish a site:
sites/<site-name>/ or another nested folder inside sites/.sites/, such as marketing/dist or docs/build.sites/sites.json with a unique name, subdomain, and root.basicauth with user and bcrypt. Generate bcrypt with python3 /opt/op-and-chloe/scripts/sites/hash_site_password.py (pipe the password on stdin; see script docstring). Never write a plaintext password into the registry.https://<subdomain>.<base-domain>.Published sites are public by default (anyone with the link). For private or sensitive work: keep publishing off, unpublish by removing the registry entry, add optional basicauth on that site’s registry entry (bcrypt hash only), or build login inside the app (OAuth, magic links, etc.).
sites/ in Chloe's workspace... in root.root at sites/ itself.sites/ before publishing.sites/sites.json.development
Use the shared webtop browser for pages that need login (LinkedIn, social, etc.); guide the user to log in in webtop when needed.
devops
Set up and use email in the worker (Himalaya for Gmail/iCloud/other, M365 for Microsoft).
tools
Bitwarden in Chloe — day-to-day instance has bw in PATH; use for vault access.
data-ai
Exec approvals — when Op runs a host command not on the allowlist, OpenClaw may prompt; use Control UI or chat to allow/deny.