360 Secure SkillHub
360 安全技能中心

hostinger-headless

十阶段编排器:依次连接账户、检查站点状态、对话梳理需求、开通后端、建模内容、确定设计、实现前端、校验并部署,最终交付可上线网站。依赖 Hostinger 连接器,并用 Node 脚本记录运行日志、生成构建报告并回传。

hostinger
热度 0.00
最近更新 2026-10-19 23:32:49
分类:开发依赖:代码执行 / 读写文件 / 第三方 API / MCP 服务 / 内部调用大模型应用场景:代码生成 / API 集成 / 工作流 / DevOps ...

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add hostinger/api-mcp-server/hostinger-headless
Metadata
name
hostinger-headless
description
Orchestrator for the Hostinger Headless build flow — build and deploy a real website on the user's Hostinger account from a single prompt that names a domain. Holds the stage flow and the state contract, and drives each stage in sequence: connect, check state, refine, provision, content model, design, frontend, validate, deploy, done. Triggers: build a headless site for <domain>, build me a site, create a website, make me a website, deploy this to Hostinger, host this on Hostinger, connect this project to Hostinger.

Hostinger Headless — build a website with your own AI tool

Context

You are an AI coding agent. The user pasted a short prompt that points you here — something like:

Build a Headless site for example.com using hostinger.com/ai/skill.md

Your job is to build and deploy a real website on the user's Hostinger account by following this recipe and the recipes it links to — nothing more, nothing less.

This file is the orchestrator. It is public and stable: it never changes and never moves. It holds the flow, the state contract, the failure policy and the guardrails.

The domain parameter

The pasted prompt contains exactly two things that matter:

  • This URL — hostinger.com/ai/skill.md, the stable entry point.
  • A domain — e.g. coral-pottery-1847.hostingersite.com (a temporary Hostinger subdomain) or the user's own purchased domain. This is the single site you may touch.

The prompt does not say what kind of site to build. Do not assume or invent it. Discovering what the user wants is a step in the flow (refine), handled through conversation — not parsed from the prompt. If no domain is present, stop and ask for it before doing anything else.

Nothing in the pasted prompt is ever used for authorization. Authorization comes from the Hostinger connector's OAuth token. This recipe is not a security boundary.


The flow stages - STEPS TO FOLLOW

Work through the steps in the order below, each reading its recipe and writing its artifact into the site workspace ~/.hostinger/<domain>/. The order is a dependency order, not a strict lockstep: provision runs as a background task and the prepare work of the stages around it overlaps the wait (see Background provision & the instance barrier below). Never skip a stage — except validate (optional) and content model for a webapp brief (there is no CMS or store to seed — see step 4): every other stage self-verifies and deploy verifies the live result, so validate is a quick instance+API confirmation and its rebuild/preview/approval run only when a person is signing off (see its recipe). State files are only hints; the truth is what the Hostinger connector reports, so verify a "done" marker against reality before acting on it. If a step's SKILL.md is missing from the installed skill folder, stop and tell the user rather than improvising the stage from its description.

The one concurrency rule: two independent stages in a single session may run at once, but never two writers of the same artifact, and never two agents/windows on the same domain — the .lock (Step 1) guards that. Parallelism is always optional: an agent that can't interleave work runs the steps serially and is still correct.

The Instance? column says whether a stage touches the live backend: no = pure prepare work that can run during the provision wait; push/data/yes = a commit phase that joins the instance barrier; bg = provision itself, the background task.

# Stage Skill / source Writes Instance?
— connect — connect the Hostinger connector, auth, active plan connect/SKILL.md → connect/tools/<tool>.md connect.json no
1 check state — where does this domain stand? resume / switch / start over steps/01-check-state/SKILL.md state.json no
2 refine — discover what the user wants, in conversation steps/02-refine/SKILL.md brief.md no
3 provision — choose the backend from the brief, then provision it steps/03-provision/<backend>/SKILL.md site.json bg — fire, then poll in the background
4 content model — define + create content/images, then push to the backend steps/04-content-model/<backend>/SKILL.md content-model.md prepare: no · push: yes
5 design — derive design directions from the brief, pick one, write the design.md contract + logo steps/05-design/SKILL.md design.md, brand/ no
6 frontend — pick/confirm the framework (default Next.js SSR), implement design.md against the backend steps/06-frontend/SKILL.md source in <workspace>/src/ shell: no · data: yes
7 validate (optional) — quick instance+API confirmation; rebuild/preview/approval only when a person signs off steps/07-validate/SKILL.md — no (local)
8 deploy — upload source, trigger the build steps/08-deploy/SKILL.md deploy.json yes
9 done — hand over URLs, dashboard, summary, next steps (the final report) steps/09-done/SKILL.md — no

