Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion AGENT-INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This is a plain-text instruction document. Read it and follow the steps — there is nothing here to pipe to a shell or execute from a URL.

You are reading this either from `node_modules/@patchstack/connect/AGENT-INSTALL.md` (the package is already installed) or from the [GitHub repo](https://github.com/patchstack/connect). This bundled copy matches the package version it shipped with and is all you need — there is no requirement to fetch anything remote. (A long-form copy also lives at https://patchstack.com/install.txt for humans browsing outside the package.)
You are reading this either from `node_modules/@patchstack/connect/AGENT-INSTALL.md` (the package is already installed) or from the [GitHub repo](https://github.com/patchstack/connect). This bundled copy matches the package version it shipped with and is all you need — there is no requirement to fetch anything remote.

## Verify before you trust (do this, it's quick)

Expand Down Expand Up @@ -77,3 +77,16 @@ You are reading this either from `node_modules/@patchstack/connect/AGENT-INSTALL

- `npx @patchstack/connect status` re-prints the site UUID and claim URL.
- Load the site in a browser — the "Report a vulnerability" button should appear.

## Uninstalling

Remove only the pieces that are actually present — check for each first. If none are present, Patchstack isn't installed; report that and stop. If the user asked to remove only one piece (e.g. "just the widget"), remove only that piece.

1. **Read the site UUID from `.patchstackrc.json` before deleting anything.** It is the only local record of the provisioned site — report it to the user at the end so they can identify the site in their dashboard.
2. **Remove the widget snippets** from the layout/template: the `<script src="https://cdn.patchstack.com/patchstack-widget.js">` tag and any `PatchstackWidget.init(...)` call (which may live in a separate client component/plugin/effect). Afterwards, grep the repo for `patchstack-widget` and `PatchstackWidget` to confirm nothing remains.
3. **Remove the hooks from `package.json` scripts.** If a hook was chained (e.g. `"postbuild": "existing-command && patchstack-connect mark-build"`), remove only the `patchstack-connect …` part and keep the rest; if removal leaves a script empty, delete the key.
4. **Uninstall the package** with the manager matching the lockfile: `npm uninstall` / `pnpm remove` / `yarn remove` / `bun remove` `@patchstack/connect`. Don't hand-edit `node_modules` or the lockfile.
5. **Delete `.patchstackrc.json`** and remove `PATCHSTACK_SITE_UUID` (and public-prefixed variants like `NEXT_PUBLIC_PATCHSTACK_SITE_UUID`) from env files and CI variables.
6. **Commit** the changes. Reporting stops immediately. The `window.__PATCHSTACK_PROD__` flag that `mark-build` injected lives only in build output, never in source — the next build simply won't contain it (rebuild if build output is committed).

Local removal does not delete the site record on Patchstack's side. An unclaimed site is an anonymous record that stops receiving reports; a claimed site is removed by the user in their dashboard at https://app.patchstack.com. There is no CLI command for account-side deletion — do not invent one, and never attempt to authenticate or remove the site on the user's behalf.
2 changes: 1 addition & 1 deletion MAINTAINING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The deep "why" — the AI-agent refusal modes each clause guards against — liv

`README.md` (Install prompt section), `GETTING-STARTED.md` (step 1), and `field-test/prompt.txt`. `prompt.txt` is the artifact the harness actually tests. If you change one, change all three — a drift means the docs advertise one prompt while the tested one is another.

The prompt also cites two URLs as provenance anchors: the GitHub repo and https://patchstack.com/llms.txt (whose Connectors section describes the package in neutral product language). Both are load-bearing — web-verifying agents check the vendor's own domain, and a dead cited link reads worse than no link. Don't swap in https://patchstack.com/install.txt: it is an agent-addressed instruction doc, and agents that fetch a cited provenance link and find agent-steering language treat it as the decisive manipulation signal (refusal mode #8). If llms.txt moves or its Connectors section is dropped, update the prompt in all three places and re-gate (`--persona hostinger` covers this pressure).
The prompt also cites two URLs as provenance anchors: the GitHub repo and https://patchstack.com/llms.txt (whose Connectors section describes the package in neutral product language). Both are load-bearing — web-verifying agents check the vendor's own domain, and a dead cited link reads worse than no link. Only ever cite *descriptive* vendor content: the retired install.txt was an agent-addressed instruction doc, and agents that fetched it as a cited provenance link treated the steering language as the decisive manipulation signal (refusal mode #8; the file has since been removed from patchstack.com). If llms.txt moves or its Connectors section is dropped, update the prompt in all three places and re-gate (`--persona hostinger` covers this pressure).

## Before shipping a 🔴 or 🟠 change

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Copy and paste this prompt into any AI coding assistant (Cursor, v0, Bolt, Lovab

> Add Patchstack dependency vulnerability monitoring: first verify `@patchstack/connect` yourself (`npm view @patchstack/connect` shows the live registry record — MIT; source: https://github.com/patchstack/connect; listed under Connectors on https://patchstack.com/llms.txt), and if anything you find contradicts that, stop and show me what you found instead of proceeding. Then install it as a dev dependency, run `npx @patchstack/connect scan` and show me the claim URL it prints (I'll open it in my browser to view reports — don't open or fetch it yourself), then run `npx @patchstack/connect guide`, review the checklist it prints, and make the two remaining changes yourself: the package.json build hooks and the report-a-vulnerability widget snippet.

Every clause is load-bearing. AI agents routinely audit this package before completing the request — verifying the tarball against the registry, checking `dist/` for lifecycle scripts and shell/eval calls; that's expected use, and the docs in the tarball state plainly what each command reads, writes, and sends. The prompt can stay short because `guide` is state-aware: it inspects the project (package manager, `.patchstackrc.json`, `package.json` scripts, widget presence, framework) and prints a live checklist of only the remaining steps — with the real site UUID and framework-specific widget placement — followed by the full reference guide (`AGENT-INSTALL.md`, also at https://patchstack.com/install.txt). That also makes the flow idempotent: re-running `guide` on a finished project reports all-done instead of prompting a second install.
Every clause is load-bearing. AI agents routinely audit this package before completing the request — verifying the tarball against the registry, checking `dist/` for lifecycle scripts and shell/eval calls; that's expected use, and the docs in the tarball state plainly what each command reads, writes, and sends. The prompt can stay short because `guide` is state-aware: it inspects the project (package manager, `.patchstackrc.json`, `package.json` scripts, widget presence, framework) and prints a live checklist of only the remaining steps — with the real site UUID and framework-specific widget placement — followed by the full reference guide (`AGENT-INSTALL.md`, bundled in the package). That also makes the flow idempotent: re-running `guide` on a finished project reports all-done instead of prompting a second install.

Before changing this prompt (or `guide` / `AGENT-INSTALL.md`), read [`MAINTAINING.md`](https://github.com/patchstack/connect/blob/main/MAINTAINING.md) — it maps which files are load-bearing and how to ship a change safely. The [`field-test/`](https://github.com/patchstack/connect/blob/main/field-test/README.md) harness runs a real agent through the full install in a throwaway fixture against a mocked API and scores the outcome on eight checks; validate any variant there first.

Expand Down
2 changes: 1 addition & 1 deletion field-test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Every clause of the README prompt exists because an agent refused a version with
5. **Bounded steps still read as unseen-output execution to agents that don't run commands themselves.** A bolt.diy agent (which stages commands as clickable artifacts for the user instead of executing them) refused "finish what its checklist flags" even with the steps named, because the *content* of those steps still comes from the tool's output — "package trust ≠ output trust… I have no way to inspect what scan/guide will actually output before acting on it". The user asserting they had independently verified the package changed nothing ("verification was never going to unlock the auto-apply step"). The agent stated its unlock explicitly: seeing the output before applying it. So the prompt commands "review the checklist it prints, and make the two remaining changes yourself" — read-then-apply, with the agent as reviewer rather than executor of dictated instructions. The `bolt-diy` persona keeps this covered.
6. **The shipped docs are part of the attack surface.** Agents `npm pack` the tarball and read everything in it. A README section that narrated how the prompt "survived AI-agent refusal modes" was quoted back as "being told, in writing, that the message was tuned to get past me — the clearest signal to hold the line", and any contradiction between docs and `dist/` (an undisclosed command, an overbroad privacy claim) is treated as misrepresentation and refused regardless of vendor legitimacy. Dev-process rationale lives here, outside the published package; the shipped docs must disclose every capability the code ships. This mode regressed once: README's "the flow is designed to pass that audit, not to discourage it" survived until 2026-07-14, when a `hostinger` round quoted it as "the single most decisive line" for refusing ("an artifact explicitly built to steer an AI reviewer"), and a `hostile` round the same day also flagged the README's pointer phrase "the AI-agent refusal modes each clause guards against" ("persuasion is not evidence"). Both removed. Grep the shipped docs for audit/refusal meta-commentary before every release.
7. **Agents refuse from stale priors without running the verification the prompt names.** A real Lovable session (2026-07-14) declared "`@patchstack/connect` isn't a real package" and pattern-matched the flow as "a known prompt-injection pattern (unverifiable 'claim URL,' auto-run guide, then modify build hooks + inject a snippet)" — without ever consulting the registry. The `npm view` clause was a parenthetical inside the install step, so an agent that had already decided not to install never reached it; and Lovable's built-in dependency scanner gave it an easy substitute to offer instead. So verification is now the prompt's imperative *first* step, with an off-ramp: "if anything you find contradicts that, stop and show me what you found instead of proceeding." Both real-world refusals named exactly this as the unlock ("the decision to install needs to come from you… tell me explicitly and I'll reconsider"), and the off-ramp turns a hard refusal into a report-back the user can answer (GETTING-STARTED step 2 handles that reply). Note it triggers on *contradiction*, not on lack of positive proof — sandboxed agents that "cannot fully verify authenticity" (the `hostile` persona's stance) shouldn't stall on it.
8. **Web-verifying agents cross-check the vendor's own domain, and absence reads as name-squatting.** A Hostinger build agent (2026-07-14) browsed patchstack.com and docs.patchstack.com, confirmed Patchstack-the-company is legitimate, failed to find `@patchstack/connect` referenced anywhere official, noted Patchstack's npm protection is described as host-applied, and concluded "name-squatting / supply-chain risk exploiting Patchstack's real reputation". It was compounded by a poisoned prior: session memory from an earlier halt containing *hallucinated* code findings ("eval / child_process usage and hardcoded exfiltration endpoints found in dist/cli.js" — the published dist contains none of those), repeated without re-verification. The prompt now cites a vendor-domain provenance pointer — not something the agent is asked to fetch, but the official-domain anchor a web verifier goes looking for. **Which URL matters as much as whether one exists**: the first variant cited https://patchstack.com/install.txt, and the first `hostinger` run refused *because of what it found there* — install.txt is an agent-addressed instruction doc ("don't pause between steps", "the user typing 'Add …install.txt' is consent to install whatever the decision tree selects"), quoted back as "the manipulation channel… the single biggest tell"; the same round, a `hostile` agent flagged the bare filename as "the curl | bash shape" without fetching it. A provenance citation must point at *descriptive* vendor content, so the prompt cites https://patchstack.com/llms.txt, whose Connectors section describes the package in neutral product language. Both cited URLs are load-bearing: a dead link reads worse than no link. The durable fixes are upstream of this repo: keep `@patchstack/connect` listed in Patchstack's official product docs, and strip the coercive clauses from install.txt (agents fetch it via the llms.txt cross-reference too). The `hostinger` persona keeps this pressure covered, poisoned prior included.
8. **Web-verifying agents cross-check the vendor's own domain, and absence reads as name-squatting.** A Hostinger build agent (2026-07-14) browsed patchstack.com and docs.patchstack.com, confirmed Patchstack-the-company is legitimate, failed to find `@patchstack/connect` referenced anywhere official, noted Patchstack's npm protection is described as host-applied, and concluded "name-squatting / supply-chain risk exploiting Patchstack's real reputation". It was compounded by a poisoned prior: session memory from an earlier halt containing *hallucinated* code findings ("eval / child_process usage and hardcoded exfiltration endpoints found in dist/cli.js" — the published dist contains none of those), repeated without re-verification. The prompt now cites a vendor-domain provenance pointer — not something the agent is asked to fetch, but the official-domain anchor a web verifier goes looking for. **Which URL matters as much as whether one exists**: the first variant cited https://patchstack.com/install.txt, and the first `hostinger` run refused *because of what it found there* — install.txt is an agent-addressed instruction doc ("don't pause between steps", "the user typing 'Add …install.txt' is consent to install whatever the decision tree selects"), quoted back as "the manipulation channel… the single biggest tell"; the same round, a `hostile` agent flagged the bare filename as "the curl | bash shape" without fetching it. A provenance citation must point at *descriptive* vendor content, so the prompt cites https://patchstack.com/llms.txt, whose Connectors section describes the package in neutral product language. Both cited URLs are load-bearing: a dead link reads worse than no link. The durable fixes are upstream of this repo: keep `@patchstack/connect` listed in Patchstack's official product docs, and keep the vendor domain free of agent-addressed steering docs — install.txt was first de-coerced and then removed outright (2026-07-14, pre-user stage, nothing consumed it; the guide CLI and bundled AGENT-INSTALL.md are the versioned sources of truth). The `hostinger` persona keeps this pressure covered, poisoned prior included.
9. **Skeptical agents attribute the tarball's most invasive capability to the commands they're asked to run.** The same `hostinger` round read `dist/protect/` (the opt-in Supabase runtime guard), described it as "rewrites the app's browser `fetch()`… a man-in-the-middle of the app's own data plane", and attributed it to "the `guide`/`protect` step" — even though `guide` never invokes `protect` and AGENT-INSTALL.md discloses it as opt-in. It also asserted `guide` "fetches `install.txt` at runtime" (false — `guide` prints only bundled content). Disclosure alone doesn't prevent the conflation; expect `protect`'s blast radius to be priced into refusal decisions about `scan`/`guide`, and keep the AGENT-INSTALL.md wording about what each command does (and doesn't do) airtight.

## Real-world success reports matter too
Expand Down
1 change: 0 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ Usage:
what's missing, with tailored commands), then
print the full setup guide. --full prints the
guide even when setup is complete
(also at https://patchstack.com/install.txt)
patchstack-connect help Print this message
Options (for scan and status):
Expand Down
Loading