@awesomate/hosting-mcp 0.19.1 → 0.20.0

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.
@@ -47,8 +47,13 @@ value goes browser → destination directly; you only ever see the key NAMES.
47
47
  node ~/.claude/skills/awesomate-credentials/scripts/secret-drop.mjs \
48
48
  --hub-app <appId> --env dev --keys STRIPE_SECRET_KEY --port <port> --token <hex>
49
49
  ```
50
- Get `<appId>` from `awesomate_app_list`. Keys are UPPER_SNAKE (lowercase is
51
- auto-uppercased). Node apps only static sites have no server env. The
50
+ Get `<appId>` from `awesomate_app_list`. Keys must be UPPER_SNAKE: the
51
+ drop script uppercases what you pass it in hub mode, but the
52
+ `awesomate_app_set_env` TOOL does not — it hard-rejects anything that
53
+ isn't `^[A-Z][A-Z0-9_]{0,63}$`, so a lowercase name or a leading
54
+ underscore is a validation error there, not a tidy-up. Pick the final
55
+ uppercase name once and use it in both places. Node apps only — static
56
+ sites have no server env (`set_env` returns 400 for them). The
52
57
  script posts each value to the hub with the user's own PAT
53
58
  (`~/.awesomate/credentials.json`) — the same route `awesomate_app_set_env`
54
59
  uses, so encryption, `.env` injection and restart all behave identically.
@@ -71,6 +76,26 @@ value goes browser → destination directly; you only ever see the key NAMES.
71
76
  6. Confirm with key names only. No rotation warning needed — the value never
72
77
  entered the conversation.
73
78
 
79
+ ### What the drop link can't do
80
+
81
+ - **The link is short-lived and single-use.** It expires after 15 minutes
82
+ (`--ttl <minutes>` to change it) and the server exits after the FIRST
83
+ successful save unless you passed `--stay`. If the user comes back later
84
+ and the page is dead, that's expected — start a fresh one on a new port
85
+ with a new token rather than telling them to retry the old link.
86
+ - **It cannot carry a MULTI-LINE value.** The bulk box is parsed line by
87
+ line, splitting on the first `=`, so a PEM private key or a Google
88
+ service-account JSON loses everything after line 1 — silently, and those
89
+ are two of the commonest secrets people have. The named field is a
90
+ single-line input, so it can't hold one either. For a multi-line secret,
91
+ either:
92
+ - **base64 it into one line** — `base64 -i key.pem | tr -d '\n'` — drop
93
+ that through the link as e.g. `GOOGLE_SA_JSON_B64`, and decode it in the
94
+ app at startup; or
95
+ - have the user **save it to a file** on their machine and tell you the
96
+ path, then read and store it — being honest that reading it puts the
97
+ value in the conversation record, so the rotation nudge applies.
98
+
74
99
  ## Detect and offer
75
100
 
76
101
  If the user's message contains something shaped like a secret — `sk-…`,
@@ -94,14 +119,26 @@ full map. Short version:
94
119
  the file-mode link; add a rotation note if it came through the chat.
95
120
  - **Never** a tracked file, a commit, or the chat.
96
121
 
122
+ A secret for an n8n workflow belongs on the n8n instance (awesomate-n8n
123
+ skill), never in an app `.env`. Those tools are consent-gated: if one comes
124
+ back 403 `consent_required`, call `awesomate_privacy_settings` — it names
125
+ the exact toggle that's off, so you can send the user to the right switch at
126
+ hub.awesomate.ai/n8n/settings instead of guessing. You can't flip it
127
+ for them.
128
+
97
129
  ## Fallback: the file-drop flow
98
130
 
99
131
  Only when the link flow can't work (e.g. Claude is running on a remote machine
100
132
  the user's browser can't reach as 127.0.0.1):
101
133
 
102
134
  1. Tell them: *"Create a file `.awesomate/secret-inbox.txt` in your project and
103
- paste the value there — I'll grab it and wipe the file."* (`.awesomate/` is
104
- gitignored by the github skill.)
135
+ paste the value there — I'll grab it and wipe the file."*
136
+ **Verify `.gitignore` yourself before any commit.** Don't assume the
137
+ folder is ignored: the github skill's setup script adds `.awesomate/` only
138
+ when it has actually been run in this project, and older installed copies
139
+ of that script didn't list it at all. `grep -q '^\.awesomate/' .gitignore`
140
+ — add the line if it's missing, before the file exists, and never commit
141
+ while it does.
105
142
  2. Read the file, store via `awesomate_app_set_env`, then **scrub the file**:
106
143
  `node ~/.claude/skills/awesomate-credentials/scripts/capture-secret.mjs .awesomate/secret-inbox.txt`
107
144
  3. Be honest with the user: reading the file put the value in the conversation
@@ -26,6 +26,14 @@ co-located with the workflow that uses it. No hosting slot consumed, and
26
26
  workflows query it directly — this is the default answer for anything
27
27
  automation-shaped. Inspect what exists with
28
28
  `awesomate_n8n_inspect {what:'datatables'}`.
29
+ **Both the write AND that read are gated:** Support Plus or above, plus the
30
+ privacy toggle **"Allow Claude Code to Build n8n Workflows"** — n8n →
31
+ Settings → Privacy (hub.awesomate.ai/n8n/settings, or the same toggles at
32
+ hub.awesomate.ai/n8n/settings, which is what the 403's
33
+ `settingsUrl` points at). It is **off by default**, so on a fresh account
34
+ both the read and the write come back 403 `consent_required`. Call
35
+ `awesomate_privacy_settings` to name the exact toggle that's off, send the
36
+ user to flip it, then re-check. You cannot flip it for them.
29
37
 
30
38
  **(b) Real APP data** — logins, dashboards, anything relational that an
31
39
  app serves to people. → the app's own Postgres.
@@ -38,7 +46,23 @@ app serves to people. → the app's own Postgres.
38
46
  **(c) A WORKFLOW that needs raw SQL against its own Postgres** — real
39
47
  joins, aggregates, or volumes a data table shouldn't carry. →
40
48
  `awesomate_n8n_provision_pg`. One step creates the database AND the n8n
41
- credential, so the workflow can query it immediately.
49
+ credential, so the workflow can query it immediately. It has the most gates
50
+ of anything here — check them BEFORE offering it, so the user doesn't hit a
51
+ wall halfway:
52
+ - Support Plus or above.
53
+ - The **"Allow Claude Code to Build n8n Workflows"** toggle (off by
54
+ default) — same one as branch (a).
55
+ - The **direct database writes** consent (`allow_pg_writes`). It's on by
56
+ default, so this is rare — but it has **no client-facing toggle in the
57
+ hub**, so if it's off, don't send the user hunting for a switch that
58
+ doesn't exist: route it to support via the awesomate-support skill.
59
+ - An Awesomate cPanel hosting account. Without one it returns 409
60
+ `hosting_required`; hosting comes first (awesomate-hosting skill).
61
+ - Capped at **2 a day**.
62
+
63
+ On any 403 here, call `awesomate_privacy_settings` first — it names the
64
+ exact toggle that's blocking, which decides whether this is a "flip this
65
+ switch" or a "raise it with support" answer.
42
66
 
43
67
  **(d) Analytics/BI or data shared with other systems** — reporting
44
68
  warehouses, a spreadsheet the whole team lives in, a CRM. → recommend
@@ -69,12 +93,19 @@ reach), ask "live or dev?" before provisioning against it.
69
93
 
70
94
  ## 2. Safety rules
71
95
 
72
- - **Passwords are shown ONCE by provisioning and land where they
73
- belong** the app's environment for `awesomate_app_provision_db`,
74
- the n8n credential for `awesomate_n8n_provision_pg`. Never echo a
75
- password into chat, and never put a `DATABASE_URL` in a message. Tell
76
- the user where it lives instead: "the app already has its connection —
77
- nothing for you to copy."
96
+ - **Passwords land where they belong, and the two branches differ.**
97
+ `awesomate_app_provision_db` NEVER returns a password: it's set
98
+ server-side, stored encrypted, and injected as the app's `DATABASE_URL`
99
+ there is nothing to show, so don't promise the user a password.
100
+ `awesomate_n8n_provision_pg` is the one that DOES return a password, once,
101
+ because it lives in the n8n credential and Awesomate never stores it. The
102
+ workflow doesn't need you to repeat it — the credential already holds it —
103
+ so say that, and only offer the value if the user actually needs it
104
+ elsewhere, warning that it has now passed through the transcript and
105
+ should be rotated. Never put a `DATABASE_URL` in a message. Tell the user where
106
+ it lives instead: "the app already has its connection — nothing for you
107
+ to copy." (After an app database is provisioned, the app needs a restart
108
+ or redeploy to pick it up.)
78
109
  - Secrets the user's own app code needs (API keys, tokens) go through
79
110
  the awesomate-credentials skill, never pasted into files or chat.
80
111
  - **Deleting data requires an explicit filter and an explicit yes.**
@@ -84,14 +115,28 @@ reach), ask "live or dev?" before provisioning against it.
84
115
 
85
116
  ## 3. Limits, honestly
86
117
 
87
- Provisioning quotas are per-day and plan-gated. App databases
88
- (`awesomate_app_provision_db`) and workflow Postgres
89
- (`awesomate_n8n_provision_pg`) need Support Plus or above; data tables
90
- work on any plan with n8n access. If the user's plan doesn't cover what
91
- branch (b) or (c) needs, say it once "app databases are on Support
92
- Plus" point them at hub.awesomate.ai/billing to upgrade, then help
93
- fully within what their plan allows. Usually that means branch (a): a
94
- data table covers more "keep track of X" asks than people expect. If a
118
+ Everything that provisions here needs **Support Plus or above** — app
119
+ databases (`awesomate_app_provision_db`), workflow Postgres
120
+ (`awesomate_n8n_provision_pg`) and data tables alike. Data tables are NOT
121
+ "any plan with n8n access": Essentials gets 0 creations a day, and both the
122
+ table read and the write also need the "Allow Claude Code to Build n8n
123
+ Workflows" toggle (§0(a)).
124
+
125
+ Only some of it is capped per day:
126
+ - `awesomate_n8n_provision_pg` — **2 a day**, flat; no plan raises it, so
127
+ don't pitch an upgrade for it.
128
+ - Data table creations — **10 a day** on Support Plus and Pro (20 on
129
+ Embedded), 0 on Essentials. An instance also tops out at 50 data tables.
130
+ - `awesomate_app_provision_db` — **no daily cap**. It's one database per
131
+ environment and refuses (409 `already_has_db`) if the app has one, so
132
+ there's nothing to ration.
133
+
134
+ If the user's plan doesn't cover what branch (b) or (c) needs, say it once
135
+ — "app databases are on Support Plus" — point them at
136
+ hub.awesomate.ai/billing to upgrade, then help fully within what their plan
137
+ allows. On Essentials that means none of (a), (b) or (c) is available —
138
+ don't dangle a data table as the consolation prize; say so once and look at
139
+ (d), keeping the data where it already lives and connecting to it. If a
95
140
  daily quota is hit, say when it resets and what can proceed meanwhile.
96
141
 
97
142
  Report every result as a business outcome: "your workflow now remembers
@@ -47,19 +47,48 @@ Ask only: **"What should we call this project?"** (repo name) and, if relevant,
47
47
  **"Keep it private?"** (default yes). Derive a sensible kebab-case repo name
48
48
  from what they tell you.
49
49
 
50
+ **The script's first push goes to `main`.** It runs `git init -b main` and
51
+ pushes the current branch, so on a fresh repo `main` — the PRODUCTION branch
52
+ for Node apps — is what gets created. That's fine for a repo that's just a
53
+ backup, but if the code isn't ready to be live, say so before running it, or
54
+ create and check out `dev` first. There is **no `dev` branch until you make
55
+ one**: `git push origin dev` on a fresh repo fails. Create it, then push:
56
+
57
+ ```
58
+ git checkout -b dev
59
+ git push -u origin dev
60
+ ```
61
+
50
62
  ## 2. Push-to-deploy (for apps built with awesomate-app-builder)
51
63
 
52
- If this is a Node app from the app builder, wire the deploy secrets so a push
53
- ships it (GitHub Actions cPanel). The app builder / hub provides the SSH
54
- deploy values; set them as repo secrets with `gh secret set` (the script does
55
- this when run with `--deploy-secrets` and the values are available in the
56
- environment). Then: **push to `dev` → deploys dev; `main` → deploys prod.**
57
- Explain it as *"save your work = it goes live"* don't lecture on branches.
64
+ Node apps from the app builder ship with a GitHub Actions workflow that
65
+ deploys on a push to `dev` / `staging` / `main` (dev dev, main → prod).
66
+ Once the branches exist, explain it as *"save your work = it goes live"*
67
+ don't lecture on branches.
68
+
69
+ **But you cannot finish the wiring yourself, and you should say so.** That
70
+ workflow needs `SSH_HOST`, `SSH_USER` and `SSH_PRIVATE_KEY` as repo secrets,
71
+ and **no client-reachable tool or route returns those values** — they're
72
+ admin-only. `github-setup.mjs --deploy-secrets` only copies them from your
73
+ environment, so with nothing there it prints `skip deploy secret …` and the
74
+ first deploy run goes red. So:
75
+
76
+ 1. Set up the repo, the branches and the commits (§1) — all of that works.
77
+ 2. Tell the user plainly: *"your code is backed up on GitHub; the automatic
78
+ deploy still needs Awesomate to connect it — I'll raise that for you."*
79
+ Raise it via the **awesomate-support** skill.
80
+ 3. **Do not loop on the failing pipeline.** Re-running it, rewriting the
81
+ workflow, or pushing again won't produce the missing secrets.
82
+
83
+ Static sites have no deploy workflow at all — the template is just the page
84
+ files — so pushing does not publish them either; same handoff.
58
85
 
59
86
  ## 3. Everyday use (plain language)
60
87
 
61
88
  - "Save my work" → stage, commit with a short message you write for them, push.
62
- - "Put it live" → push to the right branch (dev/staging/main) and tell them the URL.
89
+ - "Put it live" → push to the right branch (dev/staging/main) and tell them the
90
+ URL. If the branch doesn't exist yet, create it (`git checkout -b <name>`)
91
+ before pushing — only `main` exists after first-time setup.
63
92
  - Always write clear commit messages **for** them; don't ask them to.
64
93
 
65
94
  ## 4. Be the version-control guardian (proactive, not reactive)
@@ -78,6 +107,13 @@ control — they should never have to think about it:
78
107
  aren't backed up anywhere — want me to set that up? Takes a minute."*
79
108
  `env_file_tracked` is urgent: untrack it, .gitignore it, and route the
80
109
  secrets through awesomate-credentials.
110
+ **`last_deploy_failed` that never clears is usually the unwired deploy
111
+ secrets (§2), not a bug you can fix.** Check whether `SSH_HOST` /
112
+ `SSH_USER` / `SSH_PRIVATE_KEY` are set on the repo (`gh secret list`)
113
+ before touching anything: if they're missing, stop, tell the user the
114
+ deploy connection is pending with Awesomate, and raise it via the
115
+ awesomate-support skill. Don't retry the run, and don't start editing the
116
+ workflow file.
81
117
  - **Auto-checkpoint.** After every meaningful working change (feature works,
82
118
  bug fixed, content updated), commit with a plain-English message — don't
83
119
  wait for "save my work", and never ask them to write a message. Push at
@@ -90,7 +126,12 @@ control — they should never have to think about it:
90
126
 
91
127
  ## Hard rules
92
128
  - Never commit a secret or a `.env`. The script's secret guard is a backstop,
93
- not a licence to skip checking. If you spot a secret, route it through the
129
+ not a licence to skip checking. The script's `.gitignore` list `.env`,
130
+ `.env.local`, `.awesomate/`, `*.log`, `.DS_Store`, `node_modules/` — is only
131
+ applied when the script has been run in that project, so on a repo somebody
132
+ else set up, read `.gitignore` before committing rather than assuming.
133
+ `.awesomate/` matters especially: the credentials skill's file-drop fallback
134
+ puts a live secret there. If you spot a secret, route it through the
94
135
  awesomate-credentials skill instead.
95
136
  - Never ask the user for a GitHub token or password; the device-flow is the
96
137
  only auth path.
@@ -50,7 +50,10 @@ if (run('gh', ['auth', 'status']).status !== 0) {
50
50
 
51
51
  // --- 1. .gitignore excludes .env ------------------------------------------
52
52
  const giPath = join(cwd, '.gitignore');
53
- const needed = ['.env', '.env.local', '*.log', '.DS_Store', 'node_modules/'];
53
+ // .awesomate/ is the secret-drop inbox the credentials skill tells users it is
54
+ // ignored, and the SECRET_RE guard only catches known key SHAPES, so a database
55
+ // URL or bare token in there would otherwise be committable.
56
+ const needed = ['.env', '.env.local', '.awesomate/', '*.log', '.DS_Store', 'node_modules/'];
54
57
  let gi = existsSync(giPath) ? readFileSync(giPath, 'utf8') : '';
55
58
  const have = new Set(gi.split(/\r?\n/).map((l) => l.trim()));
56
59
  const toAdd = needed.filter((n) => !have.has(n));
@@ -20,11 +20,15 @@ description: >
20
20
 
21
21
  You are helping the user run their **Awesomate-hosted WordPress** through the
22
22
  **Awesomate Hosting MCP** (tools prefixed `awesomate_`). For WordPress work,
23
- use the tools you have: `awesomate_run_wp_cli` for plugins, themes, options,
24
- and maintenance; `awesomate_wp_post` for creating/updating posts and pages
25
- (drafts by default); `awesomate_wp_media_import` for pulling media in by URL.
26
- For anything beyond those visual page-builder edits, theme design work —
27
- point the user at their WP admin (1-click SSO link) rather than improvising.
23
+ use the tools you have: `awesomate_run_wp_cli` for the allowlisted verbs
24
+ (plugin/theme list, activate, install-by-slug, update, cache flush, `option
25
+ get`, the `list` reads §0a has the full gate and its gaps);
26
+ `awesomate_wp_settings` for title/tagline/timezone and other core settings;
27
+ `awesomate_wp_post` for creating/updating posts and pages (drafts by
28
+ default); `awesomate_wp_media_import` for pulling media in by URL. For
29
+ anything beyond those — visual page-builder edits, theme design work, core
30
+ updates, user management — point the user at their WP admin (1-click SSO
31
+ link) rather than improvising.
28
32
 
29
33
  ## 0. First run — orient before acting
30
34
 
@@ -45,21 +49,45 @@ once (plus `awesomate_get_limits` before any create/change) and cache:
45
49
  **hub.awesomate.ai/sites → Connect Claude Code** to refresh the token.
46
50
  - **`skill.updateAvailable`** — covers all nine skills; the local files are
47
51
  older than the MCP server. Mention it ONCE per session, with the what's-new
48
- line the context includes, and offer to run `awesomate_skill_update`. Give
49
- the exact restart step: in a terminal, type `exit` and run `claude` again;
50
- in VS Code, run "Reload Window". Never raise it mid-task, never nag twice
51
- in a session. If `serverVersion` is still older than `latestMcpVersion`
52
- after a restart, the npx cache is stale the remedy is
52
+ line the context includes, and offer to run `awesomate_skill_update`. Its
53
+ response carries `restart.instruction` the ONE step for THIS user's
54
+ surface, detected from the session itself (terminal / VS Code / desktop
55
+ app). Relay that line verbatim. Never read out a menu of surfaces: a
56
+ Windows desktop-app user told to "type `exit`" is being given a step that
57
+ does not exist for them. If the response includes `restart.note2` (the
58
+ surface could not be detected), ask the user how they run Claude Code
59
+ rather than guessing steps. Never raise the update mid-task, never nag
60
+ twice in a session. If `serverVersion` is still older than
61
+ `latestMcpVersion` after a restart, the npx cache is stale — the remedy is
53
62
  `rm -rf ~/.npm/_npx`, then restart again.
54
63
  - **`cpanel`** routing (host/user), present once hosting is provisioned.
55
64
 
56
65
  If `awesomate_get_context` fails with a connectivity error, it's the user's
57
66
  network or the API base — not an auth problem; say so.
58
67
 
68
+ ### Hosting not set up yet (the most likely day-one state)
69
+
70
+ If `awesomate_get_context` returns **`provisioned: false`**, or the hosting
71
+ tools 404 with `"No hosting account"`, this account has a connection but no
72
+ hosting yet. Nothing else in this skill works until that changes, and
73
+ **there is no MCP tool that provisions hosting** — don't hunt for one, and
74
+ don't retry the 404.
75
+
76
+ Say it plainly and send them to the one place it happens: *"Your Awesomate
77
+ account isn't hosting a site yet. Set that up at hub.awesomate.ai/sites —
78
+ takes a couple of minutes — then come back and I can work on it."* Then
79
+ stop; offer the n8n / app-builder / SEO work that doesn't need hosting
80
+ instead of stalling on it.
81
+
82
+ Read `references/voice.md` before writing to the user — most people here
83
+ are business owners, not developers, and that file is the tone this skill
84
+ is written in.
85
+
59
86
  References: `references/multi-account.md` (profiles, pins, resolution order,
60
87
  wrong account) · `references/connect-troubleshooting.md` (bootstrap, sandbox/
61
88
  proxy failures, resuming a connect, support report) ·
62
- `references/rest-fallback.md` (no `awesomate_*` tools — serve over REST).
89
+ `references/rest-fallback.md` (no `awesomate_*` tools — serve over REST) ·
90
+ `references/voice.md` (how to talk to a non-technical owner).
63
91
 
64
92
  ## 0a. Tool map — reach for it when
65
93
 
@@ -69,6 +97,8 @@ proxy failures, resuming a connect, support report) ·
69
97
  | `awesomate_get_context` | Session start — plan, capabilities, PAT expiry, `attention`, skill updates |
70
98
  | `awesomate_get_limits` | Before any create/change — live plan limits + workflow/AI-editor credit balances |
71
99
  | `awesomate_get_plan_features` | The live plan ladder, so upgrade talk is accurate |
100
+ | `awesomate_get_hosting_status` | Is hosting provisioned at all — eligible/provisioned flags, in-progress step, primary domain, DNS targets. Check before suggesting any site action |
101
+ | `awesomate_get_hosting_account` | cPanel account details: package, server, provisioned-at, masked username |
72
102
  | `awesomate_list_sites` | What WordPress sites exist on this account |
73
103
  | `awesomate_site_create` | Spin up a new WordPress site (check limits first) |
74
104
  | `awesomate_list_domains` | What domains are attached, and to which site |
@@ -79,11 +109,12 @@ proxy failures, resuming a connect, support report) ·
79
109
  | `awesomate_list_snapshots` | What restore points a site has |
80
110
  | `awesomate_rollback_site` | Restore a snapshot after something went wrong (confirm first) |
81
111
  | `awesomate_site_staging_create` / `_promote` / `_discard` | Private full copy on awesomate.dev to review changes; publish or throw away (§5a) |
82
- | `awesomate_run_wp_cli` | Any WP-CLI command against a live site plugins, options, users, maintenance |
112
+ | `awesomate_run_wp_cli` | The 10 allowlisted WP-CLI verbs only (see below)plugin/theme list, activate, install-by-slug, update; `cache flush`; `option get`; `post`/`media`/`menu`/`comment`/`user list` |
113
+ | `awesomate_wp_settings` | Site title, tagline, timezone, date/time format, posts-per-page, search-engine visibility — THE path for any multi-word value, and it flushes the cache (Support Plus+) |
83
114
  | `awesomate_wp_post` | Create/update/read a WP post or page — drafts by default (writes are Support Plus+) |
84
115
  | `awesomate_wp_media_import` | Pull an image/file into the WP media library from an https URL (Support Plus+) |
85
116
  | `awesomate_uninstall_site` | Remove a WordPress install (destructive — confirm explicitly) |
86
- | `awesomate_privacy_settings` | Read which privacy/consent toggles are on — explain a 403 `consent_required` precisely (the user flips toggles themselves at hub.awesomate.ai/settings?tab=privacy) |
117
+ | `awesomate_privacy_settings` | Read which privacy/consent toggles are on — explain a 403 `consent_required` precisely (the user flips toggles themselves under n8n → Settings → Privacy at hub.awesomate.ai/n8n/settings) |
87
118
  | `awesomate_notifications` | The hub notification bell — `list` unread (quota warnings, quote ready, support-access events), `read`/`read_all` to clear |
88
119
  | `awesomate_dashboard_metrics` | Account-wide numbers: executions by status, error rate, time saved, chat sessions, 7-day trend |
89
120
  | `awesomate_account_report` | A monthly-report-shaped read: working / not working / engagement / commercials |
@@ -91,6 +122,36 @@ proxy failures, resuming a connect, support report) ·
91
122
  | `awesomate_support` | Raise a support ticket / reach a human |
92
123
  | `awesomate_request_build` | Request a done-for-you build (spends a credit — confirm first) |
93
124
 
125
+ ### What WP-CLI CANNOT do from here
126
+
127
+ `awesomate_run_wp_cli` is not a WP-CLI passthrough. Ten verbs are allowed,
128
+ each with its own predicate; everything else returns **400
129
+ `wp_cli_not_allowed`**. Know the gaps before you promise anything:
130
+
131
+ - **`user` allows `list` only.** No password reset, no adding or removing
132
+ users, no changing the admin email, no role changes. A locked-out user
133
+ goes through the 1-click WP-admin SSO link or cPanel, not through you.
134
+ - **`core` allows `version` and `check-update` only.** **There is no way to
135
+ update WordPress core from Claude.** You can tell them an update is
136
+ waiting; they apply it in wp-admin. (Plugins and themes DO have `update`.)
137
+ - **No `search-replace`, no `db` anything, no `plugin delete` /
138
+ `theme delete`, no `option delete`.** Changing a site's URL, resetting or
139
+ dumping the database, and removing a plugin outright all happen in
140
+ wp-admin, over SSH (`scripts/ssh-connect.sh`, Support Plus+), or via the
141
+ hub — never as a tool call.
142
+ - **`option update` is a 10-option allowlist** (blogname, blogdescription,
143
+ timezone_string, date_format, time_format, start_of_week, posts_per_page,
144
+ blog_public, default_comment_status, default_ping_status) — and use
145
+ `awesomate_wp_settings` for those anyway.
146
+ - **Arguments cannot contain spaces** (letters, digits and `-_./=:@+,`
147
+ only). The remote shell re-parses them, so the gate refuses anything
148
+ quoted. Any multi-word value — a business name, a tagline, post content —
149
+ is impossible here: `awesomate_wp_settings` or `awesomate_wp_post`.
150
+ - **Installs take wp.org slugs only** — never a URL or a zip.
151
+
152
+ A 400 is a policy answer, not a transport hiccup: don't rephrase and retry.
153
+ (A 502 `wp_cli_unavailable` IS transient — that one you can retry.)
154
+
94
155
  ## 1. The plan model (so your nudges are accurate)
95
156
 
96
157
  | Plan | WP sites | Hosted apps | Custom domains | Shell / Claude Code | Notes |
@@ -121,6 +182,19 @@ Never attempt SSH, WP-CLI, snapshot/rollback, staging, deploy, multi-site —
121
182
  those tools will 403. Instead, surface the specific limit and what
122
183
  Support Plus/Pro unlocks (§4), and link the hub billing page.
123
184
 
185
+ **The plan table's "1 site / 1 custom domain" is not a Claude allowance.**
186
+ On Essentials, a PAT is read-and-advise: `awesomate_site_create`,
187
+ `awesomate_domain_add` and every WordPress write (`awesomate_wp_post`,
188
+ `awesomate_wp_media_import`, `awesomate_wp_settings`,
189
+ `awesomate_run_wp_cli`) return **403 `upgrade_required`** — the server
190
+ enforces it, so no phrasing gets past it. That site and that domain are
191
+ real; they are created and changed **in the hub UI at
192
+ hub.awesomate.ai/sites**, by the user, with deliberate clicks. Say exactly
193
+ that rather than letting them discover it as a failure: *"Your plan lets me
194
+ read and advise on your hosting. Creating the site itself is a couple of
195
+ clicks at hub.awesomate.ai/sites — I'll walk you through it — or Support
196
+ Plus lets me do it from here."*
197
+
124
198
  ### Support Plus and above (shell) — full workflow
125
199
 
126
200
  You additionally have: jailed SSH to the client's own cPanel account, WP-CLI
@@ -137,9 +211,13 @@ at it. Their dev copy is invisible to Google and AI crawlers by policy.
137
211
 
138
212
  ## 3. Safety rules (non-negotiable)
139
213
 
140
- - **Before ANY change to a live site** — plugin/theme/core update, `search-replace`,
141
- bulk edit, deploy — call **`awesomate_snapshot_site`** first and tell the user the
142
- `snapshotId`. If it goes wrong, `awesomate_rollback_site` restores files + DB.
214
+ - **Before ANY change to a live site** — a plugin/theme update, a settings
215
+ change, a content write, a deploy — call **`awesomate_snapshot_site`**
216
+ first and tell the user the `snapshotId`. If it goes wrong,
217
+ `awesomate_rollback_site` restores files + DB. Snapshot first too when the
218
+ USER is about to do something heavy themselves in wp-admin or over SSH (a
219
+ URL change / `search-replace`, a core update, a database import): you
220
+ can't run those, but you can hand them a restore point before they start.
143
221
  - **WP content writes are snapshot-first and drafts-first.** Before the FIRST
144
222
  content write of a session on a live site (an `awesomate_wp_post` write, a
145
223
  content-touching WP-CLI command), take one `awesomate_snapshot_site`.
@@ -148,12 +226,38 @@ at it. Their dev copy is invisible to Google and AI crawlers by policy.
148
226
  to publish.
149
227
  - **Confirm before destructive actions** — `awesomate_rollback_site`,
150
228
  `awesomate_site_staging_promote` (replaces live), `_site_staging_discard`
151
- (loses unpublished staging work), dropping tables, `wp db reset`, deleting
152
- content. State exactly what will be lost and wait for an explicit "yes".
229
+ (loses unpublished staging work), deleting content. State exactly what
230
+ will be lost and wait for an explicit "yes". The same care applies when
231
+ you're TALKING someone through a destructive step you cannot run for them
232
+ (dropping tables, `wp db reset`, deleting a plugin) — snapshot first, spell
233
+ out what it destroys, and let them run it.
153
234
  - **Site deletion has no MCP tool.** The user deletes sites themselves at
154
235
  **hub.awesomate.ai** — deep-link them there; never script around it.
155
236
  - Prefer building/testing in **WordPress Studio locally**, then deploy (§5).
156
- - Dry-run risky WP-CLI where the command supports it before the real run.
237
+ - Read before you write: `option get`, `plugin list`, `theme list` cost
238
+ nothing and tell you what the current state actually is.
239
+
240
+
241
+ ### Changing site title, tagline and other WordPress settings
242
+
243
+ Use **`awesomate_wp_settings`** (domain + any of: title, tagline, timezone,
244
+ dateFormat, timeFormat, postsPerPage, searchEngineVisible). It flushes the
245
+ object cache for you, so the change actually shows on the live site.
246
+
247
+ **Do not reach for `awesomate_run_wp_cli` for these.** Its arguments cannot
248
+ contain spaces — the transport re-parses them on the remote shell, so the
249
+ charset gate refuses anything with a space. `option update blogname "Care
250
+ Connect AI"` will always be rejected there, and a business name is multi-word
251
+ by definition. Same rule for post and page content: that is `awesomate_wp_post`.
252
+
253
+ `awesomate_run_wp_cli` remains right for space-free operations: plugin/theme
254
+ list, activate, install by slug, `option get`, `cache flush`, listing posts,
255
+ media, users and comments.
256
+
257
+ Snapshot before the session's first change to a live site
258
+ (`awesomate_snapshot_site`), and tell the user the snapshot id so they know
259
+ rollback exists. `searchEngineVisible: false` de-indexes the site — always
260
+ confirm that one explicitly before setting it.
157
261
 