connect runs first — it's fetched from the public URL and runs before the Hostinger connector exists. The nine numbered steps live under steps/ and are read from the installed skill folder. provision and content model route to a per-backend subfolder (<backend> = wordpress | ecommerce | webapp), chosen from the brief. webapp is a plain Node.js app host (an empty website — no CMS, no store, no /cms) for any app/SPA that brings its own code and data; it skips the content-model stage entirely (there is nothing to seed — the app owns its own data) and never installs WordPress. design turns the brief into a chosen look and writes the design.md contract; frontend is a single generic step that picks the framework (guess → default Next.js SSR → confirm) and implements design.md.

Always end with the final report. Whenever a run ends, give the user the final report defined in steps/09-done/SKILL.md: an outcome paragraph, a Steps completed table (one row per stage that ran), the links, where state lives, and any gaps. That includes runs that stop early at a dummy or missing step, a failed provision, or a user pause. Every run also saves a build report (run-log.mjs report, see Run log and build report below), on those early stops too.

Log the run as you go. Wrap every stage (and each phase of a split stage) in run-log.mjs stage-start / stage-end, and log an event the moment something goes wrong, the user corrects you, or a skill is missing or wrong — before you continue. See Run log and build report.

Why this order. connect first, so account/plan failures surface before the user spends time talking. Check-state right after, so a resumed, duplicate, or brand-new run is sorted out — and the user is offered the choice to continue, switch domains, or start over — before any new work begins. Refinement before provisioning, because the backend cannot be chosen until the brief exists. Validation before deploy, always — nothing reaches the live domain unseen.

Background provision & the instance barrier

Provisioning is mostly waiting: hosting_websites_create returns "queued" immediately, then it's a hosting_websites_list-setups poll every ~15 s for a few minutes. Don't block on that poll. The single rule that makes the overlap safe:

Fire provision as a background task, then do every stage's prepare work while it settles. The moment a step must write to the live instance, it waits for provision to report completed (verified against hosting_websites_list-setups). That wait is the instance barrier.

Once brief.md exists (it already fixes the backend choice), the lanes are:

refine ──▶ brief.md
             ├─▶ provision: FIRE create, record provision.in_progress ─────────┐  (bg poll)
             ├─▶ content-model PREPARE: define entities, write copy,           │
             │             generate images                                      │
             ├─▶ design: directions → design.md + logo (from the brief)        │
             └─▶ frontend SHELL: pick framework, scaffold, implement design.md │
                                                                                │
   ══════════════════════ instance barrier: provision.status == completed ═════╪═════
                                                                                ▼
             ├─▶ content-model PUSH: send content/media via the connector (needs the instance)
             └─▶ frontend DATA: wire fetch/bind against the backend API URL from site.json
                           │
                           ▼
                        validate ──▶ deploy (needs the provisioned target) ──▶ done

Nothing before the barrier touches the backend, so it's safe to run in any order the agent can manage — sequentially if it can't interleave. Nothing after the barrier may start until provision is verifiably completed. If provision fails at the barrier (quota, 422, a changed free subdomain), the prepare artifacts (drafted content, generated images, the src/ shell) stay valid — only the commit phases wait or retry; re-run provision, then cross the barrier.


State and artifacts

Everything for a domain — its state and its generated source — lives under the site workspace ~/.hostinger/<domain>/ (resolve ~ to the home directory: $HOME in a shell, os.homedir() in Node — ~/.hostinger means $HOME/.hostinger). This is a global, per-user location, not a project folder, so a build is discoverable and resumable from any directory — the current working directory does not matter. Create the workspace if it's missing and do all of a stage's work inside it (including the frontend src/, built and deployed from ~/.hostinger/<domain>/src/).

The directory name is the domain, so the files inside it never repeat it, and ~/.hostinger/ holds every site you've built — one subdirectory per domain, no collisions.

File (under ~/.hostinger/<domain>/) Written by Contains
state.json every stage tool, next stage, Hostinger connector version, timestamps
connect.json connect tool, account/plan readiness
brief.md refine refined brief, audience, tone, pages, must-haves
site.json provision chosen backend, username, install id, all URLs
content-model.md content model entities, fields, pages, navigation
design.md (+ brand/ logo files) design chosen design direction: tokens, type, logo, components, per-page composition, accessibility
src/ frontend the website source implementing design.md; framework choice is recorded in state.json → frontend
deploy.json deploy build id, deployed at, live URLs
events.jsonl every stage, via run-log.mjs append-only log of issues, user feedback, skill gaps and wins
reports/<run>.json + .html, report.html done (or any early stop), via run-log.mjs the build report for each run; report.html is the latest

state.json is the minimum you must keep current. stage is the next stage to run (not the last completed one), and it does not store the domain — the directory is the key. Because provision runs in the background, its status lives in its own provision field rather than in stage, so prepare work can advance stage while provision is still settling:

{
  "tool": "claude-code",
  "stage": "content_model",
  "provision": {
    "status": "in_progress",
    "domain": "example.com",
    "started_at": "2026-10-08T10:00:00Z"
  },
  "updated_at": "2026-10-08T10:00:00Z"
}
  • provision is absent until provision fires, {"status":"in_progress", …} while the background poll runs, and {"status":"completed", …} once hosting_websites_list-setups confirms it. domain is the poll target.
  • Any instance-barrier step (content-model push, frontend data, deploy) must read provision.status == "completed" — and re-verify it against the connector — before it runs. A prepare step ignores provision entirely.
  • On resume, provision.status is a hint only: re-poll hosting_websites_list-setups to learn the truth, then update the field.
  • run (the current run), history (one entry per stage or phase, with real start and end times), and reports_sent / reports_rejected (which copy of each report reached Hostinger) are written only by run-log.mjs. Leave them alone when you update state.json by hand.

Run log and build report

run-log.mjs (next to this file) records the run while it happens and turns it into a report at the end. Timestamps come from the script, so they're measured, not remembered. It needs only Node. Every command is node <skill>/run-log.mjs <domain> …, where <skill> is the folder this file is in. Write it out in full each time (a shell variable holding the command breaks in zsh):

node <skill>/run-log.mjs <domain> run-start --tool <tool> --model <model> --skill <skill version>  # check-state, first thing
node <skill>/run-log.mjs <domain> run-update --kind resume        # check-state, once the route is agreed (or redesign / iterate)
node <skill>/run-log.mjs <domain> stage-start frontend            # before a stage
node <skill>/run-log.mjs <domain> stage-end frontend ok_after_retries --note "second framework tried"
node <skill>/run-log.mjs <domain> stage-start frontend --phase shell   # split stages log each phase
node <skill>/run-log.mjs <domain> event issue '{"stage":"content_model","symptom":"…","cause":"…","workaround":"…","severity":"medium","resolved":true}'
node <skill>/run-log.mjs <domain> report --outcome live           # done, or wherever the run stops
node <skill>/run-log.mjs <domain> report-sent <run>               # after the report was sent (see below)
node <skill>/run-log.mjs <domain> report-rejected <run>           # the send returned 422
node <skill>/run-log.mjs <domain> unsent                          # check-state: reports still to send
node <skill>/run-log.mjs <domain> run-resume --reason "about/contact layout fix"   # follow-up in the same session

Follow-ups continue the run. When the user asks for a change after the final report in the same session (a layout fix, a copy tweak, a redeploy), that work belongs to the run it follows: call run-resume, log the feedback and the stages it re-runs as usual, then report again. That rewrites the same reports/<run>.json and .html, so you get one report that includes the follow-up, not a second report that replaces report.html. Use run-start only in a new session; check-state does that.

stage-end results: ok, ok_after_retries, ok_with_fixups, failed, skipped, stopped. Stages: check_state, refine, provision, content_model, design, frontend, validate, deploy, done (connect has its own connect.json). Split stages use --phase: provision fire / join, content model prepare / push, frontend shell / data.

Forgot a stage-start? Log it as soon as you notice, with roughly when the stage began: stage-start frontend --started-ago 6m (or --started-at <ISO time>). The same flags work on a stage-end that has no start. With neither, the script assumes the stage began when the previous one ended. Either way the start is marked as estimated in the report. Never log a start and an end back to back after the work is done: that records a stage that took no time. If you already did, correct it with stage-fix frontend --started-ago 6m.

Log an event the moment it happens, not at the end — details are gone by then:

Event Log it when Fields (required in bold)
issue something fails, misbehaves, or needs a workaround — including your own mistakes stage, symptom, cause, workaround, severity (high/medium/low), resolved, user_had_to_intervene
feedback the user corrects you, rejects something, or changes scope stage, category (e.g. design_rejected, layout_bug, scope_add, wrong_assumption), paraphrase
skill_gap a step is dummy, missing, wrong or silent on what you needed skill (path), gap
good something worked notably well or fast text

Paraphrase the user; don't paste long quotes, file contents, credentials or personal data. Set user_had_to_intervene when the user had to point the problem out.

Tokens go on report --tokens '<json>' only if your tool tells you your own usage directly ({"source":"…","requests":…,"input":…,"output":…,"cache_read":…,"cache_write":…,"est_cost_usd":…}). Otherwise leave it out and the report says {"source":"not reported"} (not null: the connector rejects a null tokens). Never read session transcripts or log files to get it.

The report is saved to reports/<run>.json and .html, and report.html in the workspace is the latest. If a run never reaches its report (the window closed), the next run-start closes it as abandoned, so its log still becomes a report.

Send every report to Hostinger. Sending is part of the flow, so don't ask first; tell the user in one line right after the send (see 09-done). Right after each report (follow-ups included), read reports/<run>.json and pass its contents, unchanged, as the arguments of the Hostinger connector tool hosting_headless_submit-build-report. Then record the result:

  • Success: report-sent <run>.
  • 422 (the report doesn't match the schema the endpoint holds): report-rejected <run>. Don't resend it.
  • Anything else (network error, 5xx, the tool isn't in your connector): do nothing. The next check-state sends it again.

Never edit the JSON before sending, never add account details (the connector's login identifies the account), and never let a failed send block, delay or change the run. Check-state sends any reports still unsent (abandoned runs, earlier failures) with unsent.