Skip to content
91 changes: 91 additions & 0 deletions apps/cli/ai/skills/hosting-plans-helper/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
name: hosting-plans-helper
description: Answer WordPress.com plan, pricing, upgrade, and feature-tier questions (plan names, what each tier unlocks — plugins, themes, custom code, SSH, hosting — and current prices) from authoritative live data. Load before answering ANY plan, pricing, or feature-gating question; never answer these from memory.
user-invokable: true
---

# Hosting Plans Helper

Use this skill whenever the user asks about WordPress.com (or Pressable) plans,
pricing, upgrades, or what a plan tier unlocks — for example "which plan do I need
for plugins?", "what does Business include?", "how much is Commerce?", "can I use
custom CSS on Premium?", or "should I upgrade?".

## Hard rule: never answer from memory

Plan names, prices, and feature-tier gating change, and your training data is stale.
You MUST fetch current data with this skill before answering. Do not state a plan
name, a price, or which tier unlocks a feature from memory — even if you are
confident. If the fetch fails, say you can't verify current plan data right now and
point the user to https://wordpress.com/pricing; do not guess.

## Step 1: Fetch plan names and features

Fetch `wpcom/v2/plans/features`. It returns, per plan, the current `name`, the
`product_slug` (used to look up the price in Step 2), and the full list of `features`
that tier unlocks — grouped (Essential features, Performance boosters, High
Availability, Developer tools, Security, etc.).

**Local sites (Bash tool available):**

```text
curl -s "https://public-api.wordpress.com/wpcom/v2/plans/features?locale=en"
```

**Connected WordPress.com sites (wpcom_request tool available, no Bash):**

```text
wpcom_request method=GET path="!/plans/features" apiNamespace="wpcom/v2"
```

## Step 2: Fetch current prices

Fetch `wpcom/v2/products` for prices. It is keyed by product slug; each product has a
`cost_display` (the formatted, **already-localized** price, e.g. `"$300"`) and a
`currency_code`.

**Local sites:**

```text
curl -s "https://public-api.wordpress.com/wpcom/v2/products"
```

**Connected WordPress.com sites:**

```text
wpcom_request method=GET path="!/products" apiNamespace="wpcom/v2"
```

Both endpoints are public (no authentication) and both are reachable in either
environment.

## Step 3: Answer from the fetched data only

- Use the exact plan **names** from Step 1 — do not rename or substitute legacy
names.
- For a plan's **price**, look up `products[ plan.product_slug ].cost_display` and
quote it as-is (it is already localized; mention the currency). The free plan has
no price.
- To answer "does plan X include feature Y?" or "what do I need for Y?", check the
per-plan `features` list from Step 1. Each feature has a `title`, a `tooltip` (use
it to explain), and a `group`. Recommend the lowest tier whose `features` includes
what the user needs.
- When recommending an upgrade, name the specific tier and the concrete features it
unlocks for the user's stated goal.

### Phrasing

Answer directly and authoritatively, as plain product knowledge. Do not mention that
you fetched anything, or reference "the live data", "the data I fetched", "according
to the API", or any source or tool. The fetched data is simply the truth — state it.

- Yes: "Plugins are supported on the Personal plan and above."
- No: "Based on the live data I just fetched, plugins are supported on Personal and
above."

## Scope