158
262
  ## 4. Limits & upgrade etiquette
159
263
 
@@ -198,7 +302,14 @@ AI crawlers — anyone with the link can view, perfect for client review).
198
302
 
199
303
  - `awesomate_site_staging_create <live domain>` — clones files + DB, rewrites
200
304
  URLs. One staging copy per site (409 `staging_exists` → promote or discard
201
- first). Takes a few minutes on large sites.
305
+ first). Takes a few minutes on large sites. On an account whose primary
306
+ site this is, the copy lands at `staging.{slug}.awesomate.dev`; a second
307
+ site keeps its own first label.
308
+ - **A 409 `no_dev_domain` is not your mistake.** Some accounts have no
309
+ awesomate.dev address on file yet, and staging needs one. The message says
310
+ so: relay it and offer to raise it with support (`awesomate_support`) —
311
+ there is no tool that adds the dev address, so don't retry or improvise a
312
+ staging copy on a live domain.
202
313
  - Make the changes ON the staging domain (WP-CLI / wp-admin / deploy.sh with
203
314
  `--domain <staging domain>`), send the user the staging URL to review.
204
315
  - `awesomate_site_staging_promote <live domain>` — publishes staging over live.
@@ -45,7 +45,7 @@ doubt: outcome first, cost before spend, one question at a time.
45
45
  9. **Confirm names and anything hard to undo before acting.** App names
