Norml WordPress Copilot Advanced
Installed skill: norml-wp-developer.
CLI only. Run this skill in Claude Code, Codex, or Gemini CLI with
filesystem and terminal access. It is not a Claude Desktop / Cowork upload
skill. Desktop users should use Norml WordPress Copilot (norml-wp-manager),
which operates through the WordPress REST API.
Local-only migration exception: For Squarespace-to-WordPress or HTML-to-WordPress builds before hosting exists, start with the migration recipe. It creates a verified local-only contract and disables every remote operation until normal hosting-connected onboarding passes.
Requires hosting-connected onboarding for remote work. Before this skill can perform hosting-connected work, the user must
run onboarding.md once per project on their machine. If
~/.config/norml-wp-developer/projects/{slug}.json is missing for the
project they're asking about, hard-stop and point at onboarding.md.
Never improvise the SSH connection by asking for host/port/passphrase in
chat.
⛔ HARD WARNING — backups are not optional and not provided
This skill does not make backups for you. The flows here — rsync
over SSH, wp db import, theme deploys, wp search-replace — can lose
data if a step fails or a wrong path is passed. You are expected to:
- Keep host-side automatic backups on (most managed hosts have this on
by default; verify in your hosting panel).
- Or take a manual backup before any destructive operation. A safe
manual backup is two things: a database dump and a
wp-content/
archive. Both must live OFF the server you're deploying to.
Every deploy command in this skill prints a backup-acknowledgement
prompt — you confirm a backup exists before the command runs. The
default answer is "no, abort." There is no autopilot here. If you
lose data, you lose data. No skill can recover it.
🟡 Working directly on the production server is elevated risk
The skill supports two modes:
- Local-first (recommended). Develop locally against WP Local /
DDEV / similar. Commit to Git. Push. CI/CD ships to staging, you
smoke test, then promote to production. Mistakes stay local until
you explicitly promote them. This is the pattern setup defaults
to.
- Direct-on-server. Edit theme files on the production server via
SSH. Faster for one-line hotfixes; risky because there's no
local copy to fall back to and the next CI/CD deploy can
overwrite your live edit if it isn't mirrored to Git. Permitted
but every direct-on-server write is logged as
[DIRECT-PROD] in
the project changelog and triggers a warning that the change is
not in Git.
Default to local-first. Reach for direct-on-server only when the
developer has explicitly chosen it for a specific operation.
When to use
For "migrate my Squarespace website", "turn this mirror into WordPress", or
"build this HTML mockup in WordPress", read Squarespace to WordPress first.
Any request to build, modify, or deploy theme code for a WordPress
site. Typical asks:
- "Set up a new WordPress project from scratch."
- "Initialize this WordPress theme repo — scaffold
.claude/, set up
Git, wire it to GitHub."
- "Build a hero block with ACF fields."
- "Add a new ACF block to the existing theme."
- "Ship this to staging."
- "Promote staging to production."
- "Hot-fix a typo on production — direct on the server."
- "Pull production database down to my local."
- "What's the CI/CD pattern for this project?"
Skip if
- The work is content management on a deployed site (posts, ACF
values, media, users, settings). → use
norml-wp-manager. That skill
is REST-API-only, doesn't require SSH, and is safer to hand to
non-developers.
- The work is fixing the WordPress install itself (broken database,
corrupted core files, hosting migration). → escalate to the hosting
provider's support or use a dedicated migration skill.
- The work is security testing / penetration testing. → use a
dedicated security skill.
Three-phase mental model
Every interaction with this skill falls into one of three phases. Each
phase has its own rules + safety posture.
1. Setup (one-time per project)
Done once per project. Outputs:
~/.config/norml-wp-developer/projects/{slug}.json — per-project
connection config (no secrets).
- SSH key (existing or generated) registered with
ssh-agent.
- SSH passphrase (if any) in macOS Keychain / Windows Credential Manager.
- Local WordPress environment detected (WP Local default; DDEV / Lando /
Valet / Local Lightning recognized as alternates).
- Git repo initialized in the theme folder, first commit made.
- GitHub remote configured and read-only connectivity verified.
.claude/ scaffolded inside the theme repo with CLAUDE.md,
capabilities.md, architecture.md, ci-cd.md, rolling changelog,
and generated architecture docs.
- CI/CD pattern chosen +
.github/workflows/ scaffolded.
- Required first-time read-only architecture scrape via WP-CLI over SSH.
See development-guides/wp-local-setup.md for the local environment details and
onboarding.md for the step-by-step.
2. Develop (the everyday workflow)
After setup, building is the bulk of the work. Rules vary by project mode:
- New / Sage-based project (Norml-authored): Roots Sage + Acorn +
Blade + Tailwind v4 + Vite + Alpine.js + ACF Pro. Read
development-guides/dev-conventions.md → Mode A, which routes to
conventions/sage-stack.md, component-system.md,
css-architecture.md, and acf-blocks.md.
- Inherited project (non-Sage, handed to us): respect the existing
architecture. Apply the framework-agnostic core principles
(section/component/partial separation, ACF block registration,
block previews, 3-layer CSS model) inside the existing theme.
Read
development-guides/dev-conventions.md → Mode B, which routes to
conventions/inherited-projects.md (+ css-architecture.md and
acf-blocks.md for the cross-cutting specifics).
Git workflow + commit conventions are the same for both:
GitHub Flow + Conventional Commits. See development-guides/git-workflow.md.
3. Deploy (the gated, backup-required workflow)
The deploy phase runs:
npm run build (or yarn / pnpm equivalent) → produces production
assets.
git push → triggers CI/CD if configured.
- Or
rsync -avz --delete over SSH for direct deploys (no CI/CD).
wp cache flush + wp acorn view:cache (Sage projects) on the
server after deploy.
- Smoke test (HEAD on the homepage, follow-up GET on a CPT archive).
- For staging→prod promotions: re-run the staging deploy steps against
the production server.
Every deploy gates on the backup acknowledgement prompt described in
the HARD WARNING block above. Without acknowledgement, the deploy
aborts. See development-guides/ci-cd/patterns.md for the three supported
patterns and their command sequences, development-guides/qa-gates.md for the
pre-deploy and post-deploy QA checkpoints (staging-based for
full-pipeline, local-based for the prod-direct patterns), and
development-guides/ci-cd/backup-strategies.md for the per-provider backup +
restore detail behind the acknowledgement.
Pre-flight (every session, before the first dev/deploy operation)
If this is an explicitly selected local-only build, use the local pre-flight in
the migration recipe instead.
The following full pre-flight remains mandatory for any hosting-connected operation.
Resolve the project slug from the user's request, the working
directory, or by asking. Slugs are kebab-cased.
Read ~/.config/norml-wp-developer/projects/{slug}.json.
- If missing → hard-stop. Tell the user the project isn't
configured and point them at
onboarding.md. Do NOT improvise SSH
details in chat.
Read the project's .claude/CLAUDE.md and .claude/ci-cd.md
from the theme repo path in the project JSON.
- If
.claude/ is missing → tell the user the project isn't
initialized and offer to run init (scripts/init-claude.sh /
init-claude.ps1) to scaffold it. Don't proceed with dev work
against an un-initialized repo.
Read .claude/capabilities.md and .claude/architecture.md.
capabilities.md is the live operating contract for GitHub, SSH,
WP-CLI, local development, staging, and production.
architecture.md is the index into the latest generated site and theme
snapshot under .claude/docs/.
- If either is missing or still says the first scan is pending, run
scripts/scrape-architecture.sh {slug} (or the PowerShell mirror) before
development.
Read the project changelog at
{theme_root}/.claude/changelog/daily.md (or changelog.md if the
project skipped the rolling-three-tier setup). Surface the most
recent entries — they tell you what was just done.
Identify the project mode from .claude/CLAUDE.md:
mode: sage → New / Norml-authored. Apply Sage conventions.
mode: inherited → Respect the existing theme. Apply
framework-agnostic principles.
Resolve the SSH alias to the production server from the project
JSON. Confirm the alias exists in ~/.ssh/config (the setup script
writes it; if it's missing, re-run setup).
Identify the deploy pattern from .claude/ci-cd.md:
full-pipeline — Git push → CI/CD → staging → manual promote → prod
prod-direct-with-git — Git push → server pulls from Git → prod
prod-direct-no-ci — rsync from local → prod (no automated deployment pipeline; source still committed and pushed to GitHub)
You now have everything needed to operate. Never ask for SSH
passphrases, GitHub tokens, or server passwords in chat. If anything's
missing, point back at onboarding.
Project knowledge layer — inside the theme repo
Every project carries its own .claude/ directory inside the theme
repository (not in the user's project folder, not on Drive — inside
the repo, so it travels with the code).
{theme_root}/.claude/
├── CLAUDE.md # Project overview, mode (sage/inherited), pointers
├── capabilities.md # Generated operating contract for this project
├── architecture.md # Generated architecture summary + docs index
├── ci-cd.md # Per-project deploy contract (pattern, envs, hooks)
├── changelog/
│ ├── README.md # The rolling-three-tier protocol
│ ├── daily.md # Today's raw entries
│ ├── weekly.md # Compressed week
│ └── changelog.md # Long-term history
├── docs/ # 5-file read-only architecture scrape
│ ├── 01-infrastructure.md
│ ├── 02-application.md
│ ├── 03-theme-architecture.md
│ ├── 04-content-structure.md
│ └── 05-issues.md
└── skills/ # Project-specific skills (empty by default)
This is the canonical knowledge layer for this project. Both the
human developer and Claude read from it at every session. It is in
git, committed with the theme code, travels everywhere the repo
travels.
Why .claude/ lives in the theme repo (not in ~/.config/ or on
Drive)
| Concern |
Where it lives |
Why |
| Connection details (host, port, SSH key path, Git remote URL) |
~/.config/norml-wp-developer/projects/{slug}.json |
Per-machine, private. Doesn't travel with the code. |
| Project knowledge (architecture, conventions, decisions, changelog) |
{theme_root}/.claude/ |
Lives with the code, travels in git, available to anyone who clones the repo. |
| Secrets (SSH passphrase, GitHub PAT) |
macOS Keychain / Windows Credential Manager / ssh-agent |
OS-managed. Claude never sees the value. |
This split is non-negotiable. Never write a secret into
{theme_root}/.claude/ — those files are committed to git. Never write
deploy state or build artifacts into ~/.config/ either — they're
per-machine config, not knowledge.
Write-back rules — how the skill compounds knowledge per-project
The point of .claude/ is that every session leaves it richer. Three
write-back triggers:
daily.md — close-of-session changelog (always)
Append an entry to {theme_root}/.claude/changelog/daily.md before
ending any session that:
- Wrote theme code (component, block, template, function)
- Ran a deploy to staging or production
- Performed a direct-on-server edit
- Pulled production DB / uploads to local
- Made a non-trivial decision the next session would benefit from
knowing
Tags:
[CODE] — theme code change
[BUILD] — Vite / Composer / NPM build ran
[DEPLOY-STAGING] — push or deploy to staging
[DEPLOY-PROD] — promote to prod (gated by backup acknowledgement)
[DIRECT-PROD] — edit made directly on the production server (high
risk, flag the un-mirrored-to-git status)
[PULL-DB] — production DB pulled to local
[PULL-UPLOADS] — production uploads pulled to local
[DECISION] — architectural choice worth recording
[LEARNED] — non-obvious fact about this project
The daily file compresses to weekly.md weekly and to changelog.md
when the calendar quarter rolls over — see
{theme_root}/.claude/changelog/README.md for the protocol the init
flow scaffolds.
.claude/CLAUDE.md — project-level decisions
When the user makes a project-level decision ("from now on this site
uses BEM for component class names," "we always set show_in_rest: true on ACF field groups"), update the relevant section of
CLAUDE.md. This file is the durable answer to "how do we work on
this project."
.claude/capabilities.md + architecture docs — rescan only
The visible capability contract, architecture index, and 5-file snapshot are
generated by scripts/scrape-architecture.sh (or .ps1) from local theme files,
Git/GitHub state, and read-only WP-CLI commands over SSH. They are overwritten on
rescan. Anything that should survive a rescan goes in CLAUDE.md or daily.md,
never hand-edited into generated files.
Safety classification — every operation buckets
Three buckets:
Safe — read-only or low-risk single-item operations. Run
immediately. Examples: git status, git log, wp post list on
local, reading any file under the theme repo, listing the active
plugin set.
Confirm — anything that writes to the local repo, to staging, or
changes git state. Show the exact command, show the diff if relevant,
ask for "yes" before running. Examples: git commit, git push,
git rebase, rsync to staging, wp plugin install on local,
database imports.
Confirm + backup — anything that writes to the production server.
Show the exact command, show the backup-acknowledgement prompt,
refuse without an explicit "I have a backup from {date}" reply.
Examples: rsync to production, wp db import on production,
wp search-replace on production, deleting plugin/theme files on
production, direct file edits over SSH on production.
The backup-acknowledgement prompt is mandatory for every production
write. There is no "skip the prompt" flag. If the project's
.claude/ci-cd.md declares the host has automatic backups (and we
trust the host), the prompt may be answered with "yes, host backups
verified" — but only if ci-cd.md says so, and only after the user
explicitly types that phrase.
Output style
- Default to terse. The user wants the result.
- When you ran a command, show the command first (one line, monospaced).
- For
Confirm + backup operations, the backup prompt is mandatory and
shown verbatim. Don't paraphrase it.
- For diffs, prefer
git diff --stat for summary + the full diff on
request rather than dumping 500 lines unprompted.
Error handling
- SSH refused / timeout → don't retry. Suggest the user run
scripts/test-ssh.sh and check their ~/.ssh/config alias.
wp: command not found on the remote → WP-CLI not installed on
the server. Stop, tell the user, suggest contacting their host.
Composer detected ... platform_check.php → server PHP < theme's
Composer floor. Stop, point at the composer.json require.php
line, tell the user to either bump the server PHP or lower the
theme's floor.
- Git conflicts → don't auto-resolve. Show the conflicting files,
let the user pick the side. Conventional Commit rules in
development-guides/git-workflow.md.
- Build failures → show the full Vite / Composer / NPM error, stop,
do not deploy with a failing build.
- Deploy failures mid-flight → stop immediately. Tell the user the
exact step that failed. Do not auto-retry — partial deploys are the
most common cause of broken production.
In all cases, fail loudly and stop. No improvised destructive
recovery.
Knowledge baseline — what the skill reads
| File |
When to read |
development-guides/dev-conventions.md |
At the start of any session that touches theme code. The router — routes to the right conventions/ files by project mode, plus the global rules (Conventional Commits, don't-commit artifacts/secrets, ACF JSON sync caveat). |
development-guides/conventions/sage-stack.md |
Sage / new projects, before building. The Sage + Acorn + Blade + Tailwind v4 + Vite + Alpine + ACF Pro foundation. |
development-guides/conventions/component-system.md |
Before building a section / component / block in a Sage project. Anatomy + core component catalog + the Alpine pattern + layout. |
development-guides/conventions/css-architecture.md |
Before writing ANY CSS, either mode. The 3-layer model + the forbidden per-page-stylesheet rule. |
development-guides/conventions/acf-blocks.md |
Before registering an ACF block or its preview, either mode. Registration + previews + ACF JSON sync. |
development-guides/conventions/inherited-projects.md |
FIRST, whenever you open a non-Sage / inherited theme. Respect-existing decision flow + framework-agnostic principles. |
development-guides/git-workflow.md |
Before any git commit, git push, branch creation, or PR. GitHub Flow + Conventional Commits. |
development-guides/ci-cd/patterns.md |
Before any deploy or any CI/CD configuration task. The three supported patterns and the per-project ci-cd.md contract. |
development-guides/ci-cd/database-strategies.md |
When content / the database moves (or must not move) between environments. |
development-guides/ci-cd/backup-strategies.md |
Before any production write — backup provider, verification, restore runbook, acknowledgement tier. |
development-guides/qa-gates.md |
Before merging, before deploying, and right after deploying. The pre-merge / pre-deploy / post-deploy checkpoints. |
development-guides/safety-rules.md |
At session start. The full Safe / Confirm / Confirm+backup classification with examples. |
development-guides/wp-local-setup.md |
During onboarding, or if the local environment is unclear. WP Local default, DDEV / Lando / Valet / Local Lightning as alternates. |
{theme_root}/.claude/CLAUDE.md |
At session start. Project mode (sage / inherited), live URLs, deploy hints. |
{theme_root}/.claude/capabilities.md |
At session start and before any operation. Verified GitHub, SSH, WP-CLI, local, staging, and production boundary. |
{theme_root}/.claude/architecture.md |
At session start. Latest architecture snapshot summary and read order. |
{theme_root}/.claude/ci-cd.md |
Before any deploy. Per-project pattern, deploy commands, pre/post hooks. |
{theme_root}/.claude/changelog/daily.md |
At session start. The last ~20 entries — what the last sessions touched. |
Hard rules
- Never deploy without an acknowledged backup. The backup-
acknowledgement prompt is mandatory for every production write.
- Never write secrets into committed files. SSH keys, GitHub
PATs, database passwords belong in the OS secret store or
ssh-agent — never in .claude/, never in .env checked into
git, never in commit messages.
- Never silently overwrite production. Every prod write shows the
exact command and waits for explicit "yes."
- Never introduce a new framework on an inherited project without
explicit, in-session approval. Match the existing architecture.
- Always log production writes as
[DEPLOY-PROD] or
[DIRECT-PROD] in daily.md before closing the response.
- Stop on any unexpected error. No improvised recovery.
.claude/ is committed to git. Never write secrets to it.
~/.config/norml-wp-developer/projects/*.json is per-machine and
never committed.
- Local-first is the default. Direct-on-server is permitted but
explicit per-operation. Never default to it.
Related skills
Companion (install both for a full WordPress workflow):
norml-wp-manager — REST-API-only content management on a deployed
site. Use it for posts, pages, ACF values, media. This skill
(norml-wp-developer) is for theme code; norml-wp-manager is for
content. They share no state.
What lives where (recap)
| What |
Where |
Why |
| The skill itself |
Runtime-specific skills directory |
Claude Code, Codex, or Gemini CLI discovers the stable norml-wp-developer slug. |
| Per-project connection config |
~/.config/norml-wp-developer/projects/{slug}.json |
Per-machine. Host, SSH alias, theme repo path, remote URL, deploy pattern. No secrets. |
| Per-project knowledge |
{theme_root}/.claude/ |
Lives in the GitHub repo. Travels with the code. CLAUDE.md, capabilities.md, architecture.md, ci-cd.md, changelog, architecture docs. |
| SSH key |
~/.ssh/{key} |
Owned by the user; ssh-agent holds the passphrase. |
| SSH passphrase |
macOS Keychain (via ssh-add --apple-use-keychain) / Windows ssh-agent (DPAPI-backed) |
OS-managed. Claude never reads it. |
The split is intentional: ~/.config/ is per-machine connection state;
{theme_root}/.claude/ is portable per-project knowledge; the OS
secret store is for secrets.
1---2name: norml-wp-developer3description: Norml WordPress Copilot Advanced: rebuild Squarespace captures and HTML mockups as editable WordPress in Local, with local-only onboarding before hosting. The CLI-only WordPress development skill for Claude Code, Codex, and Gemini CLI. Develop themes locally and deploy through SSH + Git + GitHub Actions. WP Local is the default local environment (DDEV / Lando / Valet recognized too). Per-project onboarding connects GitHub and SSH, verifies remote WP-CLI, chooses the CI/CD pattern, scaffolds .claude/ inside the theme repo, generates capabilities.md, and records a five-file architecture snapshot. The everyday workflow is edit locally, commit, push, stage, smoke test, promote to prod. **Does NOT make backups.** Every production write gates on a backup acknowledgement. Direct-on-server work is permitted but flagged and logged. Local-first is the default. Use when the user says "build a WordPress theme," "develop a WP site," "set up a new WP project," "init this WP project," "ship to staging," "deploy to productio4---56# Norml WordPress Copilot Advanced78Installed skill: `norml-wp-developer`.910> **CLI only.** Run this skill in Claude Code, Codex, or Gemini CLI with11> filesystem and terminal access. It is not a Claude Desktop / Cowork upload12> skill. Desktop users should use Norml WordPress Copilot (`norml-wp-manager`),13> which operates through the WordPress REST API.1415> **Local-only migration exception:** For Squarespace-to-WordPress or HTML-to-WordPress builds before hosting exists, start with [the migration recipe](development-guides/squarespace-to-wordpress.md). It creates a verified local-only contract and disables every remote operation until normal hosting-connected onboarding passes.1617> **Requires hosting-connected onboarding for remote work.** Before this skill can perform hosting-connected work, the user must18> run `onboarding.md` once per project on their machine. If19> `~/.config/norml-wp-developer/projects/{slug}.json` is missing for the20> project they're asking about, hard-stop and point at `onboarding.md`.21> Never improvise the SSH connection by asking for host/port/passphrase in22> chat.2324> ## ⛔ HARD WARNING — backups are not optional and not provided25>26> This skill does **not** make backups for you. The flows here — `rsync`27> over SSH, `wp db import`, theme deploys, `wp search-replace` — can lose28> data if a step fails or a wrong path is passed. You are expected to:29>30> - Keep host-side automatic backups on (most managed hosts have this on31> by default; verify in your hosting panel).32> - Or take a manual backup before any destructive operation. A safe33> manual backup is two things: a database dump and a `wp-content/`34> archive. Both must live OFF the server you're deploying to.35>36> Every deploy command in this skill prints a backup-acknowledgement37> prompt — you confirm a backup exists before the command runs. The38> default answer is "no, abort." There is no autopilot here. **If you39> lose data, you lose data.** No skill can recover it.4041> ## 🟡 Working directly on the production server is elevated risk42>43> The skill supports two modes:44>45> 1. **Local-first (recommended).** Develop locally against WP Local /46> DDEV / similar. Commit to Git. Push. CI/CD ships to staging, you47> smoke test, then promote to production. Mistakes stay local until48> you explicitly promote them. **This is the pattern setup defaults49> to.**50> 2. **Direct-on-server.** Edit theme files on the production server via51> SSH. Faster for one-line hotfixes; risky because there's no52> local copy to fall back to and the next CI/CD deploy can53> overwrite your live edit if it isn't mirrored to Git. Permitted54> but every direct-on-server write is logged as `[DIRECT-PROD]` in55> the project changelog and triggers a warning that the change is56> not in Git.57>58> Default to local-first. Reach for direct-on-server only when the59> developer has explicitly chosen it for a specific operation.6061## When to use6263For "migrate my Squarespace website", "turn this mirror into WordPress", or64"build this HTML mockup in WordPress", read [Squarespace to WordPress](development-guides/squarespace-to-wordpress.md) first.6566Any request to **build, modify, or deploy theme code** for a WordPress67site. Typical asks:6869- *"Set up a new WordPress project from scratch."*70- *"Initialize this WordPress theme repo — scaffold `.claude/`, set up71 Git, wire it to GitHub."*72- *"Build a hero block with ACF fields."*73- *"Add a new ACF block to the existing theme."*74- *"Ship this to staging."*75- *"Promote staging to production."*76- *"Hot-fix a typo on production — direct on the server."*77- *"Pull production database down to my local."*78- *"What's the CI/CD pattern for this project?"*7980## Skip if8182- The work is **content management on a deployed site** (posts, ACF83 values, media, users, settings). → use `norml-wp-manager`. That skill84 is REST-API-only, doesn't require SSH, and is safer to hand to85 non-developers.86- The work is **fixing the WordPress install itself** (broken database,87 corrupted core files, hosting migration). → escalate to the hosting88 provider's support or use a dedicated migration skill.89- The work is **security testing / penetration testing**. → use a90 dedicated security skill.9192## Three-phase mental model9394Every interaction with this skill falls into one of three phases. Each95phase has its own rules + safety posture.9697### 1. Setup (one-time per project)9899Done once per project. Outputs:100101- `~/.config/norml-wp-developer/projects/{slug}.json` — per-project102 connection config (no secrets).103- SSH key (existing or generated) registered with `ssh-agent`.104- SSH passphrase (if any) in macOS Keychain / Windows Credential Manager.105- Local WordPress environment detected (WP Local default; DDEV / Lando /106 Valet / Local Lightning recognized as alternates).107- Git repo initialized in the theme folder, first commit made.108- GitHub remote configured and read-only connectivity verified.109- `.claude/` scaffolded inside the theme repo with `CLAUDE.md`,110 `capabilities.md`, `architecture.md`, `ci-cd.md`, rolling changelog,111 and generated architecture docs.112- CI/CD pattern chosen + `.github/workflows/` scaffolded.113- Required first-time read-only architecture scrape via WP-CLI over SSH.114115See `development-guides/wp-local-setup.md` for the local environment details and116`onboarding.md` for the step-by-step.117118### 2. Develop (the everyday workflow)119120After setup, building is the bulk of the work. Rules vary by project mode:121122- **New / Sage-based project (Norml-authored):** Roots Sage + Acorn +123 Blade + Tailwind v4 + Vite + Alpine.js + ACF Pro. Read124 `development-guides/dev-conventions.md` → Mode A, which routes to125 `conventions/sage-stack.md`, `component-system.md`,126 `css-architecture.md`, and `acf-blocks.md`.127- **Inherited project (non-Sage, handed to us):** respect the existing128 architecture. Apply the framework-agnostic core principles129 (section/component/partial separation, ACF block registration,130 block previews, 3-layer CSS model) inside the existing theme.131 Read `development-guides/dev-conventions.md` → Mode B, which routes to132 `conventions/inherited-projects.md` (+ `css-architecture.md` and133 `acf-blocks.md` for the cross-cutting specifics).134135Git workflow + commit conventions are the same for both:136GitHub Flow + Conventional Commits. See `development-guides/git-workflow.md`.137138### 3. Deploy (the gated, backup-required workflow)139140The deploy phase runs:141142- `npm run build` (or yarn / pnpm equivalent) → produces production143 assets.144- `git push` → triggers CI/CD if configured.145- Or `rsync -avz --delete` over SSH for direct deploys (no CI/CD).146- `wp cache flush` + `wp acorn view:cache` (Sage projects) on the147 server after deploy.148- Smoke test (HEAD on the homepage, follow-up GET on a CPT archive).149- For staging→prod promotions: re-run the staging deploy steps against150 the production server.151152Every deploy gates on the **backup acknowledgement prompt** described in153the HARD WARNING block above. Without acknowledgement, the deploy154aborts. See `development-guides/ci-cd/patterns.md` for the three supported155patterns and their command sequences, `development-guides/qa-gates.md` for the156pre-deploy and post-deploy QA checkpoints (staging-based for157`full-pipeline`, local-based for the prod-direct patterns), and158`development-guides/ci-cd/backup-strategies.md` for the per-provider backup +159restore detail behind the acknowledgement.160161## Pre-flight (every session, before the first dev/deploy operation)162163If this is an explicitly selected local-only build, use the local pre-flight in164[the migration recipe](development-guides/squarespace-to-wordpress.md) instead.165The following full pre-flight remains mandatory for any hosting-connected operation.1661671. **Resolve the project slug** from the user's request, the working168 directory, or by asking. Slugs are kebab-cased.1691702. **Read `~/.config/norml-wp-developer/projects/{slug}.json`.**171 - If missing → hard-stop. Tell the user the project isn't172 configured and point them at `onboarding.md`. Do NOT improvise SSH173 details in chat.1741753. **Read the project's `.claude/CLAUDE.md` and `.claude/ci-cd.md`**176 from the theme repo path in the project JSON.177 - If `.claude/` is missing → tell the user the project isn't178 initialized and offer to run init (scripts/init-claude.sh /179 init-claude.ps1) to scaffold it. Don't proceed with dev work180 against an un-initialized repo.1811824. **Read `.claude/capabilities.md` and `.claude/architecture.md`.**183 - `capabilities.md` is the live operating contract for GitHub, SSH,184 WP-CLI, local development, staging, and production.185 - `architecture.md` is the index into the latest generated site and theme186 snapshot under `.claude/docs/`.187 - If either is missing or still says the first scan is pending, run188 `scripts/scrape-architecture.sh {slug}` (or the PowerShell mirror) before189 development.1901915. **Read the project changelog** at192 `{theme_root}/.claude/changelog/daily.md` (or `changelog.md` if the193 project skipped the rolling-three-tier setup). Surface the most194 recent entries — they tell you what was just done.1951966. **Identify the project mode** from `.claude/CLAUDE.md`:197 - `mode: sage` → New / Norml-authored. Apply Sage conventions.198 - `mode: inherited` → Respect the existing theme. Apply199 framework-agnostic principles.2002017. **Resolve the SSH alias** to the production server from the project202 JSON. Confirm the alias exists in `~/.ssh/config` (the setup script203 writes it; if it's missing, re-run setup).2042058. **Identify the deploy pattern** from `.claude/ci-cd.md`:206 - `full-pipeline` — Git push → CI/CD → staging → manual promote → prod207 - `prod-direct-with-git` — Git push → server pulls from Git → prod208 - `prod-direct-no-ci` — rsync from local → prod (no automated deployment pipeline; source still committed and pushed to GitHub)209210You now have everything needed to operate. **Never** ask for SSH211passphrases, GitHub tokens, or server passwords in chat. If anything's212missing, point back at onboarding.213214## Project knowledge layer — inside the theme repo215216Every project carries its own `.claude/` directory **inside the theme217repository** (not in the user's project folder, not on Drive — inside218the repo, so it travels with the code).219220```221{theme_root}/.claude/222├── CLAUDE.md # Project overview, mode (sage/inherited), pointers223├── capabilities.md # Generated operating contract for this project224├── architecture.md # Generated architecture summary + docs index225├── ci-cd.md # Per-project deploy contract (pattern, envs, hooks)226├── changelog/227│ ├── README.md # The rolling-three-tier protocol228│ ├── daily.md # Today's raw entries229│ ├── weekly.md # Compressed week230│ └── changelog.md # Long-term history231├── docs/ # 5-file read-only architecture scrape232│ ├── 01-infrastructure.md233│ ├── 02-application.md234│ ├── 03-theme-architecture.md235│ ├── 04-content-structure.md236│ └── 05-issues.md237└── skills/ # Project-specific skills (empty by default)238```239240This is the **canonical knowledge layer for this project**. Both the241human developer and Claude read from it at every session. It is **in242git, committed with the theme code, travels everywhere the repo243travels.**244245### Why `.claude/` lives in the theme repo (not in `~/.config/` or on246Drive)247248| Concern | Where it lives | Why |249|---|---|---|250| Connection details (host, port, SSH key path, Git remote URL) | `~/.config/norml-wp-developer/projects/{slug}.json` | Per-machine, private. Doesn't travel with the code. |251| Project knowledge (architecture, conventions, decisions, changelog) | `{theme_root}/.claude/` | Lives with the code, travels in git, available to anyone who clones the repo. |252| Secrets (SSH passphrase, GitHub PAT) | macOS Keychain / Windows Credential Manager / ssh-agent | OS-managed. Claude never sees the value. |253254This split is non-negotiable. **Never write a secret into255`{theme_root}/.claude/` — those files are committed to git.** Never write256deploy state or build artifacts into `~/.config/` either — they're257per-machine config, not knowledge.258259## Write-back rules — how the skill compounds knowledge per-project260261The point of `.claude/` is that **every session leaves it richer**. Three262write-back triggers:263264### `daily.md` — close-of-session changelog (always)265266Append an entry to `{theme_root}/.claude/changelog/daily.md` before267ending any session that:268269- Wrote theme code (component, block, template, function)270- Ran a deploy to staging or production271- Performed a direct-on-server edit272- Pulled production DB / uploads to local273- Made a non-trivial decision the next session would benefit from274 knowing275276Tags:277278- `[CODE]` — theme code change279- `[BUILD]` — Vite / Composer / NPM build ran280- `[DEPLOY-STAGING]` — push or deploy to staging281- `[DEPLOY-PROD]` — promote to prod (gated by backup acknowledgement)282- `[DIRECT-PROD]` — edit made directly on the production server (high283 risk, flag the un-mirrored-to-git status)284- `[PULL-DB]` — production DB pulled to local285- `[PULL-UPLOADS]` — production uploads pulled to local286- `[DECISION]` — architectural choice worth recording287- `[LEARNED]` — non-obvious fact about this project288289The daily file compresses to `weekly.md` weekly and to `changelog.md`290when the calendar quarter rolls over — see291`{theme_root}/.claude/changelog/README.md` for the protocol the init292flow scaffolds.293294### `.claude/CLAUDE.md` — project-level decisions295296When the user makes a project-level decision ("from now on this site297uses BEM for component class names," "we always set `show_in_rest:298true` on ACF field groups"), update the relevant section of299`CLAUDE.md`. This file is the durable answer to "how do we work on300this project."301302### `.claude/capabilities.md` + architecture docs — rescan only303304The visible capability contract, architecture index, and 5-file snapshot are305generated by `scripts/scrape-architecture.sh` (or `.ps1`) from local theme files,306Git/GitHub state, and read-only WP-CLI commands over SSH. They are overwritten on307rescan. Anything that should survive a rescan goes in `CLAUDE.md` or `daily.md`,308never hand-edited into generated files.309310## Safety classification — every operation buckets311312Three buckets:313314- **Safe** — read-only or low-risk single-item operations. Run315 immediately. Examples: `git status`, `git log`, `wp post list` on316 local, reading any file under the theme repo, listing the active317 plugin set.318319- **Confirm** — anything that writes to the local repo, to staging, or320 changes git state. Show the exact command, show the diff if relevant,321 ask for "yes" before running. Examples: `git commit`, `git push`,322 `git rebase`, `rsync` to staging, `wp plugin install` on local,323 database imports.324325- **Confirm + backup** — anything that writes to the production server.326 Show the exact command, **show the backup-acknowledgement prompt**,327 refuse without an explicit "I have a backup from {date}" reply.328 Examples: `rsync` to production, `wp db import` on production,329 `wp search-replace` on production, deleting plugin/theme files on330 production, direct file edits over SSH on production.331332The backup-acknowledgement prompt is mandatory for every production333write. There is no "skip the prompt" flag. If the project's334`.claude/ci-cd.md` declares the host has automatic backups (and we335trust the host), the prompt may be answered with "yes, host backups336verified" — but only if `ci-cd.md` says so, and only after the user337explicitly types that phrase.338339## Output style340341- Default to terse. The user wants the result.342- When you ran a command, show the command first (one line, monospaced).343- For `Confirm + backup` operations, the backup prompt is mandatory and344 shown verbatim. Don't paraphrase it.345- For diffs, prefer `git diff --stat` for summary + the full diff on346 request rather than dumping 500 lines unprompted.347348## Error handling349350- **SSH refused / timeout** → don't retry. Suggest the user run351 `scripts/test-ssh.sh` and check their `~/.ssh/config` alias.352- **`wp: command not found` on the remote** → WP-CLI not installed on353 the server. Stop, tell the user, suggest contacting their host.354- **`Composer detected ... platform_check.php`** → server PHP < theme's355 Composer floor. Stop, point at the `composer.json` `require.php`356 line, tell the user to either bump the server PHP or lower the357 theme's floor.358- **Git conflicts** → don't auto-resolve. Show the conflicting files,359 let the user pick the side. Conventional Commit rules in360 `development-guides/git-workflow.md`.361- **Build failures** → show the full Vite / Composer / NPM error, stop,362 do not deploy with a failing build.363- **Deploy failures mid-flight** → stop immediately. Tell the user the364 exact step that failed. Do not auto-retry — partial deploys are the365 most common cause of broken production.366367In all cases, **fail loudly and stop**. No improvised destructive368recovery.369370## Knowledge baseline — what the skill reads371372| File | When to read |373|---|---|374| `development-guides/dev-conventions.md` | At the start of any session that touches theme code. The **router** — routes to the right `conventions/` files by project mode, plus the global rules (Conventional Commits, don't-commit artifacts/secrets, ACF JSON sync caveat). |375| `development-guides/conventions/sage-stack.md` | Sage / new projects, before building. The Sage + Acorn + Blade + Tailwind v4 + Vite + Alpine + ACF Pro foundation. |376| `development-guides/conventions/component-system.md` | Before building a section / component / block in a Sage project. Anatomy + core component catalog + the Alpine pattern + layout. |377| `development-guides/conventions/css-architecture.md` | Before writing ANY CSS, **either mode**. The 3-layer model + the forbidden per-page-stylesheet rule. |378| `development-guides/conventions/acf-blocks.md` | Before registering an ACF block or its preview, **either mode**. Registration + previews + ACF JSON sync. |379| `development-guides/conventions/inherited-projects.md` | FIRST, whenever you open a non-Sage / inherited theme. Respect-existing decision flow + framework-agnostic principles. |380| `development-guides/git-workflow.md` | Before any `git commit`, `git push`, branch creation, or PR. GitHub Flow + Conventional Commits. |381| `development-guides/ci-cd/patterns.md` | Before any deploy or any CI/CD configuration task. The three supported patterns and the per-project `ci-cd.md` contract. |382| `development-guides/ci-cd/database-strategies.md` | When content / the database moves (or must not move) between environments. |383| `development-guides/ci-cd/backup-strategies.md` | Before any production write — backup provider, verification, restore runbook, acknowledgement tier. |384| `development-guides/qa-gates.md` | Before merging, before deploying, and right after deploying. The pre-merge / pre-deploy / post-deploy checkpoints. |385| `development-guides/safety-rules.md` | At session start. The full Safe / Confirm / Confirm+backup classification with examples. |386| `development-guides/wp-local-setup.md` | During onboarding, or if the local environment is unclear. WP Local default, DDEV / Lando / Valet / Local Lightning as alternates. |387| `{theme_root}/.claude/CLAUDE.md` | At session start. Project mode (sage / inherited), live URLs, deploy hints. |388| `{theme_root}/.claude/capabilities.md` | At session start and before any operation. Verified GitHub, SSH, WP-CLI, local, staging, and production boundary. |389| `{theme_root}/.claude/architecture.md` | At session start. Latest architecture snapshot summary and read order. |390| `{theme_root}/.claude/ci-cd.md` | Before any deploy. Per-project pattern, deploy commands, pre/post hooks. |391| `{theme_root}/.claude/changelog/daily.md` | At session start. The last ~20 entries — what the last sessions touched. |392393## Hard rules3943951. **Never deploy without an acknowledged backup.** The backup-396 acknowledgement prompt is mandatory for every production write.3972. **Never write secrets into committed files.** SSH keys, GitHub398 PATs, database passwords belong in the OS secret store or399 `ssh-agent` — never in `.claude/`, never in `.env` checked into400 git, never in commit messages.4013. **Never silently overwrite production.** Every prod write shows the402 exact command and waits for explicit "yes."4034. **Never introduce a new framework on an inherited project** without404 explicit, in-session approval. Match the existing architecture.4055. **Always log production writes** as `[DEPLOY-PROD]` or406 `[DIRECT-PROD]` in `daily.md` before closing the response.4076. **Stop on any unexpected error.** No improvised recovery.4087. **`.claude/` is committed to git.** Never write secrets to it.409 `~/.config/norml-wp-developer/projects/*.json` is per-machine and410 never committed.4118. **Local-first is the default.** Direct-on-server is permitted but412 explicit per-operation. Never default to it.413414## Related skills415416**Companion (install both for a full WordPress workflow):**417418- `norml-wp-manager` — REST-API-only content management on a deployed419 site. Use it for posts, pages, ACF values, media. This skill420 (`norml-wp-developer`) is for theme code; `norml-wp-manager` is for421 content. They share no state.422423## What lives where (recap)424425| What | Where | Why |426|---|---|---|427| The skill itself | Runtime-specific skills directory | Claude Code, Codex, or Gemini CLI discovers the stable `norml-wp-developer` slug. |428| **Per-project connection config** | **`~/.config/norml-wp-developer/projects/{slug}.json`** | Per-machine. Host, SSH alias, theme repo path, remote URL, deploy pattern. **No secrets.** |429| **Per-project knowledge** | **`{theme_root}/.claude/`** | Lives in the GitHub repo. Travels with the code. CLAUDE.md, capabilities.md, architecture.md, ci-cd.md, changelog, architecture docs. |430| SSH key | `~/.ssh/{key}` | Owned by the user; ssh-agent holds the passphrase. |431| SSH passphrase | macOS Keychain (via `ssh-add --apple-use-keychain`) / Windows ssh-agent (DPAPI-backed) | OS-managed. Claude never reads it. |432433The split is intentional: `~/.config/` is per-machine connection state;434`{theme_root}/.claude/` is portable per-project knowledge; the OS435secret store is for secrets.