pinnedai-mcp
OfficialThis server integrates Pinned AI's guard infrastructure into AI coding workflows, enabling proactive protection of repo invariants, automated checks before committing changes, and assisted setup.
pinned_before_code_change: Call before editing any code to retrieve active guards, recent AI lessons, and safety notes. Recommendsnpx pinnedai initif Pinned isn't installed.pinned_before_done_check: Runs a full Pinned check (diff scanning, guard integrity, AI lessons) before declaring work complete. Returns PASS / REVIEW / BLOCK with a requiredhuman_summary.pinned_scan_diff: Scans the current git diff for new risky surfaces (routes, webhooks, middleware, env changes) that lack guards.pinned_list_guards: Lists all active (and optionally retired) guards in the repository.pinned_check_pr_description: Parses PR descriptions, commit messages, or specs for behavioral claims (auth, rate-limits, permissions, etc.) and returns a structured claim list.pinned_suggest_init: Checks whether Pinned is installed in the repo and recommendsnpx pinnedai initif missing.
Integrates with GitHub Copilot by writing AI rules to .github/copilot-instructions.md, allowing Copilot to read Pinned rules before generating code.
PinnedAI
Pinned actually runs your AI-built features and asserts they produce real outcomes — not just that the code parses. Smoke pins execute endpoints. Render-collection pins cover every route in a multi-tenant app (a new row gets covered automatically — no pin edit). Visibility-invariant pins assert the negative — drafts MUST 404, not 200.
pinned devruns them locally with zero config. The generated CI workflow auto-detects Vercel/Netlify preview URLs AND verifies pins actually executed (zero-pins-ran fails the step). Plus the full first-time-bug detector net: enum drift, missing env declarations, undeclared Supabase columns/tables, webhook header typos, unguarded results, response-shape, mass-mutation.Free beta · Founder Pro waitlist open at pinnedai.dev.
The value loop
npx pinnedai audit— read-only inventory of your write surfaces. Zero install footprint. Tells you what Pinned would protect before you commit to anything.pinned sweep— one command auto-detects every high-stakes surface across your tree (not just the current diff): Server Actions, paid-API calls, Edge Functions, cron schedules, Stripe webhook event dispatch, multi-step journeys, host-conditional families. Each becomes atests/pinned/*.test.tsfile.pinned smoke add/pinned render add/pinned visibility add— pins that actually RUN your features and assert real outcomes, not just code shape:smokeasserts spec-derived invariants on a single endpoint (non-empty body, terminal state within bound, rejects bad input, errors on faults).rendercovers every route in a collection — Next.jsgenerateStaticParams, a custom getter, or/sitemap.xml. Adding a new row gets covered automatically. Per-row failure naming.visibilityasserts the negative half render pins cannot provide — items marked draft/private/archived MUST return 404 / 307 / 308, never 200.
pinned dev— boots your dev server (Next/Vite/Astro/SvelteKit/Remix/Nuxt auto-detected), runs the pin suite locally with zero env vars, verifies pins actually executed (auto-opt-in that silently still skips is the same trap), tears down. The recommended pre-commit / pre-push loop.pinned init— wires hooks + generates a CI workflow that auto-detects Vercel/Netlify/Cloudflare Pages/Render preview URLs AND verifies pins executed (zero-pins-ran fails the step). Pre-commit + pre-push Guard Integrity blocks AI-weakening attempts (.skip()/ weakened assertions / deleted tests /--no-verifybypass). Claude Code PostToolUse hook auto-verifies pins against your running dev server after every agent edit. AI-coder rules seeded intoCLAUDE.md/.cursorrules/AGENTS.md.Every commit + every agent edit runs the pin suite. Bug fixes captured as
pinned record-server-action/record-interactionfixtures land in your repo permanently.AI Lessons (
.pinned/ai-lessons.md) capture repo-specific rules from real blocked events.pinned sync-rulesinlines the top-N lessons directly into every agent-rules file (CLAUDE.md, AGENTS.md, .cursorrules) — inline the lesson, never redirect.pinned audit --learnedfinds sibling code paths with the same mistake pattern.
The output of every finding is an executable test, not a review comment. Cancel Pinned tomorrow and the pins stay.
Proof it works: see the /proof page for benchmark results, or Status below for headline numbers. Real dyad-app dogfood: 63 detections across 10 repos, 0 spurious; 42 unprotected Edge Function writes surfaced on a single repo.
Related MCP server: agent-guardrail
Quickstart
# 0. See what Pinned would protect — read-only, no install footprint
npx pinnedai audit
# 1. Auto-detect every high-stakes write surface and pin it
npx pinnedai sweep
# 2. Wire continuous verification (hooks + AI-coder rules + CI workflow)
npx pinnedai initpinned sweep finds (precision-bound, no false positives in 10-repo dogfood):
Server Action mutations (
"use server"functions with DB writes / file uploads / paid-API calls — auth gate + input schema captured)Paid-API calls (Anthropic / OpenAI / Gemini / Stripe — model literal + max_tokens preserved)
Supabase Edge Functions (Deno runtime — HTTP-route detection misses these)
Cron handlers (Vercel
vercel.json:crons[]+ GitHub Actionson.schedule)Stripe webhook event dispatch (case-literal preservation — catches one-letter typos)
Multi-step journeys (POST→GET redirects, signup→thanks flows with shared session)
Host-conditional families (one root file → multiple consumer routes)
pinned init writes .github/workflows/pinned.yml, creates tests/pinned/ with PINS.md, installs pre-commit + pre-push hooks, seeds AI-coder rules into CLAUDE.md + .github/copilot-instructions.md, and (for Claude Code users) wires the PostToolUse hook so Pinned auto-verifies pins against your running dev server after every agent edit. Each step prompts before writing in interactive mode; pass --auto to accept all.
If your repo already has .cursorrules, .clinerules, AGENTS.md, or .windsurfrules, init writes to those too — same marker-bounded block, identical uninstall flow (pinned uninstall-agent-rules).
Editor + AI-tool surfaces
Pinned ships across every major AI-coder surface:
Surface | What you get | How to install |
VS Code / Cursor / Windsurf / Codium |
| Bundled |
Claude Code | PostToolUse hook — after every Claude edit, Pinned auto-verifies the affected pins against your running dev server and injects the result into Claude's next turn (catches regressions while the agent is still in the loop). Plus statusline ( | PostToolUse hook auto-wired by |
GitHub Copilot Chat (free + paid) | Reads Pinned rules from | Auto-created during |
MCP-aware tools (Claude Desktop, Cline, Continue) |
| Add |
GitHub Action (CI) | Runs | Auto-wired via |
Pre-commit + pre-push hooks | Block bypass attempts locally before they reach CI | Auto-wired by |
Per-tool integration docs:
README badge
[](https://pinnedai.dev)Pin templates
Each template is a deterministic verifier — the LLM never writes test logic, it only fills slots. Templates auto-fire from pinned sweep based on what the detectors find in your tree. The full inventory:
🆕 First-time bug catching (0.2.22+)
Every other Pinned template catches regressions — bugs that appear when previously-good code breaks. This category catches bugs at the moment they're written, before any baseline exists. All static (no creds, no runtime probes).
enum-drift— consumer readsx === "done"but in-repo producer only emits"completed"/"failed"/"processing". The socialideagen-dogfood-shape bug. Two confidence tiers: confirmed (≥1 vocabulary overlap, auto-pin) and review (zero overlap, soft signal — cross-table column collisions or cross-repo external producers).env-required— code readsprocess.env.X_API_KEYbut.env.example/vercel.jsonenv /next.config.jsenv block /wrangler.toml [vars]doesn't declare it. Cloned-repo first-runs and deploys silently getundefined.supabase-column—.from("X").select("col_a, col_b")against a Supabase table where one of the columns isn't insupabase/migrations/*.sqlordatabase.types.ts. Runtime error on first query.expected-header— webhook handler readsx-stripe-signature(wrong) when the Stripe SDK signs with canonicalstripe-signature. Signature verification silently fails on every request. Provider catalog: Stripe / GitHub / Svix / Twilio / Shopify.nullable-result—arr.find(...)/.match()/.exec()result used without null guard in server-side route handlers (route.ts/*.actions.ts/supabase/functions/). First edge-case input crashes the route with a 500.response-shape— consumer readsbody.referralCodefrom afetch("/api/X")response, but the producer'sNextResponse.json({...})never emits that key. Generalizes the enum-drift bug class to JSON-key mismatches in same-repo HTTP routes.
HTTP / API surface
page-renders— "GET /path renders without crashing." Catches React/Next/Vite render errors + 500 pages + broken SSR.validation-rejects-bad— "POST /api/X with bad input returns 400." One pin, N sub-tests (malformed-JSON + per-field missing).happy-path-with-side-effect— "POST /api/X creates a users record." Catches stub endpoints returning 200 without doing the work (misleading-green) via theX-Pinned-Side-Effectresponse header convention.auth-required/permission-required/tier-cap— auth gates + role checks + per-tier caps survive.rate-limit/idempotent— rate limiters + webhook dedup keys preserved.returns-status—<method> <route> returns <status> on <condition>— auto-generated from added validation schemas in diffs.
App-Router + modern mutation surfaces (0.2.18+)
server-action-write—"use server"mutations with DB write / file upload / paid-API call. Direct-invoke pin withvi.mock()for the auth helper — runs the success path AND the reject path so AI silently removing the auth gate is caught (not just bypassing it).paid-api-call— Anthropic / OpenAI / Gemini / Stripe calls anywhere in the codebase (not just inside Server Actions). Captures the call expression + model literal (catchesclaude-opus→claude-haikusilent swaps) + max_tokens cap (catches unbounded-spend regressions).edge-function-write— Supabase Edge Functions atsupabase/functions/<name>/index.ts(Deno runtime — HTTP-route detection misses these). Three-tier auth posture: confirmed (recognized helper) / ambiguous (auth-shaped signals but unrecognized — soft warn) / none (truly bare endpoint — loud alarm).cron-handler— Vercelvercel.json:crons[]entries + GitHub Actionson.schedule[].cron. Catches silent schedule drift (0 4 * * *→0 4 * * 0, runs once a week instead of daily) + handler renames.stripe-event-handled— Stripe webhookswitch (event.type) { case "X": ... }dispatch. Catches AI silently typoing"checkout.session.complete"(one-letter rename), merging fallthrough arms dropping one, or wholesale deleting a case. Signature still verifies — paying customers never get provisioned.
Multi-step + family-shaped
journey— multi-step flows (signup→thanks, login→dashboard) with shared session. Catches "step 1 succeeds but step 2 silently regresses" — single-route pins structurally miss these.Family detection (host-conditional) — one root file → multiple consumer routes. A change to the root pins all consumers as a group.
Browser interactions (🛟 BETA — opt-in)
interaction-baseline— Playwright records the observable effect of an interaction (carousel arrow click → scroll position, submit button → URL change). CatchesonClickhandler regressions that go undetected because the page still renders.page-accessibility— axe-core via Playwright. Catches WCAG-AA contrast failures + invisible text — the "page renders but is unreadable" class that page-renders pins go GREEN on. WARN-only on violations;confidence: "review"so catches don't inflate the GA metric.
Repo integrity
lockfile-integrity/config-invariant/package-exports-exist/module-export-stable/import-path-resolves/tsc-clean— lockfile sha + critical config keys + module exports + import resolution + TS build all stay intact.url-literal-preserved/changed-literal-preserved— URLs in code + bug-fix literals don't regress.webhook-handler-exists— webhook handler signatures preserved.react-route-registered— internal<Link href="/foo">/navigate("/foo")resolve to a real page file.secret-not-public— noNEXT_PUBLIC_*SECRET*leaks, no.envcommits, no debug routes exposed.form-submit-error-handling— async error-handling on form submits stays wrapped.
CLI / library tooling
cli-output-contains/cli-exits-zero/cli-creates-file/cli-json-shape/cli-flag-supported— for CLI tools and binaries.library-returns— a library function still returns the expected shape.
The detectors are precision-bound: every pin emit has a specific signal, never a generic shape match. The 10-repo dyad dogfood produced 0 false positives across 63 detections.
Recognized write libraries
happy-path-with-side-effect + server-action-write + edge-function-write auto-fire on these write shapes (both in new diffs AND retroactively via pinned sweep):
Library | Pattern detected |
supabase-js |
|
prisma |
|
drizzle-orm |
|
kysely |
|
mongoose |
|
raw SQL |
|
resend / sendgrid / nodemailer / aws-ses / postmark | their send / sendMail / sendEmail methods |
bullmq / inngest / generic queue |
|
supabase-storage / aws-s3 / cloudflare-r2 / vercel-blob |
|
Anthropic / OpenAI / Gemini / Stripe (paid API) |
|
The widened Supabase client-identifier vocabulary recognizes admin.from(...), db.from(...), userClient.from(...), serviceClient.from(...), etc. — not just the literal supabase identifier. Confirmed across 42 Edge Functions on the MediniDyad dogfood repo.
If your repo uses a write library not yet recognized, the pin won't auto-fire — open an issue with the import pattern. Adding a row is two regex lines.
What Pinned protects
Pinned focuses on AI-prone failure modes. Categories grow with each release:
🆕 First-time bugs (no regression baseline needed — 0.2.22+)
The bug class where consumer + producer never agreed, OR the configuration was wrong from line 1. Other detectors miss these because there's nothing to regress from.
Enum-value drift — client reads
status === "done"but producer emits"completed"(the socialideagen dogfood bug).Undeclared env vars — code reads
process.env.Xbut.env.example/vercel.jsonenv /next.config.jsenv /wrangler.tomldoesn't list it. Cloned-repo first-runs and deploys silently get undefined.Undeclared DB columns — code queries
.from("X").select("col_a, col_b")against a Supabase table where the column doesn't exist in migrations ordatabase.types.ts.Webhook header typos — handler reads
x-stripe-signature(wrong) when Stripe SDK signs withstripe-signature(canonical). Silent verification failure on every request.Unguarded
.find()/.match()results in route handlers — first edge-case input crashes the route with a 500.Response-shape mismatches — consumer reads a JSON key the producer never emits.
App-Router + modern mutation surfaces
Next.js Server Actions —
"use server"functions that perform writes (DB / file upload / paid API) with auth gate + zod input schema captured. Direct-invoke verifier withvi.mock()for the auth helper runs success path AND reject path → catches silent gate removal too.Paid-API calls (anywhere) — model string preserved (no silent
claude-opus→claude-haikuswaps),max_tokenscap preserved (no unbounded-spend regressions), call expression preserved (no silent removal). Fires on plain backend services, library helpers, anywhere — not just Server Actions.Supabase Edge Functions — Deno-runtime functions invisible to HTTP-route detection. File-existence + write expression + auth-gate idiom all preserved. Three-tier auth posture so soft-warns don't bury truly bare endpoints.
Cron handlers — Vercel
vercel.json:crons[]+ GitHub Actionson.schedule. Schedule drift (0 4 * * *→0 4 * * 0, daily vs weekly — same shape, very different behavior) + handler renames caught.Stripe webhook event-type dispatch — every
case "<event-name>":arm preserved. One-letter typo / merged fallthrough / deleted case fails the pin even though the signature still verifies.
Auth / access
Auth gates —
requireAuth/requireAdmin/ middleware matcher coverage; the middleware-aware pin usesmiddleware.ts's captured auth signature so removing the check fails the guard.Permission roles — per-role + per-tier caps preserved.
Client / API mistakes — missing
authHeaders(), missingcredentials: "include", lostif (!res.ok)gates, removed 401/402/403 handling.Webhook signature verification —
stripe.webhooks.constructEvent,x-hub-signature-256,svix.verify,twilio.validateRequest, genericcrypto.createHmac("sha256", ...). Removing the verify call fails the pin.
Visual / usability (🛟 BETA — opt-in)
WCAG-AA contrast / invisible text — axe-core via Playwright. Catches the "page renders but is unreadable" class (white-on-white text shipped 3 times in real dyad-app dogfood) that plain page-renders pins go GREEN on.
Interaction baselines — Playwright records the observable effect of a click / scroll / type. Catches
onClickhandler regressions.
Repo integrity
Guard weakening —
.skip(),.only(),xit(),.todo(),.skipIf(true), deleted tests, weakened assertions (toBe(401)→toBeTruthy()),|| true,?? true,catch(() => true),expect(true).toBe(true)tautologies, commented-outexpect(),expect.assertions(0), earlyreturn;in test body.Pinned-infrastructure tampering — deletion of
tests/pinned/*,.github/workflows/pinned.yml,tests/pinned/.registry.json,.pinned/ai-lessons.md, or sneaky rename-to-retired/ without the matching.audit.json.Route / export / reference integrity — internal
<Link href="/foo">/navigate("/foo")/router.push("/foo")that resolve today are pinned; future removal of the target page file fails the pin.Module exports — package.json
exports, named exports from libraries, import-path resolution.Lockfile + config invariants — pnpm-lock.yaml sha + critical config keys preserved.
Public exposure
Secrets in client bundle —
NEXT_PUBLIC_*SECRET*/NEXT_PUBLIC_*KEY*leaks.No-fixture checks —
.envcommitted without.gitignorecoverage,.mapfiles indist//build/, debug routes (__debug,__test,debug.html,/admin/console).
AI lessons
Pinned writes repo-specific lessons to .pinned/ai-lessons.md (markdown for humans) and .pinned/lessons.json (structured for tools).
Each lesson is generated from a real event — a blocked bypass attempt, a replay-verified bug-fix guard, or a confirmed sibling audit. Dedupe is per guardId: repeat attempts append evidence to the existing entry, not duplicate sections.
Example:
## Don't weaken client-getReport-authHeaders
<!-- pinned:guard=client-getReport-authHeaders kind=guard-block -->
**Past mistake:**
weakened: src/api/getReport.ts — `headers: await authHeaders()` removed in PR #88
**Rule:**
Do not remove `authHeaders()` from `src/api/getReport.ts`. Fix the application code instead.
**Guard:** `client-getReport-authHeaders`
**Plain English:** don't drop authHeaders() from API callsPoint your AI coder at this file with pinned install-agent-rules so Claude/Cursor reads the rules before editing.
Commands
Setup
npx pinnedai init # one-time per repo
npx pinnedai install-agent-rules # opt-in: wire CLAUDE.md/.cursorrules/etc. to read .pinned/ai-lessons.md
npx pinnedai uninstall-agent-rules # undo the above
npx pinnedai agent-rules # show which agent files are wiredDaily workflow
npx pinned test # run the pin suite
npx pinned status # see active pins + recent events
npx pinned context # print the AI-coder context (rules + lessons) for inline promptingDiscovery
npx pinned scan-diff # show what Pinned would auto-protect in the current diff
npx pinned audit --learned # scan sibling code paths for risks matching learned patterns
npx pinned probe-admin # enumerate admin/internal routes + their protection state
npx pinned list # list all active + retired pins
npx pinned show <pin-id> # what a pin asserts + what would make it fail (alias: `describe`)
npx pinned regenerate --all # re-emit all pin .test.ts files using the current templates — run this after upgrading pinnedai to apply any template-bug fixes to existing pins (alias: `regen`)Lifecycle
npx pinned retire <claim-id> --reason="..." # legitimate retirement (writes audit entry)Reporting + analytics (local-first)
npx pinned report # per-detector dashboard, severity-sorted + 7-day trend + per-AI-model breakdown
npx pinned report --json # full schema for piping into your own tooling
npx pinned analytics status # show whether hosted analytics is opt-in
npx pinned analytics enable # opt-in to cross-repo + per-model dashboards at app.pinnedai.dev (Pro+)
npx pinned analytics disable # flip off; local stats keep working
npx pinned analytics upload # manual one-shot upload (or auto-fires on every `pinned sweep` when enabled)Local data lives in .pinned/repo-stats.json (per-detector hit counts, severity ranking, per-AI-model rollup, bounded samples, 7-day snapshots). Free tier gets the full local dashboard. Hosted analytics is opt-in only — never auto-uploads. Uploaded data is structured to exclude source code, file contents, and secrets; only counts + sample file-paths + line-numbers + plain-English summaries get sent. See tier-model-final-2026-05-23 for the free/paid split.
Paid-API call pins (silent model swap / token-cap defense)
Pin every paid API call in your backend — not just the ones in Next.js Server Actions. Captures the call expression + model literal + max_tokens cap so AI silently swapping claude-opus → claude-haiku (quality regression) or removing the token cap (unbounded spend) is caught immediately.
npx pinned sweep # auto-detects paid-API calls (Anthropic / OpenAI / Gemini / Stripe)Coverage: Anthropic (messages.create / parse / stream), OpenAI (chat.completions.create, responses.create, images.generate, embeddings.create), Google Gemini (generateContent), Stripe (paymentIntents.create, charges.create, subscriptions.create, customers.create, checkout.sessions.create, billingPortal.sessions.create). Entry-point-agnostic — fires anywhere, plain backend service or Server Action.
Supabase Edge Function pins (Deno runtime)
HTTP-route detection structurally misses Supabase Edge Functions (they run in Deno, not Node). Pin asserts the function file exists, the write expression survives, and the auth gate is preserved.
npx pinned sweep # detects supabase/functions/<name>/index.tsCatches: AI deletes the function ("dead code cleanup"), removes the write call, weakens the auth gate.
Cron handler pins (Vercel + GitHub Actions)
Cron fires WITHOUT a user in the loop — schedule drift (0 4 * * * → 0 4 * * 0 runs once a week instead of daily) or handler rename = silent SLA break. Pin captures Vercel vercel.json:crons[] entries and GH Actions on.schedule[].cron schedules.
npx pinned sweep # detects vercel.json + .github/workflows/*.ymlStripe webhook event-type dispatch pins
The layer above signature-verify. Catches AI silently typoing case "checkout.session.complete": (one-letter rename), merging fallthrough arms dropping one, or wholesale deleting a case. The signature still verifies — Stripe still returns 200 — paying customers never get provisioned.
Server-Action pins (Next.js App-Router mutations)
Pin the App-Router mutation pattern that /api/* HTTP-route detectors can't see — auth-gated "use server" functions that perform DB writes, file uploads, or paid-API calls. Closes the highest-impact coverage gap reported via real-world dogfood.
npx pinned sweep # auto-detects Server Action writes
npx pinned record-server-action <claim-id> --fixture <payload.json> # capture valid payload + regenerate testDetection covers: supabase / prisma / drizzle / kysely / mongoose / raw SQL DB writes; supabase-storage / S3 / R2 / Vercel Blob file uploads; outbound paid-API calls (Anthropic / OpenAI / Gemini / Stripe). Auth-gate function name (isAdminAuthed, requireAuth, etc.) and zod input-schema name are captured automatically. Until you record a fixture, the pin self-skips with a clear message.
Page accessibility pins (🛟 BETA — opt-in)
Catches the "page renders but is unreadable" class — white-on-white text, WCAG-AA contrast failures, invisible labels. Plain page-renders pins stay GREEN on these because the page does render; this is the only template that catches it.
npx pinned add-browser # one-time: install Playwright (~300 MB)
npx pinned sweep --include-beta # auto-detects pages + emits axe-core pinsLoads each page via Playwright + injects axe-core (pinned version, CDN-loaded) + runs the color-contrast rule. WARN-only on violations (frontend a11y doesn't fail CI) + confidence: "review" so catches don't inflate the GA metric.
Browser interaction pins (🛟 BETA — opt-in)
Cover frontend interaction regressions (the carousel "arrows do nothing" class) by wrapping Playwright. Beta posture: WARN-only on drift, attach-only to a running dev server, catches quarantined as confidence:"review" so they don't inflate the GA metric.
npx pinned add-browser # one-time: install Playwright + Chromium (~300 MB)
npx pinned sweep --include-beta # auto-detect interaction candidates + pin them
npx pinned record-interaction <claim-id> # capture the baseline observation once
npx pinned record-interaction <claim-id> --dry-run # observe without persisting (calibration)Auto-detection finds buttons with stable selectors (data-testid preferred over aria-label) AND an onClick handler. Until you run record-interaction, the pin emits a single warn-only message; only after recording does drift get reported.
Internal (called by hooks)
npx pinned check-guard-removal # pre-commit hook entry; blocks AI bypass attempts
npx pinned statusline # statusline rendering for Claude Code
npx pinned backtest --mode=bug-fix # replay a repo's git history (calibration tool)Optional AI-assisted analysis (BYOK)
PINNEDAI_BYOK=openai PINNEDAI_OPENAI_KEY=sk-... npx pinned checkLLM-as-proposer fires on each commit's diff to suggest additional guards the deterministic detectors might miss. Customer pays their LLM vendor directly; Pinned doesn't proxy.
Statusline
Pinned surfaces protection events without becoming a noisy reviewer. Events decay back to a calm baseline:
◆ pinned · 34 pins · 7 lessons · ✓ 12 verified # baseline
◆ pinned · 34 pins · ⚠ 2 protected files in this commit # editing guarded files
◆ pinned · 34 pins · ⛔ blocked: AI weakened pin sample.test.ts # Guard Integrity refused
◆ pinned · 34 pins · +1 new guard # SAVED
◆ pinned · 34 pins · scanned 3 similar files # AUDIT
◆ pinned · 34 pins · 4 guards passed # COVERED
◆ pinned · 34 pins · learned: don't drop authHeaders() from API calls # LEARNED
◆ pinned · 34 pins · ✗ 1 broken # failing pinThe BLOCK / LEARNED / SAVED / AUDIT / COVERED transients fall back to baseline after 1-2 minutes. Persistent value = guard count + lesson count.
What Pinned is NOT
Pinned is not a generic code reviewer, SAST scanner, or AI bug-fixer.
CodeRabbit reviews PRs. Snyk / Semgrep scan for broad security issues. They run once and leave comments.
Pinned protects the repo-specific promises your AI coder must not forget: the bug fixes, guards, tests, and lessons that should survive future AI edits. The output of every finding is an executable guard, not a comment.
AI and privacy
Pinned works without an LLM. The core engine is deterministic: guards either pass, fail, or were weakened.
Optional AI-assisted mode (BYOK) can propose additional guards, sibling audits, and lessons from diff context. AI output never enforces anything by itself — deterministic guards + CI do the enforcement.
Principle:
LLM proposes. Guards prove. CI enforces.Local-first. Free beta runs entirely on your machine + your CI. Pinned doesn't see your code unless you set BYOK env vars (in which case the calls go directly to your LLM vendor, not through Pinned infrastructure).
Free vs Founder Pro
Free Beta | Founder Pro (waitlist) | |
All deterministic detectors | ✅ Unlimited | ✅ |
Guard Integrity blocks | ✅ | ✅ |
AI Lessons file + agent config wiring | ✅ | ✅ |
Replay-verified bug-fix guards | ✅ | ✅ |
Local audit / probe / context | ✅ | ✅ |
Pre-commit / pre-push hooks | ✅ | ✅ |
Statusline integration | ✅ | ✅ |
Report-only CI (you wire | ✅ | ✅ |
Optional BYOK AI proposer (your own key) | ✅ | ✅ |
PR comments with repair prompts | — | Coming |
Cross-repo AI lessons | — | Coming |
Hosted AI analysis (no API key) | — | Coming |
Cloud proof / history dashboard | — | Coming |
AI / provider mistake analytics | — | Coming |
Managed CI enforcement policies | — | Coming |
Custom guard templates | — | Coming |
Team policies + audit log | — | Coming |
Founder Pro is a waitlist today — no payment, no card. We collect interest to gauge demand for the paid features above. When paid opens, founder pricing locks for everyone on the list.
Status
v0.1 (free beta) ships with:
8 Guard Integrity detectors (23 / 23 known AI bypass tactics blocked in our mutation-test suite)
AI Lessons file + opt-in agent-config wiring (CLAUDE.md, .cursorrules, .github/copilot-instructions.md, etc.)
6 P0 detector categories generating pins at init: Guard Integrity, client fetch / auth-headers / error-handling, auth/middleware, route/export/reference integrity, public exposure, webhook signature
pinned audit --learnedfor sibling discoverypinned probe-adminfor admin-route enumerationpinned contextfor runtime AI-coder briefingStatusline events for BLOCK / SAVED / AUDIT / COVERED / LEARNED / VERIFIED + baseline
N pins · M lessons
Open beta. Bug reports + feature requests welcome at github.com/pinnedai/pinnedai/issues.
License
Apache 2.0. CLI source is public; the Cloudflare Worker that backs the (coming) hosted AI / cross-repo lessons / dashboard features stays private.
Available Tools
6 toolspinned_before_code_changeA
REQUIRED: Call this BEFORE editing code in an AI-coded repo. Returns the active Pinned guards, recent AI lessons learned in this repo, and any current safety notes — so you know what protected behaviors must not regress. If the repo has no Pinned installed, this tool will recommend npx pinnedai init. Treat the returned agent_instruction field as required final-response content.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No | Absolute path to the repository root. Defaults to the AI tool's working directory if not provided. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description bears full responsibility. It reveals the tool returns data (guards, lessons, safety notes, agent_instruction) and recommends initialization if Pinned is absent. However, it does not clarify whether the tool is read-only or has side effects, and lacks details on permissions or performance.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a focused paragraph with front-loaded key information: required usage, returned data, conditional recommendation, and output handling instruction. Every sentence serves a purpose, making it efficient though not ultra-brief.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and no annotations, the description adequately describes the tool's return contents (guards, lessons, safety notes, agent_instruction) and provides a usage example (recommending initialization). This is sufficient for an AI agent to understand what to expect and how to handle the output.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (one parameter 'cwd' with a clear description). The tool description adds no additional meaning or context for this parameter, so it does not improve upon schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool returns Pinned guards, recent AI lessons, and safety notes before editing code, with a specific verb 'Returns' and resource. It distinguishes itself from siblings by emphasizing 'BEFORE editing code' and contrasting with other pinned tools that likely serve different phases.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'REQUIRED: Call this BEFORE editing code', providing a clear when-to-use. It does not explicitly mention when not to use or name alternatives, but the context is clear and sufficient for an AI agent to understand the primary use case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pinned_before_done_checkA
REQUIRED: Call this BEFORE telling the user that a code change / feature / fix is complete. Runs the full Pinned check: scan-diff for unprotected risk surfaces, Guard Integrity check for any tests in tests/pinned/ that were weakened/skipped/deleted, and AI-lessons check. Returns PASS / REVIEW / BLOCK plus a human_summary that you MUST include in your final response. Do not say work is done if status is BLOCK without explicit user acknowledgement.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No | Optional repository root. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It discloses the checks performed, the return statuses (PASS/REVIEW/BLOCK), and the required human_summary. However, it does not explicitly state whether the tool is read-only or if it has side-effects, which would be beneficial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise at 4 sentences, front-loaded with the critical requirement, and every sentence adds value. No extraneous information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no annotations and one optional parameter, the description provides complete context: what checks are run, what output to expect, and how to handle the result. No output schema, but the description compensates adequately.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter 'cwd' is described as 'Optional repository root.' The input schema already documents it as an optional string. The description adds no additional semantic value beyond the schema. Schema coverage is 100%, so baseline is 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool runs the full Pinned check including scan-diff, Guard Integrity, and AI-lessons checks, and explicitly says it must be called before declaring work complete. This distinguishes it from sibling tools like pinned_before_code_change.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance: 'Call this BEFORE telling the user that a code change / feature / fix is complete.' It also instructs not to say work is done if status is BLOCK without user acknowledgement. Alternatives are implied by sibling tool list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pinned_check_pr_descriptionA
Parse a PR description / commit message / spec for behavioral claims (auth, rate-limits, webhook idempotency, permissions, URL preservation, status codes, etc.) and return the structured claim list. Call this when the user shows you a PR body or asks 'what does this PR claim'.
| Name | Required | Description | Default |
|---|---|---|---|
| description | Yes | The PR body / commit message / spec text to parse. | |
| cwd | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It states the tool parses and returns a structured claim list, implying a read-only operation. However, it does not disclose any side effects, auth needs, or rate limits. The description is adequate but not thorough.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences: first states purpose with example claims, second gives usage instruction. No fluff, front-loaded, every sentence contributes.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 2 parameters and no output schema, the description is fairly complete. It explains input type and output as 'structured claim list' but doesn't define the structure. Given the sibling tools context, this is adequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50% (only 'description' has a description). The tool description does not add additional meaning to parameters; it only repeats that the first parameter is the text to parse. The 'cwd' parameter receives no explanation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it parses a PR description/commit message/spec for behavioral claims and returns a structured list. It lists example claims (auth, rate-limits, etc.) and distinguishes from siblings by being specific to PR bodies and claims extraction.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'Call this when the user shows you a PR body or asks what this PR claims.' It provides clear usage context but does not mention alternatives or when not to use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pinned_list_guardsA
List the active Pinned guards in the repository. Use when the user asks 'what is protected here?' or when you're about to propose changes to a file path that may be guarded.
| Name | Required | Description | Default |
|---|---|---|---|
| include_retired | No | ||
| cwd | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, description clarifies listing is read-only, though it doesn't explain what 'Pinned guards' are.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two clear, front-loaded sentences with no redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Simple listing tool, but missing parameter guidance and no output schema; adequate for basic use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
No description of the two optional parameters (include_retired, cwd); schema coverage is 0%, so description should compensate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it lists active Pinned guards, which distinguishes it from sibling tools that handle checks or suggestions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly gives scenarios: when user asks 'what is protected here?' or before proposing changes to guarded paths.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pinned_scan_diffA
Scan the current git diff (vs origin/main by default) for risky surfaces — new routes, webhook handlers, middleware changes, env file edits — that don't yet have a Pinned guard. Use during code-change work; pinned_before_done_check calls this internally.
| Name | Required | Description | Default |
|---|---|---|---|
| base | No | Base ref. Defaults to 'origin/main' or 'main'. | |
| cwd | No | Optional repository root. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries full burden. Lists specific risky surfaces and default base ref, but doesn't clarify side effects, auth requirements, or whether the tool is purely read-only (it is). Could be more explicit about the 'scan' action and return format.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with purpose and key details. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema, so description doesn't explain return values. It provides context about internal usage by another tool and lists specific scan targets. Lacks description of output format but is mostly complete for a simple scanning tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for 2 parameters. Description adds only minor clarification (default base is 'origin/main' or 'main') which duplicates schema. No additional semantic value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specifically describes scanning git diff for risky surfaces (routes, webhooks, middleware, env edits) lacking Pinned guards. Distinguishes from siblings by mentioning it's used during code-change work and that pinned_before_done_check calls it internally.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States 'Use during code-change work' and implies indirect usage via pinned_before_done_check. Does not explicitly list alternatives or when-not-to-use, but context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pinned_suggest_initA
Check whether a repository has Pinned installed. Returns status=missing with a recommended npx pinnedai init command if the repo is unprotected. Call this at the start of work on an unfamiliar repo.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses that the tool returns status=missing with a recommended command if the repo is unprotected, but it does not specify what happens if Pinned is already installed (e.g., status=ok). Given no annotations, this is a partial behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no fluff. The first sentence states purpose and return behavior, the second provides usage timing. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple check tool with one optional parameter and no output schema, the description provides adequate context: purpose, return behavior for one case, and usage timing. It lacks full return state coverage (e.g., when Pinned is installed) but is otherwise sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description compensates by implying the tool operates on a repo (likely via cwd). However, it does not explicitly explain the cwd parameter's purpose or default behavior, leaving room for ambiguity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool checks if a repository has Pinned installed, using a specific verb (check) and resource (Pinned installation status). It distinguishes itself from siblings that deal with code changes, PR descriptions, guards, and diffs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly recommends calling this tool at the start of work on an unfamiliar repo, providing clear context. However, it does not mention when not to use it or any alternative tools for similar checks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v1.0.0- First observed
pinned_before_code_change - First observed
pinned_before_done_check - First observed
pinned_check_pr_description - First observed
pinned_list_guards - First observed
pinned_scan_diff - First observed
pinned_suggest_init
TDQS
Scored across 6 tools
Each tool has a clearly distinct purpose: pre-change checks, completion verification, PR parsing, guard listing, diff scanning, and initialization. No overlap in functionality.
All tool names follow a consistent 'pinned_<action>' snake_case pattern, making them predictable and easy to differentiate.
6 tools is well-scoped for the domain of AI safety guards, covering all necessary operations without redundancy.
The tool set covers the full lifecycle: initialization, pre-change context, diff scanning, guard listing, PR claim parsing, and completion verification. No obvious gaps for the intended use case.
Maintenance
Related MCP Connectors
Deterministic runtime safety for AI agents: scan PII, gate tool actions, verify LLM output.
Pre-execution governance for AI agents. Deterministic PASS/FAIL/REVIEW verdicts, replayable proof.
Guardian agent for AI coding: four frontier models review risky diffs and commits before they ship.
Security reviews for coding agents: diffs checked against your org policy and live infrastructure.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables automatic knowledge capture and injection of guardrails for AI assistants like Claude and Cursor, improving code quality and preventing recurring mistakes.12 npmMIT
- AlicenseNot gradedqualityAmaintenanceA runtime gate for coding agents. Blocks the tool calls that wreck a repo (force-push main, rm -rf, secret exfiltration, CI wipe) and lets normal build and commit work through. Machine-checked git-branch core (z3); the rest is high-precision heuristics. Tested on 3,790 real CI commands, 0 false blocks.1MIT
- AlicenseAqualityBmaintenanceEnforces AST-based architectural guardrails on AI-generated code, blocking writes that violate maintainability, security, or complexity rules and prompting immediate refactoring.2MIT

agentguardofficial
AlicenseNot gradedqualityCmaintenanceEnforces policy controls for AI agents, including spend limits, action approvals, kill switch, scoped credentials, dry-run diffs, loop prevention, and auditable hash-chained logs.MIT