--- name: websimple-devops description: Operate the Websimple WordPress development environment — the local websimple-stack Docker Compose project, WordPress site lifecycle (create, sync, reset), Composer dependencies, Kaliroots child themes, ACF conventions, asset build pipelines, browser/Xdebug debugging, and Gitea metadata lookups. Use whenever the user mentions a Websimple WordPress site, a `wp-sites` Gitea repository, the `ledevsimple.ca` local domain (or another `WEBSIMPLE_STACK_DOMAIN`), `websimple-stack`, `wp-apache2`, Kaliroots, ACF in a Websimple context, or any local WordPress dev task on a developer machine configured for Websimple. Also use when a request implies operations on a Websimple project even without naming it explicitly — for example "spin up a local copy of example.com", "pull production into local for site X", "fix the Composer install for this site", "what's the production URL for client Y". --- # Websimple DevOps Operate Websimple's local WordPress development environment: the `websimple-stack` Docker Compose project, the WordPress sites it serves, the Composer-managed plugins/themes inside them, and the Gitea metadata that holds deployment values. This skill packages a router (this file) plus 13 topic-specific reference files under `references/` and a Bash wrapper for Gitea API reads under `scripts/`. The reference files contain the operational detail — read them when a task lands in their area. Don't try to remember their content; resolve the topic, then read the file. ## Required environment variables These must be set in the user's shell before any operation that needs them. Fail fast and ask the user to export them if they're missing — do not guess defaults. | Variable | Meaning | |---|---| | `WEBSIMPLE_STACK_PATH` | Absolute path to the local `websimple-stack` Docker Compose checkout. | | `WEBSIMPLE_STACK_PROTOCOL` | `http` or `https` — protocol used by local Traefik routing. | | `WEBSIMPLE_STACK_DOMAIN` | Local domain suffix Traefik routes wildcard subdomains for (e.g. `ledevsimple.ca`). | | `WP_LOCAL_ROOT_PATH` | Absolute path to the shared WordPress root path served by the `wp-apache2` service. | | `WEBSIMPLE_GITEA_API_TOKEN` | Read-only Gitea API token for metadata lookups. | Treat all of these as sensitive in the sense that the token must never be echoed back in chat. The paths and domain are not secrets, but still read them from the environment rather than hard-coding so the skill stays portable across user setups. ### Loading the variables (Cowork sessions) The Cowork bash sandbox does **not** inherit the user's host `.bashrc`/`.profile` — each bash call starts fresh and only sees env vars injected by the harness. The user keeps a shared env file at `~/.config/cowork/env.sh` on the host (also sourced by their host `.bashrc`, so it's a single source of truth). In Cowork, that path appears under the session's mount as `/sessions//mnt/cowork/env.sh`. At the start of any bash call that needs these variables, source the file if it exists. Resolve the session mount path dynamically rather than hard-coding a session ID: ```bash COWORK_ENV="$(ls /sessions/*/mnt/cowork/env.sh 2>/dev/null | head -1)" [ -n "$COWORK_ENV" ] && . "$COWORK_ENV" ``` If `env.sh` isn't found, fall back to normal behavior: check each variable and, when something's missing, ask the user either to export it or to approve mounting `~/.config/cowork/` (whichever is the actual gap). ## Reference index — read the file that matches the task For any non-trivial task, **read the matching reference file first** before producing commands or making changes. The reference files encode conventions that aren't obvious from the codebase and that the user expects to be followed. | Concern | Reference file | |---|---| | Host environment, Docker Compose, Traefik, required executables, MySQL/WP-CLI defaults | `references/websimple-stack.md` | | Websimple Gitea conventions, repository URLs, Actions variables, token usage | `references/websimple-gitea.md` | | WordPress project naming, slug derivation, local/remote URL/DB/path conventions | `references/wp-project.md` | | Local site lifecycle — create, clone, provision from remote, reset, delete | `references/wp-local-site.md` | | Composer dependency management, Satis private repo, plugin/theme integrity | `references/wp-composer.md` | | General WordPress theme PHP conventions (non-Kaliroots) | `references/wp-theme-dev.md` | | Kaliroots parent/child theme conventions and overrides | `references/wp-kaliroots.md` | | ACF field groups, local JSON, options pages, naming, output | `references/wp-acf.md` | | Theme asset source, Vite/Tailwind build, enqueue integration | `references/wp-assets.md` | | Lovable → WordPress conversion (Lovable React export into Websimple theme) | `references/wp-lovable.md` | | Browser-based smoke checks, navigation, SSRF allowlisting | `references/wp-browser.md` | | Autonomous Xdebug runtime debugging | `references/wp-xdebug.md` | | PHPCS/PHPCBF tooling and coding-standard checks | `references/wp-code-style.md` | Many tasks touch more than one area. For example, "sync example.com's production database into my local site" needs `wp-project.md` (to resolve names and paths), `websimple-gitea.md` (to read `WP_SITE_URL` and SSH metadata), and `wp-local-site.md` (the synchronize-from-remote workflow). Read all three before starting. ## Gitea API access — use the bundled script Three read-only Gitea operations are available via `scripts/gitea.sh`. They replace what used to be OpenClaw plugin tools and require `WEBSIMPLE_GITEA_API_TOKEN` plus `jq` and `curl`. ```bash # List repositories in the wp-sites org (default org is wp-sites) bash "${SKILL_ROOT}/scripts/gitea.sh" repos-list # List Actions variables for a repository bash "${SKILL_ROOT}/scripts/gitea.sh" vars-list wp-sites example # Get one Actions variable bash "${SKILL_ROOT}/scripts/gitea.sh" var-get wp-sites example WP_SITE_URL ``` Each prints a JSON envelope on stdout and exits non-zero with a stderr message on failure. See `references/websimple-gitea.md` for the full operation set and output shapes. `${SKILL_ROOT}` here is the directory containing this `SKILL.md`. Resolve it from the path of this file when invoking the script. ## Safety defaults These apply across every reference file. They override anything in a reference that conflicts. - **Prefer read-only inspection before changing anything.** Before deleting, dropping a database, overwriting files, or running broad updates, show the resolved values (path, DB name, URL) and ask for confirmation. - **Treat remote hosts as read-only.** Production/staging WordPress sites should only be read from (database export, file rsync) — never written to, never updated, never have plugins deactivated, never have WP-CLI mutations run against them. The only approved remote action shapes are read-only WP-CLI commands (e.g. `wp option get`, `wp db export -`), `rsync` *from* remote *to* local, and SSH connection tests. - **Never echo secrets.** Do not print `WEBSIMPLE_GITEA_API_TOKEN`, admin passwords, or anything from `~/.my.cnf` or `~/.wp-cli/config.yml` back in chat. When using them, reference them by variable name. - **Preserve source-controlled files.** When repairing Composer-managed plugins/themes, never delete directories that are tracked in Git — only ignored/disposable install artifacts. See `references/wp-composer.md` for the integrity-check pattern. - **Use recoverable deletion where possible.** Prefer moving files to the user's trash over `rm -rf` when shelling out, especially for project directories. ## Workflow shape For a typical request: 1. Identify which reference(s) the task falls under from the table above. 2. Read those reference file(s) — fully, not just headings. 3. Resolve the WordPress project's slug, paths, domain, and DB name using `references/wp-project.md` conventions and the relevant environment variables. 4. If remote metadata is needed (production URL, SSH host/port/user/path), prefer `scripts/gitea.sh var-get` against the matching `wp-sites/` repository before falling back to SSH inspection. 5. Run small read-only checks before any change. 6. Make the smallest change that accomplishes the request, asking for confirmation before destructive steps. 7. Verify with a small post-change check. When in doubt about which reference applies, the simple rule: the file's name describes its concern. `wp-acf.md` is for ACF questions, `wp-xdebug.md` is for Xdebug-driven debugging, and so on.