@awesomate/hosting-mcp 0.20.6 → 0.20.8

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.
package/dist/index.js CHANGED
@@ -39754,13 +39754,13 @@ function findPinFile(startDir = process.cwd()) {
39754
39754
  }
39755
39755
  function profileList(profiles) {
39756
39756
  const names = Object.keys(profiles);
39757
- return names.length ? names.join(", ") : "(none \u2014 run Connect Claude Code from hub.awesomate.ai/sites)";
39757
+ return names.length ? names.join(", ") : "(none \u2014 run Connect Claude Code from hub.awesomate.ai/claude)";
39758
39758
  }
39759
39759
  function fromProfile(key, profile, source, credPath, pinPath, availableProfiles) {
39760
39760
  const pat = profile.pat ?? "";
39761
39761
  if (!pat.startsWith("amt_pat_")) {
39762
39762
  throw new Error(
39763
- `Profile "${key}" in ${credPath} has a malformed access token \u2014 re-run Connect Claude Code from hub.awesomate.ai/sites for this account.`
39763
+ `Profile "${key}" in ${credPath} has a malformed access token \u2014 re-run Connect Claude Code from hub.awesomate.ai/claude for this account.`
39764
39764
  );
39765
39765
  }
39766
39766
  return {
@@ -39804,7 +39804,7 @@ function loadConfig() {
39804
39804
  const profile = profiles[envAccount];
39805
39805
  if (!profile) {
39806
39806
  throw new Error(
39807
- `AWESOMATE_ACCOUNT="${envAccount}" has no matching profile in ${credPath}. Available profiles: ${profileList(profiles)}. Connect that account from hub.awesomate.ai/sites (logged in as it) to add its profile.`
39807
+ `AWESOMATE_ACCOUNT="${envAccount}" has no matching profile in ${credPath}. Available profiles: ${profileList(profiles)}. Connect that account from hub.awesomate.ai/claude (logged in as it) to add its profile.`
39808
39808
  );
39809
39809
  }
39810
39810
  return fromProfile(envAccount, profile, "env-account", credPath, null, available);
@@ -39819,7 +39819,7 @@ function loadConfig() {
39819
39819
  const profile = profiles[account];
39820
39820
  if (!profile) {
39821
39821
  throw new Error(
39822
- `This folder is pinned to account "${account}" (${pinPath}) but no matching profile exists in ${credPath}. Available profiles: ${profileList(profiles)}. Fix the pin, or connect "${account}" from hub.awesomate.ai/sites while logged into that account.`
39822
+ `This folder is pinned to account "${account}" (${pinPath}) but no matching profile exists in ${credPath}. Available profiles: ${profileList(profiles)}. Fix the pin, or connect "${account}" from hub.awesomate.ai/claude while logged into that account.`
39823
39823
  );
39824
39824
  }
39825
39825
  return fromProfile(account, profile, "pin", credPath, pinPath, available);
@@ -39833,7 +39833,7 @@ function loadConfig() {
39833
39833
  }
39834
39834
  if (available.length === 0) {
39835
39835
  throw new Error(
39836
- `No Awesomate access token found. Set AWESOMATE_PAT or run Connect Claude Code from hub.awesomate.ai/sites (it writes ${credPath}).`
39836
+ `No Awesomate access token found. Set AWESOMATE_PAT or run Connect Claude Code from hub.awesomate.ai/claude (it writes ${credPath}).`
39837
39837
  );
39838
39838
  }
39839
39839
  throw new Error(
@@ -39899,9 +39899,9 @@ async function hubRequest(config3, method, path, jsonBody, opts = {}) {
39899
39899
  const code = body && typeof body === "object" && "code" in body && typeof body.code === "string" ? body.code : null;
39900
39900
  let hint = "";
39901
39901
  if (res.status === 401) {
39902
- hint = " Your access token is invalid or expired \u2014 ask the user to open the hub Sites page (hub.awesomate.ai/sites), generate a fresh Connect prompt, and re-run the bootstrap.";
39902
+ hint = " Your access token is invalid or expired \u2014 ask the user to open the hub Claude page (hub.awesomate.ai/claude), generate a fresh Connect prompt, and re-run the bootstrap.";
39903
39903
  } else if (res.status === 403 && code === "consent_required") {
39904
- const settingsUrl = body && typeof body === "object" && "settingsUrl" in body && typeof body.settingsUrl === "string" ? body.settingsUrl : "https://hub.awesomate.ai/n8n/settings";
39904
+ const settingsUrl = body && typeof body === "object" && "settingsUrl" in body && typeof body.settingsUrl === "string" ? body.settingsUrl : "https://hub.awesomate.ai/settings?tab=privacy";
39905
39905
  hint = ` This needs a privacy toggle the user must flip themselves \u2014 send them to ${settingsUrl}, wait for them to confirm, then retry. Never suggest a plan upgrade for a consent denial.`;
39906
39906
  } else if (res.status === 403) {
39907
39907
  const missing = body && typeof body === "object" && "missingScopes" in body ? ` (missing: ${JSON.stringify(body.missingScopes)})` : "";
@@ -40572,11 +40572,12 @@ async function knowledgeAgents(config3, args) {
40572
40572
  if (args.goal) {
40573
40573
  const draft = await hubPost(config3, "/api/knowledge/agents/draft", { goal: args.goal });
40574
40574
  if (!draft.proposal) return { error: "draft_failed", detail: draft };
40575
- const created = await hubPost(config3, "/api/knowledge/agents", draft.proposal);
40576
- return { ...created, test_questions: draft.test_questions ?? [], status_note: "Created as a private DRAFT: test it, then publish when the user approves." };
40575
+ const body = { ...draft.proposal, ...args.audience ? { audience: args.audience } : {} };
40576
+ const created = await hubPost(config3, "/api/knowledge/agents", body);
40577
+ return { ...created, test_questions: draft.test_questions ?? [], status_note: `Created as a private DRAFT serving audience '${args.audience ?? "private"}': test it, then publish when the user approves.` };
40577
40578
  }
40578
40579
  if (!args.name) return { error: "name (or goal) is required for create" };
40579
- return await hubPost(config3, "/api/knowledge/agents", { name: args.name });
40580
+ return await hubPost(config3, "/api/knowledge/agents", { name: args.name, ...args.audience ? { audience: args.audience } : {} });
40580
40581
  }
40581
40582
  if (args.action === "publish") {
40582
40583
  if (!args.agentId) return { error: "agentId is required for publish" };
@@ -40770,7 +40771,7 @@ server.registerTool(
40770
40771
  "awesomate_get_context",
40771
40772
  {
40772
40773
  annotations: READ_ONLY,
40773
- description: "THE session entry point \u2014 call it FIRST, before any domain context. Returns the connected account: plan, capabilities, limits, scopes, token expiry, cPanel routing, PLUS `attention` ({unreadNotifications, erroringWorkflows7d, patExpiresInDays} \u2014 null means unknown, never zero; when something is non-zero, mention it to the user in one line before starting the asked task), `latestMcpVersion` (if serverVersion still lags it after a restart, the npx cache is stale \u2014 remedy: rm -rf ~/.npm/_npx, then restart), and `skill` ({updateAvailable, staleSkills, whatsNew} \u2014 if updateAvailable, mention ONCE with a whatsNew line, offer awesomate_skill_update, never mid-task). If the token is near expiry (patExpiresInDays < 7), re-running Connect Claude Code from hub.awesomate.ai/sites refreshes skills AND renews the token in one go.",
40774
+ description: "THE session entry point \u2014 call it FIRST, before any domain context. Returns the connected account: plan, capabilities, limits, scopes, token expiry, cPanel routing, PLUS `attention` ({unreadNotifications, erroringWorkflows7d, patExpiresInDays} \u2014 null means unknown, never zero; when something is non-zero, mention it to the user in one line before starting the asked task), `latestMcpVersion` (if serverVersion still lags it after a restart, the npx cache is stale \u2014 remedy: rm -rf ~/.npm/_npx, then restart), and `skill` ({updateAvailable, staleSkills, whatsNew} \u2014 if updateAvailable, mention ONCE with a whatsNew line, offer awesomate_skill_update, never mid-task). If the token is near expiry (patExpiresInDays < 7), re-running Connect Claude Code from hub.awesomate.ai/claude refreshes skills AND renews the token in one go.",
40774
40775
  inputSchema: {}
40775
40776
  },
40776
40777
  async () => {
@@ -41658,6 +41659,7 @@ server.registerTool(
41658
41659
  agentId: external_exports.string().max(64).optional().describe("get/publish/test: agent_id from list"),
41659
41660
  name: external_exports.string().max(80).optional().describe("create: blank draft with this name"),
41660
41661
  goal: external_exports.string().max(2e3).optional().describe("create: describe the agent and AI drafts it from the account content"),
41662
+ audience: external_exports.enum(["private", "internal", "public"]).optional().describe("create: who the agent serves \u2014 'public' for anything customers or a website will talk to (it then answers from sources marked public ONLY), 'internal' for the team, 'private' (default) for the owner's own tools. Widening later is a publish, so choose now."),
41661
41663
  message: external_exports.string().max(4e3).optional().describe("test: the question to ask the draft"),
41662
41664
  sessionId: external_exports.string().max(128).optional().describe("test: keep follow-ups in one thread")
41663
41665
  }
@@ -41804,7 +41806,7 @@ readTool(
41804
41806
  );
41805
41807
  readTool(
41806
41808
  "awesomate_privacy_settings",
41807
- "READ which privacy/consent toggles are on or off for this account \u2014 call it when a tool returns 403 consent_required so you can name the exact toggle instead of guessing. Toggles are changed ONLY by the user in the hub (n8n \u2192 Settings \u2192 Privacy, hub.awesomate.ai/n8n/settings); there is deliberately no write here.",
41809
+ "READ which privacy/consent toggles are on or off for this account \u2014 call it when a tool returns 403 consent_required so you can name the exact toggle instead of guessing. Toggles are changed ONLY by the user in the hub (Settings \u2192 Privacy, hub.awesomate.ai/settings?tab=privacy); there is deliberately no write here.",
41808
41810
  "/api/client-settings/privacy"
41809
41811
  );
41810
41812
  server.registerTool(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awesomate/hosting-mcp",
3
- "version": "0.20.6",
3
+ "version": "0.20.8",
4
4
  "description": "Awesomate MCP server — lets Claude manage your Awesomate WordPress hosting, plan, limits, n8n automations, and build Node/static apps + databases",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -1,5 +1,12 @@
1
1
  {
2
2
  "versions": [
3
+ {
4
+ "version": "0.20.7",
5
+ "highlights": [
6
+ "Your Knowledge Base can now go on your website: install the Verified Content Chat Agent from the hub Library and it answers visitors from the agent you published, with sources on every reply",
7
+ "Fixed: a credential Awesomate creates in your n8n now shows up immediately in the list Claude reads, instead of after the weekly refresh"
8
+ ]
9
+ },
3
10
  {
4
11
  "version": "0.20.6",
5
12
  "highlights": [
@@ -78,7 +78,7 @@ inventory (`awesomate_n8n_inspect {what:'credentials'}`) and say e.g. *"you alre
78
78
  have Gmail connected in n8n — want the form to email you through that?"*
79
79
  That read is **consent-gated**: it needs the **"Allow Claude Code to Build
80
80
  n8n Workflows"** toggle (n8n → Settings → Privacy,
81
- hub.awesomate.ai/n8n/settings; also on hub.awesomate.ai/n8n/settings),
81
+ hub.awesomate.ai/settings?tab=privacy; also on hub.awesomate.ai/settings?tab=privacy),
82
82
  which is **off by default** — so on a fresh account it comes back 403
83
83
  `consent_required`. That's not a failure to work around: call
84
84
  `awesomate_privacy_settings` to name the exact toggle, ask the user to flip
@@ -68,7 +68,7 @@ credentials are already connected there, so there's nothing new to set up.
68
68
  sheet?"* That read needs the **"Allow Claude Code to Build n8n Workflows"**
69
69
  privacy toggle, which is off by default — a 403 `consent_required` means
70
70
  call `awesomate_privacy_settings`, name the toggle, and ask the user to flip
71
- it at hub.awesomate.ai/n8n/settings.
71
+ it at hub.awesomate.ai/settings?tab=privacy.
72
72
  - Build the workflow with the **awesomate-n8n** skill (webhook trigger →
73
73
  action), take its **webhook URL**, and wire it into the app.
74
74
  - **Node app:** `awesomate_n8n_attach_to_app` — it stores
@@ -123,7 +123,7 @@ A secret for an n8n workflow belongs on the n8n instance (awesomate-n8n
123
123
  skill), never in an app `.env`. Those tools are consent-gated: if one comes
124
124
  back 403 `consent_required`, call `awesomate_privacy_settings` — it names
125
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
126
+ hub.awesomate.ai/settings?tab=privacy instead of guessing. You can't flip it
127
127
  for them.
128
128
 
129
129
  ## Fallback: the file-drop flow
@@ -28,8 +28,8 @@ automation-shaped. Inspect what exists with
28
28
  `awesomate_n8n_inspect {what:'datatables'}`.
29
29
  **Both the write AND that read are gated:** Support Plus or above, plus the
30
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
31
+ Settings → Privacy (hub.awesomate.ai/settings?tab=privacy, or the same toggles at
32
+ hub.awesomate.ai/settings?tab=privacy, which is what the 403's
33
33
  `settingsUrl` points at). It is **off by default**, so on a fresh account
34
34
  both the read and the write come back 403 `consent_required`. Call
35
35
  `awesomate_privacy_settings` to name the exact toggle that's off, send the
@@ -46,7 +46,7 @@ once (plus `awesomate_get_limits` before any create/change) and cache:
46
46
  asked task, then get on with the task. `null` means unknown, never zero —
47
47
  say nothing on null.
48
48
  - **`patExpiresAt`** — within ~7 days, or any 401: re-run the setup prompt at
49
- **hub.awesomate.ai/sites → Connect Claude Code** to refresh the token.
49
+ **hub.awesomate.ai/claude → Connect Claude Code** to refresh the token.
50
50
  - **`skill.updateAvailable`** — covers all nine skills; the local files are
51
51
  older than the MCP server. Mention it ONCE per session, with the what's-new
52
52
  line the context includes, and offer to run `awesomate_skill_update`. Its
@@ -115,7 +115,7 @@ proxy failures, resuming a connect, support report) ·
115
115
  | `awesomate_wp_post` | Create/update/read a WP post or page — drafts by default (writes are Support Plus+) |
116
116
  | `awesomate_wp_media_import` | Pull an image/file into the WP media library from an https URL (Support Plus+) |
117
117
  | `awesomate_uninstall_site` | Remove a WordPress install (destructive — confirm explicitly) |
118
- | `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) |
118
+ | `awesomate_privacy_settings` | Read which privacy/consent toggles are on — explain a 403 `consent_required` precisely (the user flips toggles themselves under Settings → Privacy at hub.awesomate.ai/settings?tab=privacy) |
119
119
  | `awesomate_notifications` | The hub notification bell — `list` unread (quota warnings, quote ready, support-access events), `read`/`read_all` to clear |
120
120
  | `awesomate_dashboard_metrics` | Account-wide numbers: executions by status, error rate, time saved, chat sessions, 7-day trend |
121
121
  | `awesomate_account_report` | A monthly-report-shaped read: working / not working / engagement / commercials |
@@ -67,7 +67,7 @@ if (process.argv.includes('--update')) {
67
67
  }
68
68
 
69
69
  if (!resumePat && (!code || !code.startsWith('amt_bs_'))) {
70
- console.error('Missing/invalid --code. Copy a fresh setup prompt from hub.awesomate.ai/sites (or resume with --pat if you already hold a token).');
70
+ console.error('Missing/invalid --code. Copy a fresh setup prompt from hub.awesomate.ai/claude (or resume with --pat if you already hold a token).');
71
71
  console.error('AWESOMATE CONNECT: FAILED reason=bad-code');
72
72
  process.exit(1);
73
73
  }
@@ -596,7 +596,7 @@ async function main() {
596
596
  main().catch((err) => {
597
597
  console.error('Bootstrap failed:', err.message);
598
598
  if (err.isApiError && err.status === 401) {
599
- console.error('Grab a fresh code from hub.awesomate.ai/sites — codes last 10 minutes (and stay re-runnable within that window).');
599
+ console.error('Grab a fresh code from hub.awesomate.ai/claude — codes last 10 minutes (and stay re-runnable within that window).');
600
600
  }
601
601
  console.error(SUPPORT_HINT);
602
602
  console.error('AWESOMATE CONNECT: FAILED reason=error');
@@ -25,7 +25,7 @@
25
25
  set -euo pipefail
26
26
 
27
27
  CRED="$HOME/.awesomate/credentials.json"
28
- [ -f "$CRED" ] || { echo "Not connected — run the Connect Claude Code setup from hub.awesomate.ai/sites first."; exit 1; }
28
+ [ -f "$CRED" ] || { echo "Not connected — run the Connect Claude Code setup from hub.awesomate.ai/claude first."; exit 1; }
29
29
 
30
30
  FROM="" DOMAIN="" DOCROOT="" LOCAL_URL="" LIVE_URL="" WITH_DB=0 ASSUME_YES=0
31
31
  while [ "$#" -gt 0 ]; do
@@ -11,7 +11,7 @@
11
11
  set -euo pipefail
12
12
 
13
13
  CRED="$HOME/.awesomate/credentials.json"
14
- [ -f "$CRED" ] || { echo "Not connected — run the Connect Claude Code setup from hub.awesomate.ai/sites first."; exit 1; }
14
+ [ -f "$CRED" ] || { echo "Not connected — run the Connect Claude Code setup from hub.awesomate.ai/claude first."; exit 1; }
15
15
 
16
16
  DOMAIN="" TO="" DOCROOT=""
17
17
  while [ "$#" -gt 0 ]; do
@@ -70,7 +70,7 @@ if (process.env.AWESOMATE_ACCOUNT) {
70
70
  if (!profiles[key]) {
71
71
  fail(
72
72
  `This folder is pinned to account "${key}" (${pinPath}) but no matching profile exists in ${credPath}. ` +
73
- `Available: ${names.join(', ') || '(none)'}. Connect "${key}" from hub.awesomate.ai/sites (logged in as it) or fix the pin.`,
73
+ `Available: ${names.join(', ') || '(none)'}. Connect "${key}" from hub.awesomate.ai/claude (logged in as it) or fix the pin.`,
74
74
  );
75
75
  }
76
76
  } else if (names.length === 1) {
@@ -78,7 +78,7 @@ if (process.env.AWESOMATE_ACCOUNT) {
78
78
  } else if (file.defaultProfile && profiles[file.defaultProfile]) {
79
79
  key = file.defaultProfile;
80
80
  } else if (names.length === 0) {
81
- fail('Not connected. Run the Connect Claude Code setup from hub.awesomate.ai/sites.');
81
+ fail('Not connected. Run the Connect Claude Code setup from hub.awesomate.ai/claude.');
82
82
  } else {
83
83
  fail(
84
84
  `Multiple accounts are connected (${names.join(', ')}) and this folder isn't pinned to one. ` +
@@ -6,7 +6,7 @@
6
6
  # ssh-connect.sh 'wp --info' # one-off command
7
7
  set -euo pipefail
8
8
  CRED="$HOME/.awesomate/credentials.json"
9
- [ -f "$CRED" ] || { echo "Not connected. Run bootstrap first (Connect Claude Code on hub.awesomate.ai/sites)."; exit 1; }
9
+ [ -f "$CRED" ] || { echo "Not connected. Run bootstrap first (Connect Claude Code on hub.awesomate.ai/claude)."; exit 1; }
10
10
 
11
11
  # Resolve WHICH account (folder pin / AWESOMATE_ACCOUNT / sole profile) and its
12
12
  # ssh block via the shared resolver. Capture then eval so a resolver failure
@@ -31,7 +31,7 @@ platform's answer beats anything you remember.
31
31
  link once, honestly, then help within what reads allow. Never retry
32
32
  into the gate.
33
33
  - `consent.knowledge_platform_enabled: false` → the user must turn it on
34
- themselves: hub.awesomate.ai/n8n/settings, under the heading
34
+ themselves: hub.awesomate.ai/settings?tab=privacy, under the heading
35
35
  **"Knowledge Base"**, the toggle **"Send My Content to the Knowledge
36
36
  Platform"**. Name it exactly like that — one heading and one switch, so
37
37
  they can find it without hunting. You cannot flip it for them, and
@@ -62,7 +62,7 @@ platform's answer beats anything you remember.
62
62
  | Instant search with facet counts (find WHAT is in there: moments, pages, datasets; free) | `awesomate_knowledge_search` |
63
63
  | Ask a question → verified answer + numbered sources (accepts the same facet `filters` to ask within a slice) | `awesomate_knowledge_ask` |
64
64
  | Agent persona / fallback message / model tier — get & set (the single workspace default) | `awesomate_knowledge_agent` |
65
- | Agent BUILDER: list / get / create (AI-drafted from their content, saved as a private draft) / test the draft / publish (explicit approval first) | `awesomate_knowledge_agents` |
65
+ | Agent BUILDER: list / get / create (AI-drafted from their content, saved as a private draft; pass `audience:'public'` for anything customers will talk to — it then answers from sources marked public ONLY) / test the draft / publish (explicit approval first) | `awesomate_knowledge_agents` |
66
66
  | People, places, topics: list / name / hide / merge / alias suggestions / re-run resolution | `awesomate_knowledge_people` |
67
67
  | Business-data warehouse: `metrics` / `datasets` / `query` / `imports` — answer quantitative questions from their own imported business data (query is free-form but read-only) | `awesomate_knowledge_data` |
68
68
  | Refresh these skills from the latest package | `awesomate_skill_update` |
@@ -83,10 +83,20 @@ before a customer sees it. Show the citations.
83
83
 
84
84
  ## 5. Draft the agent
85
85
 
86
- `awesomate_knowledge_agents {action:'create', goal}` — describe what the agent
87
- is for and the platform drafts instructions, scope, tone and test questions
88
- from the account's own content. It saves as a **private draft**; nothing is
89
- live and nothing is lost.
86
+ `awesomate_knowledge_agents {action:'create', goal, audience}` — describe what
87
+ the agent is for and the platform drafts instructions, scope, tone and test
88
+ questions from the account's own content. It saves as a **private draft**;
89
+ nothing is live and nothing is lost.
90
+
91
+ **`audience` is the retrieval ceiling, and it is enforced.** `public` for
92
+ anything customers or a website will talk to: the agent then answers from
93
+ sources marked public ONLY, whatever key runs it. `internal` for the team
94
+ (internal + public sources). `private` (the default) for the owner's own
95
+ tools. A source's own visibility is set at upload (`visibility` on
96
+ `awesomate_knowledge_upload` / `sources add`) or in the hub Library; a public
97
+ agent over a library with nothing marked public answers nothing — say so
98
+ before building, and get the owner to mark the customer-facing sources public
99
+ first. Widening an agent later is a publish, so choose now.
90
100
 
91
101
  Then `{action:'test', agentId, message}` — free and unmetered, and the right
92
102
  way to check behaviour. Test the awkward cases: something out of scope, a
@@ -106,10 +116,12 @@ Two destinations. Ask which they want; do not assume.
106
116
 
107
117
  **A chat on their existing website — via n8n.** This is usually the right
108
118
  answer, and the plumbing is already provisioned. See
109
- `references/n8n-connection.md`: the hub creates the scope credential and the
110
- `knowledge_answer` tool. Build the workflow with the awesomate-n8n skill
111
- (Chat Trigger or Webhook -> AI Agent with the `knowledge_answer` tool ->
112
- Respond), test it, promote it, and give them the webhook URL to embed. Read
119
+ `references/n8n-connection.md` §3: they install the **Verified Content Chat
120
+ Agent** card from the hub Library (`/templates`); it runs the agent they
121
+ published, publishes on install, and the Chat URL goes into the embed
122
+ snippet. Only when they want their OWN agent node (extra tools, a different
123
+ model) build it with the awesomate-n8n skill instead — Chat Trigger -> AI
124
+ Agent with the `knowledge_answer` library tool -> Respond — and read
113
125
  `awesomate-n8n/references/ai-agents.md` before designing the agent node.
114
126
 
115
127
  **A standalone page or app — via the app builder.** When they want a hosted
@@ -34,18 +34,45 @@ their own agent on top and accept ungated composition.
34
34
 
35
35
  ## 3. The bundle — "Verified Content Chat Agent"
36
36
 
37
- One redeem token installs: the public chat webhook workflow (speaks the
38
- `@n8n/chat` embed widget contract), a Setup Tool sub-workflow, and the
39
- "Knowledge Bot Setup" Chat Hub agent whose FIRST action is a connection
40
- check that reads back "connected to <business name>'s knowledge base with
41
- N sources" the human confirmation the scope is right. Every `kb_*`
42
- variable has a fallback: zero config to first reply.
43
-
44
- Flow you drive: confirm the knowledge base is active with indexed content →
45
- redeem the bundle token (the user gets it from Awesomate) via the hub's
46
- Templates page or `POST /api/client-settings/redeem {token}` → hand the
47
- user to "Knowledge Bot Setup" in Chat Hub for greeting/name/origins → the
48
- setup agent activates and tests the bot and hands over the embed snippet.
37
+ One library card installs the public chat workflow that speaks the
38
+ `@n8n/chat` embed widget contract. There is **no AI Agent node in it**: the
39
+ agent the member published in the hub (Knowledge Agents) IS the agent —
40
+ its system message, grounding mode, scope and no-answer message run on the
41
+ platform, and n8n only relays. Chat Trigger `POST /v1/answer` with
42
+ `agent_id` (scope credential above) → a Code node that renders the N1
43
+ contract (§4) → the widget.
44
+
45
+ Variables (all read from `$vars`, all with fallbacks):
46
+
47
+ - `kb_agent_id` **set automatically at install** when the member has
48
+ exactly one published, unsuspended agent. Two or more is their choice:
49
+ preflight lists it as manual setup and the value is the agent id shown in
50
+ the hub. Unset, `/v1/answer` falls back to the tenant's default agent.
51
+ - `kb_allowed_origins` — the website origin (CORS). Default: any.
52
+ - `kb_fallback_message` — shown only when the platform itself could not be
53
+ reached (401/429/timeout). A verified "no answer" shows the agent's own
54
+ no-answer message, never this.
55
+
56
+ Flow you drive: confirm the knowledge base is active with indexed content and
57
+ one published agent → the member installs the bundle from the hub's
58
+ **Library** page (`/templates`, card "Verified Content Chat Agent"; a redeem
59
+ token via `POST /api/client-settings/redeem {token}` also works if Awesomate
60
+ hands one over) → the workflow publishes on install once the scope credential
61
+ is verified → open "When chat message received", copy the **Chat URL**, and
62
+ give them the embed snippet (it is also in the workflow's HOW IT WORKS note):
63
+
64
+ ```html
65
+ <link href="https://cdn.jsdelivr.net/npm/@n8n/chat/dist/style.css" rel="stylesheet" />
66
+ <script type="module">
67
+ import { createChat } from 'https://cdn.jsdelivr.net/npm/@n8n/chat/dist/chat.bundle.es.js';
68
+ createChat({ webhookUrl: '<the Chat URL>' });
69
+ </script>
70
+ ```
71
+
72
+ Not yet shipped (do not promise them): a "Knowledge Bot Setup" Chat Hub
73
+ agent that walks the member through greeting/name/origins, and the hosted
74
+ widget with a per-site install flow. Until then the sticky notes in the
75
+ workflow are the setup guide.
49
76
 
50
77
  If the member already has their own agent workflow, attach the
51
78
  `knowledge_answer` tool from the library to it instead — same credential,
@@ -30,11 +30,11 @@ as outcomes ("your form now emails you") with URLs.
30
30
  2. `awesomate_n8n_context` — cache the result:
31
31
  - `consented: false` → give the user the `settingsUrl` and tell them
32
32
  where it lands: **n8n → Settings → Privacy** at
33
- `hub.awesomate.ai/n8n/settings` → "Allow Claude Code to Build n8n
33
+ `hub.awesomate.ai/settings?tab=privacy` → "Allow Claude Code to Build n8n
34
34
  Workflows". Privacy moved there; the plain `/settings` page no longer
35
35
  has it (old `?tab=privacy` links just redirect). Wait, then re-check.
36
36
  - `403 missingScopes` → token predates n8n support — reconnect from
37
- hub.awesomate.ai/sites (Connect Claude Code card).
37
+ hub.awesomate.ai/claude (Connect Claude Code card).
38
38
  - `capabilities.builder: false` → reads only; building is Support Plus+.
39
39
  Be honest about it once, then help fully within reads.
40
40
  - `capabilities.variant` → FFMPEG variants have the media community
@@ -82,7 +82,7 @@ use it to explain and prioritise, not as a substitute for your own diagnosis
82
82
  of the execution data. On a 403, the plan or the toggle is the reason —
83
83
  `awesomate_privacy_settings` (hosting skill) tells you which; the user flips
84
84
  toggles themselves under **n8n → Settings → Privacy** at
85
- hub.awesomate.ai/n8n/settings — the one for this tool is labelled
85
+ hub.awesomate.ai/settings?tab=privacy — the one for this tool is labelled
86
86
  **"Enable AI Error Diagnosis"**.
87
87
 
88
88
  ## 5. What to do when you inherit a workflow with no plan
@@ -74,7 +74,7 @@ trust this file.
74
74
  real error. Use it instead of guessing from the summary. It is gated on
75
75
  the client's `error_content_analysis` privacy toggle (default OFF) — on
76
76
  a consent refusal, ask the user to enable it under **n8n → Settings →
77
- Privacy** at `hub.awesomate.ai/n8n/settings` (Privacy moved off the plain
77
+ Privacy** at `hub.awesomate.ai/settings?tab=privacy` (Privacy moved off the plain
78
78
  `/settings` page; old `?tab=privacy` links redirect there);
79
79
  never work around the gate.
80
80
 
@@ -62,7 +62,7 @@ the conversation or logs.
62
62
  - `403 consent_required` + `flag` + `settingsUrl` → relay the link, re-check
63
63
  after the user toggles (a null `settingsUrl` means contact support).
64
64
  - `403 missingScopes` → token predates n8n support — reconnect from
65
- hub.awesomate.ai/sites.
65
+ hub.awesomate.ai/claude.
66
66
  - `429 quota_exceeded` → the plan's daily cap; stop, don't retry-loop.
67
67
  - `503 node_catalog_unavailable` → use `references/vendor/` knowledge.
68
68
  - `404` on a path in this table → check the path against this file
@@ -49,9 +49,9 @@ rebuilt (a rebuilt instance shows 0 workflows and invalidates every old key).
49
49
  5. `awesomate_n8n_executions {executionId, debug: true}` — node-level output
50
50
  data. Requires `error_content_analysis` consent:
51
51
  - `403 consent_required` → give the user the `settingsUrl` from the error
52
- response and stop; they enable it under **n8n → Settings → Privacy** at
53
- `hub.awesomate.ai/n8n/settings` (the plain `/settings` page no longer
54
- carries Privacy; old `?tab=privacy` links redirect there).
52
+ response and stop; they enable it under **Settings → Privacy** at
53
+ `hub.awesomate.ai/settings?tab=privacy` (old `/n8n/settings?section=privacy`
54
+ links redirect there).
55
55
  - `tooLarge: true` → payload over 15MB. Use the summary in the response;
56
56
  do NOT retry hoping for the full payload.
57
57
  6. Node behaving strangely rather than erroring → check its schema with
@@ -135,7 +135,7 @@ to the Awesomate team, who scope, build, test, and deliver it.
135
135
  to do rather than opening a ticket.
136
136
  - **A 403 that mentions consent is a toggle, not a bug.** Call
137
137
  `awesomate_privacy_settings` to see exactly which toggle is off, name it,
138
- and send them to hub.awesomate.ai/n8n/settings. You cannot flip it
138
+ and send them to hub.awesomate.ai/settings?tab=privacy. You cannot flip it
139
139
  for them, and there is deliberately no tool that can.
140
140
 
141
141
  ## 6. Hard rules