How do I add PinSay to my app?

PinSay mounts an in-browser feedback widget on your running application and connects your team's comment queue directly to your AI coding agents. This guide walks through prerequisites, the initialization command, interactive prompts, files written to disk, and non-interactive usage.

Prerequisites

  • Node.js ≥ 18: Required to execute the initialization CLI.
  • A PinSay account: An active account in your organization's workspace (see Workspaces).
  • An API key: Found in the PinSay web dashboard. Click your user avatar in the top navigation, navigate to Profile, scroll to the API Key section, and copy the key (prefixed with ptr_). For details on storage and security, see API Keys.

The initialization command

Run the initialization command from the root directory of your project repository:

npx -y pinsay init

Running without flags starts an interactive setup assistant that authenticates your session, links or creates a project, detects your dev server and frontend stack, configures widget embedding, and installs AI agent skills.

Walkthrough of interactive prompts

  1. PinSay server URL: Defaults to https://api.pinsay.dev (or the value of PINSAY_SERVER / existing .pinsay/config.json). The CLI reaches out to the server's /api/branding endpoint to discover the server name and product identity.
  2. API key prompt: You are asked to paste your API key (terminal input is hidden for security). The CLI exchanges this key with the server via POST /api/auth/login-with-key to verify permissions and prints your confirmed identity (e.g. ✔ Signed in as Jane Developer (Developer)). You have up to 3 attempts before the command aborts.
  3. Project selection: The CLI retrieves your workspace's projects. You can select an existing project from the list or choose + Create a new project…. When creating a project, you provide a project name; the CLI suggests a slugified key matching ^[a-z0-9-]+$ and creates it immediately.
  4. Environment: Select the environment where this codebase runs (local, staging, or production; defaults to local).
  5. Dev-server URL auto-detection (Step 4b): When configuring the local environment, the CLI inspects your repository to detect the dev-server address:
    • Vite: Scans vite.config.{js,ts,mjs,mts} for server.port and server.https, or checks package.json dev scripts for --port. Defaults to http://localhost:5173.
    • Angular: Scans angular.json under architect.serve.options.port and ssl, or package.json start scripts. Defaults to http://localhost:4200.
    • Next.js: Inspects package.json dev scripts for -p or --port, and checks .env / .env.local for PORT. Defaults to http://localhost:3000.
    • Create React App (CRA): Inspects package.json start scripts and .env for PORT. Defaults to http://localhost:3000.
    The CLI asks Where does this app run in local? with the detected URL prefilled as the default. Press Enter to accept it or enter your custom URL.
  6. AI tool selection: The CLI checks environment variables (such as CLAUDECODE, ANTIGRAVITY_AGENT, TERM_PROGRAM for Cursor, WINDSURF, or OPENCODE) and asks you to confirm your AI coding environment (claude-code, cursor, windsurf, opencode, antigravity, or other).

What the command writes to your repository

Running init creates or updates the following files in your repository:

File path Purpose & contents Git status
.pinsay/config.json Stores project key, server URL, environment, AI tool choice, and CLI version. Committed (safe)
.pinsay/credentials.env Contains your personal PINSAY_API_KEY=ptr_... written with restrictive permissions (0600). Gitignored (never committed)
.pinsay/credentials.env.example Empty key template (PINSAY_API_KEY=) so teammates know which variable is required. Committed
.pinsay/stack.json Recorded frontend, backend, and AI tool tokens discovered from package.json. Committed
.gitignore Updated to ignore .pinsay/ entirely while explicitly re-including safe files: !.pinsay/credentials.env.example, !.pinsay/stack.json, !.pinsay/pinsay.sh, and !.pinsay/config.json. Committed
Skills directory Installs AI agent skills (such as pinsay-init and feedback processing skills) into your editor's skills folder (e.g. .claude/skills/ or tool equivalent). Committed

Deterministic widget injection & stack hand-off

How the feedback widget gets mounted into your application depends strictly on your frontend stack:

Deterministic injection (Vite & static HTML)

The CLI performs deterministic, automated widget injection for two stacks:

  • Vite: Injects a guarded script snippet into index.html reading from %VITE_PINSAY_*% placeholders, and sets VITE_PINSAY_SERVER and VITE_PINSAY_PROJECT in your .env file (plus empty stubs in .env.example). Leave VITE_PINSAY_SERVER empty in a build to ship without the widget; there is no separate enabled flag and no environment variable: the server resolves each comment's environment from the page origin against the project's registered app URLs, so one build is right everywhere. This prevents hard-coding production URLs into local builds.
  • Static HTML: Injects the <script src=".../widget.js" defer></script> tag and <pinsay-feedback ...> element directly before the closing </body> tag of your index.html (or the file passed to --html).