Currently covers the WordPress.com consumer plans (Free, Personal, Premium,
Business, Commerce). If the user asks about a plan or product not in the response
(e.g. Pressable, Woo Hosted, VIP, enterprise), say it's not covered by this data and
point them to https://wordpress.com/pricing rather than answering from memory.
4 changes: 4 additions & 0 deletions apps/cli/ai/system-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function buildRemoteIntro( site: RemoteSiteContext ): string {
IMPORTANT: The active site is a remote WordPress.com site: "${ site.name }" (ID: ${ site.id }) at ${ site.url }.
IMPORTANT: You MUST use the wpcom_request tool to manage this site. Do NOT use WP-CLI, Bash, or local site file operations — this site is hosted on WordPress.com and cannot be modified through the local filesystem. You may use local Read/Write/Edit/Ls for temporary working files within Studio app data; those files do not affect the remote site until passed to wpcom_request.
IMPORTANT: Before doing ANY work, you MUST first check the site's plan by calling \`GET /\` (apiNamespace: \`""\`). The \`plan.product_slug\` field indicates the plan. If the site is on a free plan (e.g. \`free_plan\`), you MUST refuse design customization requests — this includes custom CSS, inline styles, style attributes on blocks, global styles editing, custom JavaScript, animations, custom colors/fonts/layouts, and plugin management. Do NOT attempt workarounds like inline styles or style block attributes — these produce invalid blocks on WordPress.com. Instead, tell the user that design customizations require upgrading to a paid WordPress.com plan and STOP. Do not proceed with the design task.
IMPORTANT: ${ PLAN_DATA_GUARDRAIL }

## Available Tools

Expand Down Expand Up @@ -95,6 +96,7 @@ ${ getStudioWidgetPromptManifest() }`
return `${ AGENT_IDENTITY } You manage and modify local WordPress sites using your Studio tools and generate content for these sites.

IMPORTANT: You MUST use your Studio tools to manage WordPress sites. Never create, start, or stop sites using Bash commands, shell scripts, or manual file operations. Never run \`wp\` commands via Bash — always use the wp_cli tool instead. The Studio tools handle all server management, database setup, and WordPress provisioning automatically.
IMPORTANT: ${ PLAN_DATA_GUARDRAIL }
IMPORTANT: For any generated content for the site, these three principles are mandatory:

- Gorgeous design: Load the \`visual-design\` skill for site creation, redesign, layout, style, CSS, typography, color, or motion work. To verify and polish the rendered result, load the \`visual-polish\` skill.
Expand Down Expand Up @@ -233,6 +235,8 @@ const REMOTE_DESIGN_GUIDELINES = `## Design capabilities by plan
- Custom CSS, global styles, plugin management, and advanced customization become available.
- Check the specific plan to determine exact capabilities.`;

const PLAN_DATA_GUARDRAIL = `For ANY question about WordPress.com or Pressable plans, pricing, upgrades, or what a plan tier includes (plugins, themes, custom code, SSH, hosting, storage, etc.), you MUST load the \`hosting-plans-helper\` skill and answer only from the data it fetches. Do NOT answer from memory: your training knowledge of plan names, prices, and feature-tier gating is stale and frequently wrong. In particular, do not claim a tier lacks a feature (e.g. that Personal or Premium cannot install plugins) based on memory — check the fetched per-tier feature list, which is the only source of truth. If you cannot fetch the data, say you cannot verify current plan details and point the user to https://wordpress.com/pricing; never guess.`;

const LOCAL_SKILL_ROUTING = `## Skill routing

For any site creation, redesign, landing page, homepage, layout, style, CSS, typography, color, or motion work, load the \`visual-design\` skill before writing design files or block markup.
Expand Down
16 changes: 16 additions & 0 deletions apps/cli/ai/tests/system-prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,22 @@ describe( 'buildSystemPrompt', () => {
expect( prompt ).not.toContain( '## Common wp/v2 Endpoints' );
} );

it( 'guards plan/pricing/feature answers behind the hosting-plans-helper skill (local)', () => {
const prompt = buildSystemPrompt( { chatArtifactsEnabled: true } );

expect( prompt ).toContain( '`hosting-plans-helper` skill' );
expect( prompt ).toContain( 'Do NOT answer from memory' );
expect( prompt ).toContain( 'Personal or Premium cannot install plugins' );
} );

it( 'guards plan/pricing/feature answers behind the hosting-plans-helper skill (remote)', () => {
const prompt = buildSystemPrompt( { remoteSite } );

expect( prompt ).toContain( '`hosting-plans-helper` skill' );
expect( prompt ).toContain( 'Do NOT answer from memory' );
expect( prompt ).toContain( 'Personal or Premium cannot install plugins' );
} );

it( 'references only bundled skills', () => {
const prompts = [
buildSystemPrompt( { chatArtifactsEnabled: true } ),
Expand Down
Loading