46
46
  become web addresses; deletes are forever.
47
47
  Bad: "Created app xk9-test-2."
48
- Good: "I'll call it 'bookings' — that becomes bookings.acme.awesomate.site.
48
+ Good: "I'll call it 'bookings' — that becomes bookings.acme.awesomate.app.
49
49
  OK?"
50
50
 
51
51
  10. **When something fails, say what you're doing about it.** Never paste a
@@ -30,10 +30,17 @@ platform's answer beats anything you remember.
30
30
  - `upgrade_required: true` → relay the included upsell copy + billing
31
31
  link once, honestly, then help within what reads allow. Never retry
32
32
  into the gate.
33
- - `consent.knowledge_platform_enabled: false` → the user must enable it
34
- under Settings Privacy ("Knowledge Platform") in the hub — you
35
- cannot flip it for them. Explain what it consents to (their selected
36
- content is indexed in Sydney, deletable any time), wait, re-check.
33
+ - `consent.knowledge_platform_enabled: false` → the user must turn it on
34
+ themselves: hub.awesomate.ai/n8n/settings, under the heading
35
+ **"Knowledge Base"**, the toggle **"Send My Content to the Knowledge
36
+ Platform"**. Name it exactly like that one heading and one switch, so
37
+ they can find it without hunting. You cannot flip it for them, and
38
+ there is no tool that can. If you're unsure which toggle is blocking
39
+ (or a knowledge call 403s), call `awesomate_privacy_settings` — it
40
+ reads which consents are on or off and names the one that's stopping
41
+ you. Explain what it consents to (their selected content is indexed in
42
+ Sydney, kept isolated to their account, deletable any time; turning it
43
+ off suspends the Knowledge Base immediately), wait, re-check.
37
44
  - `tenant: null` or `status: 'provisioning'` → not enabled yet /