Hand-off for Next.js, Angular, CRA, and monorepos

Deterministic direct file injection is not supported for Next.js (App Router / Pages Router), Angular, Create React App, or monorepos because root layouts, server components, and multi-package trees vary too widely for rigid string substitution.

Instead of modifying your application code unpredictably, the CLI outputs a clear hand-off message:

ℹ <stack> detected — automatic injection isn't supported for this stack yet.
  The pinsay-init skill was installed for <tool>. Run it and it will mount the widget for you:
    claude -> /pinsay-init (or @pinsay-init for cursor)
  Config is already saved in .pinsay/config.json, so the skill won't ask for the key or project again.

Your configuration is already stored in .pinsay/config.json. You simply invoke the pinsay-init skill inside your AI editor, and the agent mounts the widget safely following your framework's idioms.

Non-interactive mode (CI and automated setup)

To run init without interactive prompts (for CI pipelines, dev container provisioning, or automated setup scripts), supply --yes (or -y). When --yes is used, --key is mandatory, and you must supply either --project <key> or --create <name>.

npx -y pinsay init \
  --yes \
  --server https://api.pinsay.dev \
  --key "$PINSAY_API_KEY" \
  --project my-web-app \
  --environment local \
  --tool claude-code

Adding --json outputs structured JSON containing setup details and automatically implies --yes.

CLI flags reference

Flag Description
--server <url> PinSay server URL (defaults to https://api.pinsay.dev).
--key <key> Your PinSay API key (ptr_...). Required when running with --yes.
--project <key> The project key to connect this codebase to.
--create <name> Creates a new project with the given name instead of linking an existing one.
--environment <env> Target environment (local, staging, or production; default: local).
--tool <tool> AI tool to install skills for (claude-code, cursor, windsurf, opencode, antigravity, other).
--skills-dir <path> Custom target directory for AI agent skills.
--app-url <url> Explicit dev-server URL (e.g. http://localhost:3000), bypassing detection prompts.
--no-app-url Skips assigning an application URL for the environment.
--html <path> Path to the target HTML file for static injection (defaults to index.html).
--no-inject Skips widget script injection into HTML/env files entirely.
--no-skills Skips installing AI agent skills.
-y, --yes Non-interactive mode. Fails immediately if required inputs are missing.
--json Outputs results in JSON format and suppresses interactive prompts (implies --yes).
-h, --help Displays usage documentation and flag summaries.

Exit codes

Code Status Meaning & typical trigger
0 Success Setup completed successfully; config and skills written to disk.
1 General Error Server unreachable, project key conflict, or unhandled runtime failure.
2 Invalid Usage Unknown command, invalid flag, or missing required flag (e.g. --key omitted with --yes).
3 Auth Failure Invalid or revoked API key, or the authenticated account lacks project creation permissions.

Keeping the AI skills up to date

init copies the AI skills and pinsay.sh into your repository, where they stay exactly as they were on the day you installed them. The server keeps changing. A skill file installed months ago is frozen prose describing an API that has moved on — and nothing about it looks wrong, which is what makes it expensive.

Every served skill and script carries a version stamp, so your installed copy can be compared with the server’s:

  • npx -y pinsay doctor reports a stale warning naming each file that is behind.
  • npx -y pinsay update --check lists what would change and writes nothing.
  • npx -y pinsay update refreshes them in place, preserving the .agents/ symlinks.

A stale skill is a warning, never an error — it still works, it is just behind. Nothing updates silently: refreshing is always something you ask for.

Self-hosting: the stamp defaults to the API’s build version, so every deploy moves it. Set PinSay__SkillVersion to invalidate installed copies after editing skill prose without shipping new code.

Troubleshooting & common pitfalls

  • Invalid API key (Exit 3): Verify that the API key was copied completely from your profile page and has not been regenerated. If you regenerated your key in the web dashboard, the previous key was revoked immediately.
  • This account cannot create projects (Exit 3): Stakeholder or client accounts are scoped to viewing comments and cannot mint new projects. An organization owner or administrator must create the project or invite you with developer privileges.
  • Key already exists, choose another: Project keys must be unique within your organization. Provide a distinct slug or attach to the existing project with --project <key>.
  • Comments blocked after deploy: If you enable origin enforcement on your project, ensure the deployed origin matches your configured environment URL. See Project Settings.
Not yet available

The pinsay doctor diagnostic command is currently stubbed and will be expanded in an upcoming release. Direct deterministic widget injection for SSR and monorepo frameworks is intentionally delegated to the AI editor skill (pinsay-init) rather than hardcoded in the CLI.