Skip to content

Repository files navigation

SourcePin

English | 简体中文

npm version CI license

Pin feedback to UI. Trace it to source.

SourcePin is a local-first visual feedback layer for coding agents. Click an element in a running Vite app, leave a comment, and SourcePin records the route, DOM identity, component, and source location in the repository. A later Codex session can pick up the pin, edit the right code, and return the result for human review.

click UI → leave feedback → agent fixes source → human accepts or reopens

No cloud account is required. Pins live under .sourcepin/, travel with the project when you choose to commit them, and remain human-owned at the final acceptance step.

SourcePin overlay showing numbered UI pins and the feedback drawer with Open, Awaiting review, and Accept states

The real SourcePin development overlay running on the included billing demo: numbered targets stay attached to the page while the complete drawer tracks feedback and human review.

Run the same interactive demo locally:

pnpm install
pnpm demo

Then open http://127.0.0.1:4190, click SourcePin, and choose a mode: Element clicks to create a durable pin or drags a source-addressed target; Text keeps native browser selection and exposes Copy context / Drag to agent; Region draws a viewport rectangle and exports up to eight intersecting DOM/source candidates. All drag paths use bounded text/plain plus structured application/x-sourcepin, and never submit destination input automatically. Region coordinates are evidence only, not persistent identity. Terminal support varies, so normal pin persistence and copy remain the reliable fallback.

What's new in 0.2.0

  • Next.js App Router support through the verified next dev --webpack path, with a project-local Route Handler and production stripping.
  • Direct element drag into compatible coding-agent/terminal text targets.
  • Native text selection with Copy context and Drag to agent.
  • Region selection with bounded intersecting DOM/source candidates.
  • Compact, mutually exclusive Element / Text / Region controls that do not auto-submit agent input.

The durable pin/MCP workflow remains canonical for cross-session work; drag and copy modes are fast handoff paths for an agent session that is already open.

Why SourcePin?

A screenshot or issue saying “fix this button” leaves an agent guessing. SourcePin gives it structured context:

  • the route and internal UI surface where the problem appeared;
  • a stable selector and semantic fallback anchor;
  • the React/Vue component and project-relative source location;
  • the original comment, viewport, and element geometry;
  • a constrained review state that the agent cannot self-accept.

SourcePin is useful for interaction, copy, layout, and state bugs. Screenshots are optional evidence—not a requirement and not an automatic visual-model call.

Quick start

1. Install

pnpm add -D sourcepin

2. Add the Vite plugin

Place SourcePin before the framework plugin so it can inspect the original JSX/TSX or Vue template.

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import sourcepin from "sourcepin/vite";

export default defineConfig({
  plugins: [sourcepin(), react()],
});

The same ordering applies to Vue:

plugins: [sourcepin(), vue()]

3. Mount the development overlay

// src/main.tsx, src/main.ts, or equivalent
import { mountSourcePin } from "sourcepin";

if (import.meta.env.DEV) {
  void mountSourcePin();
}

Start the app, click the purple SourcePin button, select an element, and write feedback. The left-side Feedback button opens the review drawer.

Pins are saved as validated JSON:

.sourcepin/pins/pin_<uuid>.json

Next.js App Router

Available in sourcepin@0.2.0 and later.

SourcePin supports Next.js App Router projects through the webpack development path. Configure Next to add source metadata and rewrite the browser protocol to a project-local Route Handler:

// next.config.mjs
import { withSourcePin } from "sourcepin/next";

export default withSourcePin({}, { root: process.cwd() });

Use webpack while developing:

{
  "scripts": {
    "dev": "next dev --webpack"
  }
}