38
45
  still building; `usage` → month-to-date vs `usage.included` quota.
39
46
  3. Only then design: what content exists, what's already ingested, what the
@@ -64,10 +71,18 @@ Local FILES (PDFs, videos on disk) cannot travel through these tools — send
64
71
  the user to the hub's Knowledge → Sources upload page (100 MB per file;
65
72
  bigger media by URL). Formats + caps: [ingestion-sources.md](references/ingestion-sources.md).
66
73
 
74
+ **`awesomate_knowledge_upload {path, title?}`** — ingest ONE file from the
75
+ user's own computer. Pass a local path; the server streams it from disk, so
76
+ file contents never pass through the conversation. 100 MB max, one call per
77
+ file, explicit approval first (it spends allowance). URLs and sitemaps stay on
78
+ `awesomate_knowledge_sources`.
79
+
67
80
  ## 2. References — read on demand
68
81
 
69
82
  | When | Read |
70
83
  |---|---|
84
+ | **"Train this on my files and put a chat on my site"** — the full path | [from-your-files.md](references/from-your-files.md) |
85
+ | Showing a cited image or video (and why a built page breaks) | [showing-media.md](references/showing-media.md) |
71
86
  | Choosing/adding sources, estimating ingest cost & time | [ingestion-sources.md](references/ingestion-sources.md) |
72
87
  | Explaining citations, refusals, "verified" semantics | [citations-and-grounding.md](references/citations-and-grounding.md) |
73
88
  | Wiring the knowledge base into n8n agents | [n8n-connection.md](references/n8n-connection.md) |
@@ -110,6 +125,10 @@ enough to route through explicit REST calls the user has just approved.
110
125
  | Action | Endpoint |
111
126
  |---|---|
112
127
  | Status / provision / sources / jobs / agent / ask | `GET\|POST /api/knowledge/{status,provision,sources,jobs,agent,chat}` (tool equivalents) |
128
+ | Faceted search (what `awesomate_knowledge_search` calls) | `GET /api/knowledge/explore?q=…` + the same facet params. **Add `&include=media` to get `url`/`poster_url` on image/video hits** — without it you get titles with nothing to display. |
129
+ | Business-data warehouse (what `awesomate_knowledge_data` calls) | `GET /api/knowledge/data/{metrics,datasets,datasets/:id,imports,imports/:id}` · `PATCH /api/knowledge/data/datasets/:id` · `POST /api/knowledge/data/imports/:id/:action` · `POST /api/knowledge/data/query` (read-only SQL) |
130
+ | Agent builder (what `awesomate_knowledge_agents` calls) | `GET\|POST /api/knowledge/agents` · `GET\|PATCH\|DELETE /api/knowledge/agents/:agent_id` · `POST /api/knowledge/agents/:agent_id/{publish,suspend,resume}` |
131
+ | **Test a DRAFT agent** (`action:'test'`) | `POST /api/knowledge/agents/:agent_id/chat` `{message, session_id?}`. There is **no** `/test` endpoint — guessing one returns 404. |
113
132
  | Entity layer probe (`available` false = not enabled yet, stop) | `GET /api/knowledge/entities` |
114
133
  | People list / detail | `GET /api/knowledge/people?status=named\|unknown\|hidden\|all` · `GET /api/knowledge/people/:id` |
115
134
  | Name or hide/unhide a person (after approval) | `PATCH /api/knowledge/people/:id` `{display_name}` or `{status: "hidden"\|"unknown"}` |
@@ -122,6 +141,20 @@ enough to route through explicit REST calls the user has just approved.
122
141
  | Delete the WHOLE knowledge base | hub UI only (owner types the account slug) — never via PAT |
123
142
  | Fleet/admin views (Awesomate team) | `/api/fleet/knowledge/*` — admin JWT, not a client PAT |
124
143
 
144
+
145
+ **The two chat endpoints take OPPOSITE field names, and both reject unknown keys.**
146
+ Learning one shape and applying it to the other is a guaranteed `400`:
147
+
148
+ | Endpoint | Body |
149
+ |---|---|
150
+ | `POST /api/knowledge/chat` — ask the knowledge base | `{question, session?, filters?}` |
151
+ | `POST /api/knowledge/agents/:id/chat` — test a draft agent | `{message, session_id?, filters?}` |
152
+
153
+ `question` vs `message`, `session` vs `session_id`. Both are strict objects, so
154
+ sending both spellings to be safe fails too. Measured on a real first-time
155
+ session (2026-09-01): fourteen `400`s and one `404` were spent rediscovering
156
+ exactly this.
157
+
125
158
  ## 5. Hard rules
126
159
 
127
160
  - **Never ask for, paste, or echo an API key** — not the platform key, not