@hostinger/mcp 3.2.2 → 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/gemini-extension.json +1 -1
  3. package/package.json +1 -1
  4. package/server.json +2 -2
  5. package/skills/headless/SKILL.md +245 -36
  6. package/skills/headless/connect/SKILL.md +98 -0
  7. package/skills/headless/{entry → connect}/bootstrap.mjs +8 -3
  8. package/skills/headless/connect/tools/antigravity.md +54 -0
  9. package/skills/headless/connect/tools/claude-code.md +46 -0
  10. package/skills/headless/connect/tools/codex.md +48 -0
  11. package/skills/headless/connect/tools/cursor.md +109 -0
  12. package/skills/headless/connect/tools/devin.md +50 -0
  13. package/skills/headless/connect/tools/vscode.md +57 -0
  14. package/skills/headless/report.schema.json +149 -0
  15. package/skills/headless/run-log.mjs +662 -0
  16. package/skills/headless/steps/01-check-state/SKILL.md +209 -0
  17. package/skills/headless/steps/02-refine/SKILL.md +273 -0
  18. package/skills/headless/steps/03-provision/SKILL.md +117 -0
  19. package/skills/headless/steps/03-provision/ecommerce/SKILL.md +142 -0
  20. package/skills/headless/steps/03-provision/webapp/SKILL.md +154 -0
  21. package/skills/headless/steps/03-provision/wordpress/SKILL.md +249 -0
  22. package/skills/headless/steps/04-content-model/SKILL.md +228 -0
  23. package/skills/headless/steps/04-content-model/ecommerce/SKILL.md +75 -0
  24. package/skills/headless/steps/04-content-model/wordpress/SKILL.md +223 -0
  25. package/skills/headless/steps/04-content-model/wordpress/woocommerce.md +153 -0
  26. package/skills/headless/steps/05-design/SKILL.md +464 -0
  27. package/skills/headless/steps/05-design/logo-kit.mjs +201 -0
  28. package/skills/headless/steps/06-frontend/SKILL.md +160 -0
  29. package/skills/headless/steps/07-validate/SKILL.md +56 -0
  30. package/skills/headless/steps/08-deploy/SKILL.md +179 -0
  31. package/skills/headless/steps/09-done/SKILL.md +157 -0
  32. package/src/core/skills.js +171 -24
  33. package/src/core/skills.ts +171 -24
  34. package/src/servers/agency-hosting.js +1 -1
  35. package/src/servers/agency-hosting.ts +1 -1
  36. package/src/servers/agent-readiness.js +1 -1
  37. package/src/servers/agent-readiness.ts +1 -1
  38. package/src/servers/all.js +1 -1
  39. package/src/servers/all.ts +1 -1
  40. package/src/servers/billing.js +1 -1
  41. package/src/servers/billing.ts +1 -1
  42. package/src/servers/dns.js +1 -1
  43. package/src/servers/dns.ts +1 -1
  44. package/src/servers/domains.js +1 -1
  45. package/src/servers/domains.ts +1 -1
  46. package/src/servers/ecommerce.js +1 -1
  47. package/src/servers/ecommerce.ts +1 -1
  48. package/src/servers/horizons.js +1 -1
  49. package/src/servers/horizons.ts +1 -1
  50. package/src/servers/hosting.js +1 -1
  51. package/src/servers/hosting.ts +1 -1
  52. package/src/servers/mail.js +1 -1
  53. package/src/servers/mail.ts +1 -1
  54. package/src/servers/reach.js +1 -1
  55. package/src/servers/reach.ts +1 -1
  56. package/src/servers/vps.js +1 -1
  57. package/src/servers/vps.ts +1 -1
  58. package/src/servers/wordpress.js +1 -1
  59. package/src/servers/wordpress.ts +1 -1
  60. package/skills/headless/entry/skill.md +0 -79
  61. package/skills/headless/references/DATABASE.md +0 -49
  62. package/skills/headless/references/DEPLOYMENT.md +0 -34
  63. package/skills/headless/references/SETUP.md +0 -35
  64. package/skills/headless/references/STORE.md +0 -52
  65. package/skills/headless/references/WORDPRESS.md +0 -51
@@ -0,0 +1,209 @@
1
+ ---
2
+ name: headless-step-check-state
3
+ description: "First build step of the Hostinger Headless flow, run right after connect. Works out where a given domain's build stands — is a run already in progress, does the site already exist, how far did it get — by reconciling the global workspace state under ~/.hostinger/<domain>/ with what the Hostinger connector reports, then guides the user to continue, switch or buy a domain, or start over. Owns all resume/position logic for the flow."
4
+ ---
5
+
6
+ # headless-step-check-state
7
+
8
+ The first build step of the Hostinger Headless flow (orchestrated by `hostinger.com/headless/skill.md`),
9
+ run right after connect. Connect has already connected the Hostinger connector and confirmed the
10
+ account can build. Your job here is to
11
+ **figure out where this domain stands and agree the route with the user** before any new work begins.
12
+ This step owns all resume/position logic — no other stage second-guesses it.
13
+
14
+ Nothing in this step creates, provisions, deploys, or deletes anything. It reads and guides.
15
+
16
+ ---
17
+
18
+ ## Where state lives
19
+
20
+ Everything for a domain lives under the global site workspace **`~/.hostinger/<domain>/`** — one
21
+ directory per domain, under the user's home (`~` = `$HOME`), **not** the current working directory.
22
+ The directory name **is** the domain, so `state.json` inside does not store it. Because it's global,
23
+ `~/.hostinger/` holds every site the user has built and each one is discoverable and resumable from
24
+ any directory — no collisions.
25
+
26
+ `state.json` shape (`stage` is the *next* stage to run; `provision` is the background task's status,
27
+ present only once provision has fired):
28
+
29
+ ```json
30
+ { "tool": "claude-code", "stage": "content_model",
31
+ "provision": { "status": "in_progress", "domain": "<domain>", "started_at": "…" },
32
+ "updated_at": "…" }
33
+ ```
34
+
35
+ `provision.status` is `in_progress` or `completed` — but it is a **hint**: always re-verify it against
36
+ `hosting_websites_list-setups` (Step 1) before trusting it to gate an instance-barrier step.
37
+
38
+ ---
39
+
40
+ ## Step 0 — Start the run log
41
+
42
+ Before anything else, start a run and the stage (see *Run log and build report* in the top-level
43
+ `SKILL.md`):
44
+
45
+ ```bash
46
+ node <skill>/run-log.mjs <domain> run-start --tool <tool> --model <model> --skill <skill version>
47
+ node <skill>/run-log.mjs <domain> stage-start check_state
48
+ ```
49
+
50
+ If an earlier run on this domain never wrote its report, `run-start` closes it as `abandoned` first.
51
+
52
+ Then send any build reports that haven't reached Hostinger yet (that abandoned run, or a send that
53
+ failed last time):
54
+
55
+ ```bash
56
+ node <skill>/run-log.mjs <domain> unsent
57
+ ```
58
+
59
+ Each line is `<run> <path>`. For each, send the file through `hosting_headless_submit-build-report`
60
+ and record the result, as described in *Run log and build report* in the top-level `SKILL.md`. One
61
+ try each. Don't ask first; if any went out, say so in one line (e.g. "Sent 1 earlier build report to
62
+ Hostinger."). Don't let a failure hold up this step.
63
+ Check-state runs once per session. A follow-up after the final report, in the same session, doesn't
64
+ come back here: it calls `run-resume` (see *Run log and build report* in the top-level `SKILL.md`).
65
+
66
+ ## Step 1 — Is a build actively running right now? (check this before anything else)
67
+
68
+ Keep two things separate, and **never guess from a timestamp.**
69
+
70
+ - **A platform build actively in progress** — the only *reliable* "running now" signal. Check
71
+ `hosting_websites_list-setups { "domain": "<domain>" }` and exact-match the domain row:
72
+ - `status: running` → provisioning is underway **right now** (a background provision from an earlier
73
+ turn). Don't start a second one — reconcile `state.json`'s `provision` to `in_progress`, and
74
+ either resume prepare work while it finishes or poll it to `completed` at the barrier.
75
+ - `status: failed` → not running; route to provision to self-heal (Step 3).
76
+ - `completed` → provision is done; set `provision.status` to `completed`. Instance-barrier steps
77
+ (content push, frontend data, deploy) are now unblocked.
78
+ - no row → not provisioned yet; carry on.
79
+
80
+ This check **is** the source of truth for `provision.status`: a stored `in_progress`/`completed` in
81
+ `state.json` is only a hint until this reconciles it.
82
+
83
+ - **A `.lock`** — `~/.hostinger/<domain>/.lock`. It only tells you *a previous run
84
+ touched this domain*. **Do not judge it by age** — a 2-minute-old lock and a 3-year-old lock get the
85
+ same treatment, and a lock on its own is **not** a reason to interrupt the user. Carry it into Step 5:
86
+ if there's nothing to resume (new build), silently take it over; only if there's real state to resume
87
+ do you also ask *is another Claude window building this domain right now?* (yes → stop; no → take
88
+ over).
89
+
90
+ Once you're actively working this domain, **acquire/refresh the lock** (write the current timestamp),
91
+ and **release it on a clean stop** (Step 6). The lock marks an active session, nothing more.
92
+
93
+ ---
94
+
95
+ ## Step 2 — Read the workspace directory
96
+
97
+ Look at `~/.hostinger/<domain>/`:
98
+
99
+ - **Absent** → no history for this domain in the workspace.
100
+ - **Present** → read `state.json` (its `stage`) and whatever artifacts exist (`brief.md`,
101
+ `site.json`, …). Treat these as a hint, not the truth.
102
+
103
+ ---
104
+
105
+ ## Step 3 — Verify against reality (reality wins)
106
+
107
+ Query the Hostinger connector — the local files are never trusted on their own:
108
+
109
+ - **Does the site exist?** `hosting_websites_list { "domain": "<domain>" }`. ⚠️ This filter is a
110
+ **case-insensitive substring match**, not exact — so `test.com` would also return
111
+ `shop.test.com`. **Compare each returned row's `domain` to your target for an *exact* match**
112
+ (case-insensitive) and ignore the rest. No exact row ⇒ the domain is free. An exact row ⇒ the site
113
+ exists; note its `website_type` (`headless`, `wordpress`, `nodejs`, …) and `username`.
114
+ - **How far did it get?** If the site exists, check its setup via
115
+ `hosting_websites_list-setups { "domain": "<domain>" }` (exact-match the row the same way):
116
+ - `status: completed` → provisioned; then, depending on backend, check whether a build has succeeded.
117
+ - `status: running` → still provisioning (see Step 1).
118
+ - `status: failed` → provisioning stopped before finishing → route to **provision** to self-heal.
119
+ - **Is it an empty headless shell from onboarding?** A `headless` site whose setup is `completed` is
120
+ **not necessarily finished** — onboarding now creates the website *before* the build runs, as an
121
+ **empty headless shell** (`hosting_websites_start-setup { type: "headless_empty" }`): `website_type`
122
+ is `headless` but **no backend is installed** (no WordPress at `/cms`, no store). Tell a shell from a
123
+ real backend the same way provision does: within 24 h the setup `type` is `headless_empty`; otherwise
124
+ `wordpress_installations_list { username, domain, ownership: "all" }` returns **no** `/cms` row and
125
+ there is no `site.json` recording a backend. An empty shell means **provision has not chosen or
126
+ installed a backend yet** — this is a **new build** that happens to already own its website, not a
127
+ finished or resumable one. Route it to **refine** (choose the backend), then **provision** adopts the
128
+ shell and swaps it to that backend (see the provision router's *Onboarding handoff*). Never create a
129
+ second site, and never skip provision for it.
130
+
131
+ Reconcile with the local state. **When they disagree, reality wins** and the local `stage` is
132
+ corrected.
133
+
134
+ ---
135
+
136
+ ## Step 4 — Determine the position
137
+
138
+ Connect always writes `state.json` (with `stage: check_state`) before this step runs, so local
139
+ state is never truly empty. **"Local state: none" here means only connect artifacts exist** —
140
+ `connect.json` + a `state.json` still pointing at `check_state`/`refine`, and **no build artifacts
141
+ yet** (`brief.md`, `site.json`, …).
142
+
143
+ | Local state | Reality (domain) | Position |
144
+ |---|---|---|
145
+ | none (connect only) | free | **new build** — start from refine |
146
+ | none (connect only) | empty headless shell (onboarding) | **new build on an existing shell** — start from refine; provision adopts the shell and swaps it to the chosen backend. Never create a second site, never skip provision |
147
+ | none (connect only) | site exists with a real backend | **adopt / resume** — never create a second site; route to the first unfinished stage |
148
+ | build artifacts present, incomplete | matches | **resume** at `state.json`'s `stage` |
149
+ | build artifacts present | disagrees | **reality wins** — recompute the stage from what actually exists |
150
+ | build artifacts present, all done | live site exists | **finished** — this is now an *iterate* request, not a build |
151
+
152
+ ---
153
+
154
+ ## Step 5 — Guide the user
155
+
156
+ The question to ask depends on whether there is actually **something to resume** — i.e. **build
157
+ artifacts** (`brief.md`, `site.json`, …) or a **live site** for this domain. A stray `.lock` or
158
+ connect-only files are *not* something to resume.
159
+
160
+ - **New build** (no build artifacts and either the domain is free **or** it holds only an empty
161
+ headless shell from onboarding) → just proceed to refine. **Don't ask resume vs start over** —
162
+ there's nothing to resume; both would land in the same place. An empty headless shell is not
163
+ "something to resume": it has no backend and no content yet, so it's a fresh build that already owns
164
+ its website — provision will adopt and swap it. Mention it in one line ("Using the headless site
165
+ onboarding already created for this domain."). If a leftover `.lock` is lying around, silently take
166
+ it over and continue (optionally mention it in one line).
167
+ - **Something to resume** (build artifacts exist, or a site exists for the domain **with a real backend
168
+ installed** — WordPress at `/cms`, a store, or a deployed app) → tell the user plainly what's there
169
+ and **ask them to choose**, regardless of how old it is (don't guess from timestamps):
170
+
171
+ - **Resume** — pick up at the computed stage. (If a `.lock` is present in this case, also confirm no
172
+ other window is actively building this domain right now.)
173
+ - **Start over / redo a step** — only safe **before anything is provisioned**. If the site is already
174
+ provisioned or live, you **cannot** re-create it: that is forward-only *iterate* (change content or
175
+ design and redeploy), not a fresh build. Never re-provision or overwrite a live site; if the user
176
+ insists on a clean slate for a live domain, explain the limitation and point them at hPanel.
177
+ - **Switch domain** — they want a different domain. A new domain is a **new workspace**
178
+ (`~/.hostinger/<other-domain>/`, with its own `src/`). Hand off to start that domain's run.
179
+ - **Buy a domain** — they want a custom domain instead of the temporary one. Route to the domain
180
+ purchase / `connect-domain` flow, then continue with the chosen domain.
181
+
182
+ When the intent is ambiguous, **ask** — don't guess.
183
+
184
+ ---
185
+
186
+ ## Step 6 — Record and route
187
+
188
+ Write `~/.hostinger/<domain>/state.json` with the agreed next `stage` and a fresh timestamp. If the
189
+ route isn't a new build, record it with `run-log.mjs <domain> run-update --kind resume` (or
190
+ `redesign` / `iterate`), then end the stage with `stage-end check_state ok --note "<the route>"`.
191
+ Then:
192
+
193
+ - **Handing straight to the next stage in this same session?** Keep the `.lock` (you are still
194
+ actively running) and continue.
195
+ - **Stopping and returning control to the user?** (e.g. the next stage isn't built yet, or you are
196
+ waiting on them.) **Delete the `.lock`** — the session is no longer active, and a leftover lock just
197
+ forces an unnecessary "is another window running?" question on the next run. Always release the lock
198
+ on a clean stop; it exists only to mark an actively-running session. A stop is still the end of a
199
+ run: give the final report and save the build report (`09-done`).
200
+
201
+ ---
202
+
203
+ ## Invariants
204
+
205
+ - **One directory per domain.** The domain is the key; state files never repeat it.
206
+ - **Never create a second site** on a domain that already has one.
207
+ - **Never re-provision or overwrite a live site.** Recovery is forward-only.
208
+ - **Reality beats local state**, always.
209
+ - **When ambiguous, ask.**
@@ -0,0 +1,273 @@
1
+ ---
2
+ name: headless-step-refine
3
+ description: "Step 2 (refine) of the Hostinger Headless flow. Turns the user's seed — often just a domain — into a brief through conversation: asks what they want to build (purpose, audience, tone, pages, products, must-haves; images, local files, links all welcome), then *infers* the backend that fits (WordPress, Ecommerce, WordPress + Ecommerce, WordPress + WooCommerce for a one-site content+store, or Webapp for a custom app/SPA) — it never asks the user to pick a backend or a technology; the user confirms the plan in plain language, then it writes brief.md. Hostinger Ecommerce stays the default for selling; WooCommerce is chosen only when the user explicitly asks for it or wants content and a store on one WordPress site."
4
+ ---
5
+
6
+ # headless-step-refine
7
+
8
+ Find out what the user wants to build, guess which backend fits, and write it down. This is a
9
+ **conversation, not a form**: the pasted prompt names a domain and nothing else, so everything about
10
+ the site comes from talking to the user.
11
+
12
+ **Keep it short.** The only thing you must know is *what they are building* — enough to guess the
13
+ backend. Every other question is skippable: the more the user gives, the better the site, but never
14
+ hold the build hostage to refinement. Fill gaps with sensible defaults and say so in the brief.
15
+
16
+ > **Never ask the user to choose a backend or a technology.** Don't ask "WordPress or Ecommerce?",
17
+ > don't present WordPress/Ecommerce/WooCommerce/Webapp as options, and don't surface the backend in a
18
+ > multiple-choice UI. Open with **"What do you want to build?"** and infer the backend yourself in
19
+ > Step 4 from what they describe (and whether they sell). The backend is a technical decision the flow
20
+ > makes *for* the user — they confirm the **plan** (what the site is and does), not the plumbing. The
21
+ > only exception is when the user *volunteers* a backend ("build it on WordPress", "use WooCommerce"):
22
+ > then honour their choice and note it in the brief.
23
+
24
+ **In:** the domain (the workspace directory name), plus anything the user already shared.
25
+ **Out:** `~/.hostinger/<domain>/brief.md`.
26
+
27
+ Nothing in this step touches Hostinger. It only asks, decides and writes.
28
+
29
+ ---
30
+
31
+ ## Step 1 — Read the workspace, then the resume check
32
+
33
+ Read everything already in `~/.hostinger/<domain>/` (`state.json`, `connect.json`, any notes, images
34
+ or files the user dropped there) — it all counts as input.
35
+
36
+ If `brief.md` already exists for this domain, **don't overwrite it**. Show the user a three-line
37
+ summary (what the site is, its pages, the suggested backend) and ask: *keep it, or change something?*
38
+ Keep → go to Step 6. Change → edit only what they asked for, then re-confirm (Step 5).
39
+
40
+ If the site is already provisioned (`site.json` exists), the backend is **fixed** — never change the
41
+ Suggested backend on a provisioned site. Explain that switching backends means a new domain.
42
+
43
+ ## Step 2 — Gather what you already have
44
+
45
+ Before asking anything, collect what the user has already given you, so you don't ask for it again:
46
+
47
+ - **Inspect the directory the command was run in** — this is the biggest signal for the build mode
48
+ (Step 3). Look for an existing **frontend / webapp / commerce project**: a `package.json`, a
49
+ framework config (`next.config.*`, `astro.config.*`, `vite.config.*`, `svelte.config.*`, `nuxt.*`),
50
+ a `src/` or `app/` tree, `index.html`, a storefront/cart, etc. A real project here usually means the
51
+ user **already has their own frontend** and mainly needs a Hostinger backend to wire it to — lean
52
+ toward "bring your own frontend" in Step 3. If the folder has nothing site-like, assume they don't
53
+ and lean toward "agent builds it".
54
+ - Anything in the pasted prompt beyond the domain (a sentence, a link, a screenshot).
55
+ - Files in the current project that look like site material (copy, logos, product lists, images).
56
+ - What the agent already knows about the user from local memory or this conversation (a prior build,
57
+ stack preferences, a frontend they always use).
58
+ - The domain name itself — a hint only (`coral-pottery.com` suggests pottery), never a conclusion.
59
+
60
+ ## Step 3 — Ask
61
+
62
+ If Step 2 already answers *what are you building* and *will they sell*, skip the Round 1–3 questions
63
+ below, but still ask **Build mode** before moving on.
64
+
65
+ Otherwise open with one line and **wait for the user's answer**: *"Tell me what you want to build — a
66
+ sentence is enough. Links, screenshots or files help too. Skip anything you don't want to answer."*
67
+
68
+ > **"What do you want to build?" is an OPEN question — ask it in plain prose and wait.** Never turn it
69
+ > into a multiple-choice list of pre-baked site ideas ("Coffee shop / Travel blog / Portfolio …"):
70
+ > that puts words in the user's mouth and defeats the point of asking. Let them describe it in their
71
+ > own words. The structured question UI is only for genuinely *choice-shaped* follow-ups (selling
72
+ > yes/no, which pages, tone adjectives, the build mode) — not for the opening question, and never for
73
+ > the backend.
74
+
75
+ Ask in **short rounds of 2–3 questions**, and adapt each round to the previous answers. If your tool
76
+ has a structured question UI (multiple choice with an "other" field), use it for the choice-shaped
77
+ follow-up questions (pages, selling yes/no, tone) — **never for the opening "what do you want to
78
+ build?" and never for the backend** (that's your decision, not theirs). **At most 3 rounds**, and stop early as soon as you can guess the backend and the user
79
+ seems done — "just build it", "you decide", or a skipped question means *use defaults*, not *ask
80
+ again*.
81
+
82
+ **Round 1 — what it is (the only required round):**
83
+
84
+ 1. **What are you building?** The business or project, and what the site is for.
85
+ 2. **Will you sell anything on it?** Physical products, digital products, services with checkout —
86
+ or nothing. *This decides the backend.* Skip it only when the answer is already unmistakable
87
+ ("an online shop for my candles", "my personal blog"); when in doubt, ask.
88
+ 3. **Who is it for?** The audience, and how they'll find the site. *(skippable)*
89
+
90
+ **Round 2 — what goes on it (optional, adapt to Round 1):**
91
+
92
+ - **Content they'll publish over time** — blog posts, articles, news, recipes, portfolio pieces,
93
+ case studies? How often? Or is it a handful of pages that rarely change?
94
+ - **Pages** — propose a page list from what you know and ask them to add or remove.
95
+ - If they sell: **what and how many** — a rough product count, categories, whether products have
96
+ variants (size, colour), and the shipping regions.
97
+
98
+ **Round 3 — how it should feel (optional, skip what you already know):**
99
+
100
+ This is the round that captures **all design input** — the design step reads it from `brief.md` to derive
101
+ the design directions, so it is **not** asked again later; gather it here:
102
+
103
+ - **Reference & look** — a **site they like (URL)** and what to take from it, plus a few adjectives for
104
+ the vibe. Screenshots welcome.
105
+ - **Colours & brand** — brand/accent colours, logo, fonts, existing copy, photos. Note where they live.
106
+ - **Must-haves and no-gos** — contact form, newsletter, bookings, languages, things to avoid.
107
+
108
+ If the user asks for something outside the scope (user accounts, member areas, bookings with a
109
+ calendar backend, user-generated content), say plainly that the headless flow doesn't support it yet
110
+ and record it under **Out of scope** — don't promise it.
111
+
112
+ ### Build mode — ask once (this one *is* a user choice)
113
+
114
+ The backend is your call, but **how the frontend gets built is the user's** — because most of the time
115
+ the user already has their own frontend and just needs a Hostinger backend to wire it to. After the
116
+ folder + memory inspection (Step 2), ask **one** question (a structured choice is ideal here), seeding
117
+ the default from what you found:
118
+
119
+ - **Bring your own frontend** *(default when Step 2 found a real project in the folder)* — "I already
120
+ have a frontend / I'll drive the design and we vibe-code it together." The agent **uses the user's
121
+ existing project in the current folder as the source**, collaborates on design/code at the user's
122
+ direction, and wires it to the provisioned backend. There is **no agent-generated design** — the
123
+ design step defers to the user (see the Build mode box at the top of the design step), and the frontend step builds on their project
124
+ rather than scaffolding a new one.
125
+ - **Agent designs and builds it** *(default when the folder has nothing site-like)* — "Give me ideas
126
+ — you design and code it." Today's flow: the design step proposes directions and the frontend step
127
+ scaffolds and implements them.
128
+
129
+ Record the answer as the brief's **Build mode**. This is the one frontend/technology question you *do*
130
+ put to the user; everything else about the stack (framework, SSR/SSG) is still inferred. The deliverable
131
+ is the same either way — a working site on the backend; only *who drives the frontend* changes.
132
+
133
+ ## Step 4 — Decide the backend (your call, from the brief — not a question)
134
+
135
+ From what the user described, **you** pick the backend that fits — this is an internal decision, never
136
+ a question put back to the user. Pick the backend that fits what the user told you:
137
+
138
+ | Backend | Choose when | What it gives the owner |
139
+ |---|---|---|
140
+ | **WordPress** | No selling. The owner publishes and edits content: pages, blog, articles, portfolio. | Headless WordPress at `/cms` — write and edit content in wp-admin. |
141
+ | **Ecommerce** | Selling is the point, and the rest is a few static pages (About, Contact, FAQ, policies). No ongoing blog. | Hostinger Ecommerce store — products, collections, checkout, payments, shipping, orders. |
142
+ | **WordPress + Ecommerce** | Selling **and** regular editorial content (a blog, guides, lookbooks, recipes) the owner keeps adding to, run as **two** backends (WordPress site + separate Hostinger Ecommerce store). | Both: WordPress for content, the Ecommerce store for products and checkout. |
143
+ | **WordPress + WooCommerce** | **Only** when the user explicitly names WooCommerce, or explicitly wants content **and** a store on **one** WordPress site (one admin, one domain). The one-site alternative to WordPress + Ecommerce. | A single headless WordPress at `/cms` with the WooCommerce plugin — products, cart, coupons and checkout (Cash on Delivery) over the WooCommerce Store API, plus WP posts/pages on the same site. |
144
+ | **Webapp** | A custom **app, SPA or web application** that brings its own code and data — a dashboard, tool, calculator, booking app, a project the user is deploying — **not** a content site or a store. No CMS and no store engine. | A plain Node.js app host (an empty website, no `/cms`), with a MySQL database when the app needs one. The app owns all its routes and data. |
145
+
146
+ Rules of thumb:
147
+
148
+ - **Is it an app, or a site?** A custom application the user builds/brings (its own logic, its own data,
149
+ maybe a database) → **Webapp**. A content site or a shop → one of the three above. When the user says
150
+ "my app / SPA / dashboard / tool", or hands you an existing app project to deploy, that's **Webapp**.
151
+ - **Selling decides first (for sites).** No selling → WordPress. Selling → Ecommerce or
152
+ WordPress + Ecommerce.
153
+ - **Then the content.** Selling plus only a few fixed pages → Ecommerce. Selling plus content the
154
+ owner will keep publishing → WordPress + Ecommerce.
155
+ - **Hostinger Ecommerce is the default for selling — WooCommerce is never the default and is never
156
+ recommended on its own.** Choose **WordPress + WooCommerce** only when the user explicitly names
157
+ WooCommerce, or explicitly wants content **and** a store on one WordPress site (one admin, one
158
+ domain — the one-site alternative to WordPress + Ecommerce). For every other selling case, keep
159
+ Hostinger Ecommerce. If the user wants both content and a store but hasn't said "one site" or
160
+ "WooCommerce", offer it as an option — don't switch to it silently.
161
+ - **Don't add WordPress "just in case".** A second backend is a second admin to learn. Recommend the
162
+ combination only when the user described ongoing content.
163
+ - Selling a single service by enquiry (no checkout, no cart) is **not** commerce → WordPress with a
164
+ contact page.
165
+ - **Webapp never uses WordPress or a store.** If the user wants a custom app *and* a CMS/shop, that's two
166
+ different sites — build the app as a Webapp and tell them the content/commerce backend is a separate
167
+ domain.
168
+
169
+ **Then set rendering** (write it in the brief's **Rendering** section): **Ecommerce → SSR required**
170
+ (carts/search need per-request rendering — any SSR framework works; Next.js is the default, not a
171
+ requirement); **WordPress + WooCommerce → SSR required** (same reason — cart/checkout need per-request
172
+ rendering); **WordPress → SSG (Astro)** if the site is mostly static and the owner is fine rebuilding
173
+ to publish, otherwise **SSR**; **Webapp → whatever the app is** (SSR for a server app, SPA for a
174
+ client-only app) — it deploys as a Node.js app either way. When unsure, default to **Next.js SSR**.
175
+
176
+ ## Step 5 — Confirm the plan in one message
177
+
178
+ Send **one** message that confirms **what you'll build** — the plan, not the plumbing. Lead with the
179
+ site, not the backend:
180
+
181
+ - **The plan** — what it is, audience, pages, products (if any), tone. Mark anything you defaulted
182
+ (*"assumed: warm, minimal look"*) so the user sees what they skipped.
183
+ - **How it's built** — state the backend as a *consequence* in one plain line, focused on what it
184
+ means for them day to day ("I'll build this on WordPress, so you edit pages and posts in a normal
185
+ WordPress admin"), **not** as a choice you're asking them to make. Don't ask "is WordPress OK?" or
186
+ offer alternatives unless it was a genuine close call *and* the difference matters to the user.
187
+
188
+ End with *"Good to go, or anything to change?"* A yes (or silence-equivalent like "go") → write
189
+ `brief.md`. Changes → apply them and write it; don't loop back into questions. If the user
190
+ *volunteers* a different backend, use theirs and note it in the brief.
191
+
192
+ ## Step 6 — Write `brief.md` and hand off
193
+
194
+ Write `brief.md` from the template below. Fill every section from the conversation, defaulting what
195
+ the user skipped and tagging it `(assumed)`; leave out **Products** when nothing is sold. Use the
196
+ user's own words where you can. Then update `state.json`:
197
+ `"stage": "provision"`, fresh `updated_at`.
198
+
199
+ The **Suggested backend** section is the contract with `03-provision/SKILL.md`, which routes on it.
200
+ Its first line must be exactly one of `**WordPress**`, `**Ecommerce**`, `**WordPress + Ecommerce**`,
201
+ `**WordPress + WooCommerce**` or `**Webapp**`, followed by an em dash and the one-line reason.
202
+ `**WordPress + WooCommerce**` is the WordPress backend with the WooCommerce store turned on — provision
203
+ routes it to the `wordpress` subfolder with the store enabled (it is **not** a separate backend).
204
+
205
+ ## `brief.md` template
206
+
207
+ ```markdown
208
+ # Brief — <domain>
209
+
210
+ > Brief agreed with the user on <today>.
211
+
212
+ ## Purpose
213
+ <what the site is, who runs it, what it's for — 2–3 sentences>
214
+
215
+ ## Audience
216
+ <who visits, how they arrive, what device they mostly use>
217
+
218
+ ## Tone
219
+ <voice in a sentence or two>
220
+
221
+ ## Design direction
222
+ <look & feel in a few adjectives; **reference site(s)** the user named (URLs) and what to take from them
223
+ (layout, structure, mood); colours / brand palette; any screenshots. This is where ALL design questions
224
+ land — the frontend step reads this and does not re-ask. Write "Agent's choice: <short style>" when the
225
+ user didn't specify.>
226
+
227
+ ## Pages
228
+ - **<Page>** — <one-line purpose>
229
+ - …
230
+
231
+ ## Products
232
+ <only when selling: what is sold, rough count, categories, variants, shipping regions, payments>
233
+
234
+ ## Content
235
+ <what the owner will publish over time and how often — or "A few fixed pages; no ongoing content.">
236
+
237
+ ## Must-haves
238
+ - …
239
+
240
+ ## Out of scope
241
+ - …
242
+
243
+ ## Assets
244
+ <logo, colours, photos, copy the user provided and where they are; "None yet" if none>
245
+
246
+ ## Suggested backend
247
+ **<WordPress | Ecommerce | WordPress + Ecommerce | WordPress + WooCommerce | Webapp>** — <one-line reason>.
248
+ <"Confirmed by the user." or "User chose this over the recommended <X> because <reason>.">
249
+
250
+ ## Build mode
251
+ **<Bring your own frontend | Agent designs and builds>** — <one line>. <When "Bring your own frontend":
252
+ the path to the user's existing project in the current folder (the frontend source), and how they want
253
+ to drive design/code. When "Agent designs and builds": leave the design + frontend steps to run as
254
+ normal.> The design step and the frontend step both read this: **Bring your own frontend** → design
255
+ defers to the user and frontend builds on their project; **Agent designs and builds** → both run as normal.
256
+
257
+ ## Rendering
258
+ **<SSR | SSG>** — <reason>. Rules: **Ecommerce requires SSR** and **WordPress + WooCommerce requires
259
+ SSR** (carts/checkout need per-request rendering — any SSR framework works; Next.js is the default, not
260
+ a requirement); **WordPress may be SSG (Astro)** when the site is mostly static and rarely changes,
261
+ otherwise **SSR**. Default when unsure: **Next.js SSR**.
262
+ ```
263
+
264
+ ## Example — WordPress + Ecommerce
265
+
266
+ > A ceramicist sells around 30 handmade pieces and writes a monthly studio journal.
267
+
268
+ ```markdown
269
+ ## Suggested backend
270
+ **WordPress + Ecommerce** — sells ~30 products with checkout, and the owner publishes a monthly
271
+ studio journal they want to edit themselves.
272
+ Confirmed by the user.
273
+ ```
@@ -0,0 +1,117 @@
1
+ ---
2
+ name: headless-step-provision
3
+ description: "Step 3 (provision) of the Hostinger Headless flow. Chooses the backend from brief.md (wordpress | ecommerce | webapp), then routes to the matching subfolder to provision it; writes site.json. WordPress + WooCommerce routes to the wordpress subfolder with the WooCommerce store turned on — it is not a separate backend."
4
+ ---
5
+
6
+ # headless-step-provision
7
+
8
+ Router. The backend is decided in **refine** and recorded in `brief.md`; this step only routes to the
9
+ matching subfolder, which provisions it.
10
+
11
+ **In:** `brief.md`. **Out:** `site.json` (written by the subfolder).
12
+
13
+ **This stage runs in the background.** Provisioning is mostly a poll wait, so it splits in two: a
14
+ **fire** half (detect + create, returns straight away) and a **join** half (poll to `completed`,
15
+ verify, write `site.json`). Fire it, record `provision.in_progress`, then go do the prepare work of
16
+ the other stages (content-model prepare, frontend shell) while it settles. Only cross back to
17
+ the join half when an instance-barrier step needs the live backend. See *Background provision & the
18
+ instance barrier* in the top-level `SKILL.md`. An agent that can't interleave simply does fire and
19
+ join back-to-back — still correct, just no overlap.
20
+
21
+ ## Step 1 — Route on the suggested backend
22
+
23
+ Read the brief's **Suggested backend** section:
24
+
25
+ | Suggested backend | Follow |
26
+ |---|---|
27
+ | WordPress | `wordpress/SKILL.md` |
28
+ | WordPress + WooCommerce | `wordpress/SKILL.md` **with the WooCommerce store on** (see below) |
29
+ | Ecommerce | `ecommerce/SKILL.md` |
30
+ | Webapp | `webapp/SKILL.md` |
31
+
32
+ If the section is missing or names something else, go back to **refine** — don't pick one here.
33
+ Tell the user the backend and its one-line reason before provisioning.
34
+
35
+ > **WordPress + WooCommerce is the WordPress backend with a store — not a new backend.** Route it to
36
+ > `wordpress/SKILL.md` and follow that recipe's **optional WooCommerce tail** (install + activate the
37
+ > `woocommerce` plugin and verify the store endpoints; the catalog is seeded later through the per-site WP
38
+ > MCP's native `wc-*` abilities — no custom plugin, no consumer key). `site.json → backend` stays
39
+ > `"wordpress"`; the store is recorded under `site.json → woocommerce` (`enabled: true`). Everything else
40
+ > downstream that routes on
41
+ > `wordpress` (content-model push, deploy's `/cms` preservation, done's wp-admin login) then works
42
+ > unchanged.
43
+
44
+ > **Supported backends: `wordpress` (optionally with a WooCommerce store), `ecommerce` and `webapp`.**
45
+ > `webapp` is a plain Node.js app host (an empty website — no CMS, no store, no `/cms`) for any app/SPA
46
+ > that brings its own code and data; it never installs WordPress. PocketBase is not available in this
47
+ > version — refine never proposes it, and there is no `pocketbase/` subfolder; if a brief somehow names
48
+ > it, stop and tell the user rather than improvising it. A **WordPress + Ecommerce** brief (two separate
49
+ > backends — a WordPress site **and** a Hostinger Ecommerce store) has no single combined `start-setup`
50
+ > type yet: stop, tell the user it isn't supported as one site, and offer either to continue with just
51
+ > WordPress or just Ecommerce (route to that one subfolder), **or**, if they want content and a store on
52
+ > **one** site, to switch the brief to **WordPress + WooCommerce** — the one-site path, which routes to
53
+ > `wordpress/SKILL.md` with the store on.
54
+
55
+ ## Onboarding handoff — swap an existing empty headless shell (do this before creating anything)
56
+
57
+ Onboarding can create the website **before** you ever run, then paste the build prompt into this agent.
58
+ When it does, the domain already has an **empty headless shell**: a website set up with
59
+ `hosting_websites_start-setup { type: "headless_empty" }` — `website_type` is `headless`, but **nothing
60
+ is installed** (no WordPress at `/cms`, no store). It is the hosting slot only, waiting for a backend.
61
+
62
+ So provision has **two entry shapes**, and each subfolder's *detect* step picks between them:
63
+
64
+ - **An empty headless shell already exists for the domain → adopt it and *swap* it to the chosen
65
+ backend. Never call `start-setup` again, never create a second site.** The swap is backend-specific:
66
+ - **WordPress** → install WordPress **into the existing shell's `/cms`** with
67
+ `wordpress_installations_install { type: "headless" }` (it rewrites the root `.htaccess` and marks
68
+ the site headless-WordPress). Do **not** use `start-setup { type: "headless_wordpress" }` — that is
69
+ only for creating a fresh site.
70
+ - **Ecommerce** → the empty headless shell **is** the storefront host already (a `headless_ecommerce`
71
+ website installs no store engine either). Adopt it as the frontend host and go straight to creating
72
+ the store + custom sales channel.
73
+ - **No site exists for the domain at all → create it fresh, exactly as each subfolder defines today**
74
+ (`start-setup` with the backend's own `type`).
75
+
76
+ > **Webapp is not part of this handoff at all.** `webapp` is **not** reached on the usual onboarding
77
+ > flow — it is only triggered by experimental actions — so it **ignores headless instances entirely**:
78
+ > it never detects, adopts or swaps an empty headless shell, and provisions its own **Node.js app host**
79
+ > exactly as `webapp/SKILL.md` defines today. The swap below is **WordPress and Ecommerce only**.
80
+
81
+ **How to tell an empty shell from an already-provisioned backend** (both read `website_type: headless`):
82
+
83
+ 1. Exact-match the domain row in `hosting_websites_list` — if there is **no** row, nothing exists → create fresh.
84
+ 2. Within 24 h of onboarding, `hosting_websites_list-setups` still shows the setup `type`
85
+ (`headless_empty` = empty shell; `headless_wordpress` = WordPress already; `headless_ecommerce` = an
86
+ ecommerce host). Beyond 24 h the setup drops off — fall back to the backend probe:
87
+ 3. `wordpress_installations_list { username, domain, ownership: "all" }` — a row with `directory: "cms"`
88
+ and `is_valid: true` means WordPress is **already** installed (adopt, don't swap); **no** such row on
89
+ a `headless` site means the shell is still empty and WordPress must be swapped in. A local `site.json`
90
+ with a recorded backend means a previous run already provisioned — trust reality over it, but it tells
91
+ you not to expect an empty shell.
92
+
93
+ This only changes *detect*. Everything after the swap (verify, `site.json`, the WooCommerce tail, the
94
+ background fire/join split) is identical to a fresh provision. A swap that installs WordPress is still
95
+ asynchronous — fire it, record `provision.in_progress`, and join at the barrier just like a fresh create.
96
+
97
+ ## Step 2 — Fire (don't block)
98
+
99
+ Follow the chosen subfolder's `SKILL.md` through **detect + create** (its "start-setup" call). The
100
+ moment the create is accepted and queued, record it in `state.json` and **return** — do not sit on the
101
+ readiness poll:
102
+
103
+ ```json
104
+ { "stage": "content_model",
105
+ "provision": { "status": "in_progress", "domain": "<domain>", "started_at": "<now>" } }
106
+ ```
107
+
108
+ Now go run the prepare work that doesn't need the backend (content-model prepare, frontend
109
+ shell). The subfolder's readiness poll, verification and `site.json` are the **join** half below.
110
+
111
+ ## Step 3 — Join (at the instance barrier)
112
+
113
+ When an instance-barrier step is about to run (content-model push, frontend data wiring, deploy) — or
114
+ right away, if the agent can't interleave — finish the subfolder's `SKILL.md`: **poll to `completed`**,
115
+ run its verification, and write `site.json` (which records the chosen `backend`). Then set
116
+ `provision.status` to `"completed"` in `state.json` with a fresh `updated_at`. On resume, treat a
117
+ stored `in_progress` as a hint only — re-poll `hosting_websites_list-setups` for the truth first.