Add one catch-all App Router handler. The public /__sourcepin/* protocol is rewritten here because underscore-prefixed App Router folders are private:

// app/sourcepin-api/[...sourcepin]/route.ts
import { createSourcePinRouteHandlers } from "sourcepin/next";

export const dynamic = "force-dynamic";
const handlers = createSourcePinRouteHandlers({ root: process.cwd() });
export const { GET, POST, PATCH } = handlers;

Mount the client overlay only when the server layout is running in development:

// app/sourcepin.tsx
"use client";

import { useEffect } from "react";
import { mountSourcePin } from "sourcepin";

export function SourcePinOverlay() {
  useEffect(() => {
    let dispose: undefined | (() => void);
    void mountSourcePin().then((value) => { dispose = value; });
    return () => dispose?.();
  }, []);
  return null;
}
// app/layout.tsx (inside <body>)
{process.env.NODE_ENV === "development" ? <SourcePinOverlay /> : null}

The adapter currently targets next dev --webpack; Turbopack is not claimed. The package gate installs the packed tarball into an independent Next.js 16 App Router consumer, creates and reloads a real pin in Chromium, reads it back through the Route Handler and repository store, runs next build --webpack, then verifies that production HTML contains neither source metadata nor the overlay.

Daily workflow

Leave feedback in the browser

The overlay provides:

  • element hover and selection;
  • numbered markers attached to live targets;
  • a collapsible feedback drawer;
  • Open, Review, and Accepted filters;
  • cross-route navigation and internal-tab restoration;
  • human-only Accept and Reopen actions.

Give the agent repository instructions

Install the bundled SourcePin skill into the consuming project:

pnpm exec sourcepin init

A CLI-only agent can then discover and inspect work:

pnpm exec sourcepin next --json
pnpm exec sourcepin context pin_<id>

After changing the code and running the relevant tests, the agent returns the pin for review:

pnpm exec sourcepin changed pin_<id> src/components/Card.tsx

The status lifecycle is deliberately asymmetric:

open ──agent──▶ changed-awaiting-review ──human──▶ accepted
  ▲                         │                              │
  └────────────── human reopen ◀──────────────────────────┘

The agent can report a verified change. Only a human can accept it.

Codex MCP

SourcePin includes a stdio MCP server. Register it from the consuming repository:

codex mcp add sourcepin -- pnpm exec sourcepin-mcp

Verify the registration:

codex mcp list

Available tools:

Tool Purpose Mutates pin state
list_pins List and filter feedback No
get_context Return the pin, bounded source snippet, and surface metadata No
mark_changed Move an open pin to human review after verified edits Yes

There is intentionally no MCP accept tool. Read-only tools declare MCP safety annotations, and all operations are constrained to the current repository.

How target recovery works

SourcePin never persists an HTMLElement. DOM nodes may disappear when a React/Vue branch unmounts, a modal closes, or a virtualized row is recycled. Instead, each pin stores several independent signals.

Selector preference:

data-testid
→ data-sourcepin-key
→ id
→ injected source metadata
→ bounded DOM path

If the preferred selector drifts, SourcePin scores semantic candidates using the element tag, text, role, accessible name, and source location. It restores a marker only when one candidate wins unambiguously.

Target states shown by the drawer:

State Meaning
attached One visible target is currently resolved
dormant The target is hidden/unmounted but its UI surface can be restored
unresolved No reliable current target exists; the feedback remains available to the agent
ambiguous Multiple candidates are equally plausible, so SourcePin refuses to guess

SourcePin never falls back to drawing a marker at stale screen coordinates.

Tabs, modals, and transient UI

Standard ARIA tabs are detected through role="tabpanel" and the corresponding role="tab". Clicking a dormant feedback card can reactivate the recorded tab and resolve the target again.

For custom internal views, add an explicit surface:

<section
  data-sourcepin-surface="settings.billing"
  data-sourcepin-surface-label="Billing"
>

For repeated rows with otherwise identical text and source metadata, add a stable business key:

<article data-sourcepin-key="user:42">

Stored activation recipes are limited to structured actions such as a selector-based click. Pin files cannot contain arbitrary JavaScript.

Framework support

Surface Status
Vite middleware and overlay Supported
React JSX/TSX source injection Supported
Vue SFC template source injection Supported
React/Vue conditional unmount and hidden DOM Supported
ARIA tabs and explicit custom surfaces Supported
Next.js App Router (next dev --webpack) Supported since 0.2.0; independently dogfooded
Nuxt-native and SvelteKit adapters Out of scope
Browser extension Out of scope; project integration provides more reliable source mapping

Vue injection uses the Vue template AST and leaves <script> strings and component tags untouched. JSX/TSX injection uses the Babel AST. Both transforms fail open rather than blocking the development build on unsupported syntax.

Storage and security

SourcePin is designed for local development:

  • Vite middleware writes only validated files under .sourcepin/pins/;
  • each repository root is an independent store, so parallel Codex sessions in different projects cannot see one another's pins;
  • updates to the same pin use a project-local atomic lock and atomic rename, so concurrent agents cannot both complete the same open → changed-awaiting-review transition;
  • pin IDs, routes, selectors, geometry, source paths, surfaces, and evidence paths are validated;
  • request bodies are bounded;
  • source-context reads reject lexical and symlink escapes from the repository;
  • comments are treated as untrusted feedback, not executable agent instructions;
  • UI text is rendered without unsafe HTML insertion;
  • final acceptance remains human-owned.

If middleware is unavailable, the browser can temporarily fall back to localStorage. The fallback key includes a stable fingerprint of the Vite project root, preventing projects that reuse the same localhost origin from sharing fallback pins. Repository-backed pins remain the canonical path for cross-session agent work.

Optional visual evidence

A pin may reference screenshots produced by a separate adapter or sidecar:

{
  "evidence": {
    "screenshots": [".sourcepin/assets/pin_example.png"]
  }
}

Evidence is limited to 20 project-local PNG/JPEG/WebP files under .sourcepin/assets/, which is ignored by default. SourcePin does not capture the screen or invoke a visual model automatically.

CLI reference

sourcepin init
sourcepin list [--json]
sourcepin next [--json]
sourcepin show <pin_id>
sourcepin context <pin_id>
sourcepin changed <pin_id> <changed_files...>
sourcepin accept <pin_id>
sourcepin reopen <pin_id>

Use changed from an agent session. Reserve accept and reopen for human review.

Development

Requirements: Node.js 20+ and pnpm 10.15.1.

pnpm install
pnpm exec playwright install chromium
pnpm gate

pnpm gate runs:

  • strict TypeScript checking;
  • unit and protocol tests;
  • the library build;
  • the billing demo build;
  • a packed-tarball consumer smoke;
  • a real stdio MCP handshake and tool invocation;
  • Chromium end-to-end tests for Element/Text/Region handoff modes, persistence, scrolling, routes, tabs, hidden/transient DOM, selector drift, and browser review actions.

GitHub Actions runs the same gate on Linux. npm releases use Trusted Publishing/OIDC with provenance.

Project status

SourcePin is an early public release focused on proving the local UI-to-source feedback loop. The core Vite, React/Vue, Next.js App Router over webpack, CLI, MCP, review, packaging, and CI paths are implemented and tested. Turbopack support is not claimed. Nuxt-native, SvelteKit, and browser-extension adapters are out of scope. Comment editing/deletion and stronger source fingerprints remain possible future work.

License

MIT

About

Pin feedback to UI and trace it to source for coding agents

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages