---
name: embed-widget
description: Embed the PinAppAI widget snippet into an EXISTING project's site, then bootstrap the iteration boundary marker. Use this when the project already exists in PinAppAI and you just need to wire up the widget on the customer's site (the equivalent of clicking "Copy embed prompt for AI" in the admin UI). For brand-new projects, use /pinappai:setup-project instead — that creates the project first.
arguments: []
---
# Embed the PinAppAI widget into this site

You're adding the PinAppAI feedback widget to a site whose project already
exists in PinAppAI. The flow:
**(resolve project) → (embed snippet) → (bootstrap marker) → (land changes)**.

Compare this to `/pinappai:setup-project`, which is a strict superset:
that one *creates* the project first, then runs these same steps. Use this
prompt when the project is already there (created via the admin UI or via
`create_project` in a previous session).

## Step 1 — Resolve the project

{{include: _shared/project-resolution.md}}

Once you have the resolved slug, call `get_project({project: "<resolved
slug>"})` to fetch the project's `project_key` (a `pk_…` value, 28
chars). It's what goes into `data-project="…"` in the snippet. The
field is also returned as `api_key` in the response for back-compat —
same value, legacy name. **Never confuse it with your MCP `ppk_…`
credential** — that's a privileged workspace key for tool calls only.

**Do NOT echo the full `project_key` value in your chat reply.** It's
public-by-design (it ships in every customer page's HTML; CORS gates
abuse via the project's `allowed_origins`), so this is not a security
leak — but the string LOOKS like a secret and surfaces noise the user
doesn't need to see. Refer to it by name (`project_key`, `the project's
pk_… key`) when explaining what you're doing; substitute the actual
value silently when you write it to the source file. The user can
always find the value in the admin UI if they need it.

## Step 2 — Embed the widget snippet

{{include: _shared/widget-snippet.md}}

Substitute the placeholder with the `project_key` returned by
`get_project` in Step 1 — the substitution happens in the file write,
NOT in your chat output.

**Do NOT wrap the script tag in an environment conditional** (e.g.
`{import.meta.env.PROD && …}` in Astro, `process.env.NODE_ENV ===
'production'` in Next.js, etc.). The widget must load in both
development and production so the reviewer can test their changes
locally before pushing. If a customer specifically wants dev-time
suppression, they can add the gate themselves later — default install
is unconditional.

How to install:

  1. Detect the framework from the repo (Astro / Next.js / SvelteKit / Eleventy
     / Hugo / WordPress / plain HTML / etc.). Look for a single shared layout
     or root template — the snippet should appear on every public page
     automatically, NOT scattered across individual pages.
  2. Embed the snippet ONCE in the most idiomatic shared location:
     base layout, root template, or footer partial. Place it just before
     `</body>` if the framework lets you target that.
  3. Skip non-public pages: admin / login / signup / 404 / API routes —
     reviewers don't need the widget there.
  4. If you cannot determine a single shared place, ASK which page set
     should carry the widget rather than scattering the snippet across
     individual pages.

If the framework emits the widget URL through a config (env var, CMS
setting, plugin config), set the config rather than hand-editing rendered
HTML — that survives template regeneration.

The `defer` attribute is required — the ~106KB widget bundle would block
HTML parsing without it.

### Step 2b — Permissions-Policy audit

{{include: _shared/permissions-policy-audit.md}}

## Step 3 — Bootstrap the iteration boundary marker

If `.pinappai/last-applied.json` already exists in the customer's repo,
SKIP this step — the marker is already set up from a prior install or
apply run, and overwriting it would clobber the iteration boundary.
Surface that to the user: "Marker already exists; not touching."

If `.pinappai/last-applied.json` does NOT exist:

{{include: _shared/marker-write.md}}

Use the bootstrap variant (file doesn't exist yet → write with the `note`
field). The bootstrap timestamp will be overwritten on the first
`/pinappai:apply` run (or a legacy fix-changes / apply-decisions run);
until then it just establishes the baseline so the first `/changes/`
regen has something to diff from.

## Step 3b — Review link

{{include: _shared/review-link-offer.md}}

(`get_project` from Step 1 already told you whether `primary_origin` is
set — don't re-fetch.)

## Step 4 — Land the install changes

The customer's working tree now has: the `<script>` tag added to their
shared layout, (if not pre-existing) `.pinappai/last-applied.json`, and
(if found and approved in Step 2b) the Permissions-Policy relaxation.
All of it commits together as a single install batch.

{{include: _shared/landing-chooser.md}}

Suggested branch name: `pinappai/embed-YYYY-MM-DD-HHMM`.
Suggested commit message: `chore: embed PinAppAI feedback widget`.

After the commit (or stage), reviewers will see a floating button on every
page where the snippet loads — they can pin a comment anywhere or click
on a specific element to comment on it.

{{include: _shared/output-language.md}}
