
Research
Shai-Hulud Descends to Hades: Miasma Worm Campaign Spreads with New PyPI Wave
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.
@agent-native/pinpoint
Advanced tools
Visual feedback and annotation tool for agent-native web applications
Visual feedback and annotation tool for web applications. Users select UI elements, add feedback, and send structured context to any AI agent.
Works standalone, with Builder.io, or with any agent runtime that speaks the agent-native protocol (Builder.io, Claude Code, Codex, Gemini CLI, Cursor, etc.).
Instructions for an AI agent (Builder.io, Claude Code, Codex, Cursor, etc.) to add Pinpoint to an agent-native repository.
pnpm add @agent-native/pinpoint
npx @agent-native/pinpoint init
This copies agent actions to actions/ and the Pinpoint skill to .agents/skills/pinpoint/. No manual file copying needed.
Find the root React component (typically app/App.tsx or src/App.tsx). Add the <Pinpoint /> component:
import { Pinpoint } from "@agent-native/pinpoint/react";
// Add as a sibling to your app root — renders nothing, mounts overlay in Shadow DOM
<Pinpoint author="User" endpoint="/api/pins" autoSubmit colorScheme="auto" />;
If the app is not React-based, use the imperative API:
import { mountPinpoint } from "@agent-native/pinpoint";
mountPinpoint({ author: "User", endpoint: "/api/pins", autoSubmit: true });
Find the Express server setup (typically server/index.ts). Add the pin routes:
import { pagePinRoutes } from "@agent-native/pinpoint/server";
// Add before your page routes
app.use("/api/pins", pagePinRoutes());
This creates REST endpoints at /api/pins for pin CRUD. Pins are stored as JSON files in data/pins/.
Cmd+Shift+. to toggle the Pinpoint toolbarPins are stored as individual JSON files in data/pins/{uuid}.json:
{
"id": "uuid",
"pageUrl": "/dashboard",
"comment": "This button color is wrong",
"element": {
"tagName": "button",
"selector": ".sidebar button.primary",
"classNames": ["primary", "btn"]
},
"framework": {
"framework": "react",
"componentPath": "<Sidebar> <ActionButton>",
"sourceFile": "src/components/Sidebar.tsx:42"
},
"status": { "state": "open" }
}
Key fields for agents:
sourceFile — the exact file and line to editcomponentPath — the React/Vue component hierarchyselector — CSS selector to find the element in the DOMcomment — what the user wants changedAgent commands (available after npx @agent-native/pinpoint init):
pnpm action get-pins --status open — list unresolved pinspnpm action resolve-pin --id <uuid> — mark as resolved after fixingpnpm action create-pin --pageUrl / --selector ".btn" --comment "Fix this"pnpm action update-pin --id <uuid> --comment "Updated feedback"pnpm action delete-pin --id <uuid> — remove a pinWorkflow:
pnpm action get-pins --status opensourceFile to locate and edit the relevant codepnpm action resolve-pin --id <uuid>| Issue | Fix |
|---|---|
| Toolbar doesn't appear | Check that <Pinpoint /> is mounted. Press Cmd+Shift+. |
| Pins not persisting | Ensure endpoint="/api/pins" is set and server middleware is added |
sourceFile is empty | Source detection requires dev mode. Production builds strip _debugSource |
| "Cannot find module" | Run pnpm install. Check the package is in dependencies |
pnpm add @agent-native/pinpoint
# or
npm install @agent-native/pinpoint
import { Pinpoint } from "@agent-native/pinpoint/react";
function App() {
return (
<>
<Pinpoint author="Designer" endpoint="/api/pins" autoSubmit />
<YourApp />
</>
);
}
<script src="https://unpkg.com/@agent-native/pinpoint/dist/index.browser.js"></script>
<script>
Pinpoint.mountPinpoint({ author: "Designer" });
</script>
import { mountPinpoint } from "@agent-native/pinpoint";
const { dispose } = mountPinpoint({
author: "Designer",
endpoint: "/api/pins",
});
// Call dispose() to unmount
pnpm add @agent-native/pinpoint
npx @agent-native/pinpoint init
Copies agent actions to actions/ and the Pinpoint skill to .agents/skills/pinpoint/.
// app/App.tsx
import { Pinpoint } from "@agent-native/pinpoint/react";
function App() {
return (
<>
<Pinpoint
author="Designer"
endpoint="/api/pins"
autoSubmit
colorScheme="auto"
/>
<YourApp />
</>
);
}
// server/index.ts
import { createServer } from "@agent-native/core/server";
import { pagePinRoutes } from "@agent-native/pinpoint/server";
const app = createServer({
/* ... */
});
app.use("/api/pins", pagePinRoutes());
Cmd+Shift+. (or Ctrl+Shift+.)Cmd+Shift+EnterThe agent receives structured context: CSS selector, component hierarchy, source file location, and the user's comment.
All options can be passed as props to <Pinpoint /> or as the config object to mountPinpoint():
| Option | Type | Default | Description |
|---|---|---|---|
author | string | — | Who is annotating |
endpoint | string | — | REST endpoint for persistence (e.g., /api/pins) |
colorScheme | 'auto' | 'light' | 'dark' | 'auto' | Theme |
outputFormat | 'compact' | 'standard' | 'detailed' | 'standard' | Detail level in agent output |
autoSubmit | boolean | true | Auto-submit annotations to agent chat |
clearOnSend | boolean | false | Clear pins after sending |
sendToAgent | (output) => void | Promise<void> | — | Custom bridge for annotation delivery |
blockInteractions | boolean | false | Block page clicks during selection |
compactPopup | boolean | true | Hide technical details behind toggle |
freezeJSTimers | boolean | false | Freeze JS timers during selection |
allowedOrigins | string[] | — | Allowed origins for postMessage |
webhookUrl | string | — | Webhook URL for pin events |
includeSourcePaths | boolean | — | Include source file paths in output |
markerColor | string | '#3b82f6' | Badge color on annotated elements |
plugins | Plugin[] | — | Plugin extensions |
storage | PinStorage | — | Custom storage adapter |
position | { x, y } | — | Initial toolbar position |
npx @agent-native/pinpoint init # Copy actions and skill to your project
npx @agent-native/pinpoint # Show help
| Shortcut | Action |
|---|---|
Cmd/Ctrl+Shift+. | Toggle toolbar |
Cmd/Ctrl+Shift+C | Copy annotations to clipboard |
Cmd/Ctrl+Shift+Enter | Send annotations to agent |
Esc | Close popup / collapse toolbar |
Shift+Drag | Multi-select elements |
| Import Path | What It Provides |
|---|---|
@agent-native/pinpoint | mountPinpoint(), unmountPinpoint(), types |
@agent-native/pinpoint/react | <Pinpoint /> React component |
@agent-native/pinpoint/server | pagePinRoutes() Express middleware |
@agent-native/pinpoint/primitives | getElementContext(), freeze(), unfreeze(), openFile() |
@agent-native/pinpoint/types | TypeScript types (Pin, PinpointConfig, etc.) |
Express middleware for pin CRUD:
import { pagePinRoutes } from "@agent-native/pinpoint/server";
app.use("/api/pins", pagePinRoutes({ dataDir: "data/pins" }));
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/pins | List pins (query: pageUrl, status) |
| GET | /api/pins/:id | Get a pin |
| POST | /api/pins | Create a pin |
| PATCH | /api/pins/:id | Update a pin |
| DELETE | /api/pins/:id | Delete a pin |
| DELETE | /api/pins | Clear pins (query: pageUrl) |
Available after running npx @agent-native/pinpoint init:
| Action | Purpose | Args |
|---|---|---|
get-pins | List pins | --pageUrl, --status |
create-pin | Create a pin | --pageUrl, --selector, --comment |
resolve-pin | Mark as resolved | --id, --message |
update-pin | Update a pin | --id, --comment, --status |
delete-pin | Remove a pin | --id |
list-sessions | List pages with pins | — |
Standalone functions for programmatic element inspection (no UI):
import {
getElementContext,
freeze,
unfreeze,
openFile,
detectFramework,
} from "@agent-native/pinpoint/primitives";
const context = getElementContext(document.querySelector(".sidebar"));
freeze(); // Pause all animations
unfreeze(); // Resume
openFile("src/components/Sidebar.tsx", 42); // Open in editor
import type { Plugin } from "@agent-native/pinpoint/types";
const myPlugin: Plugin = {
name: "analytics",
hooks: {
onPinCreate(pin) {
analytics.track("pin_created", { page: pin.pageUrl });
},
onPinResolve(pin) {
analytics.track("pin_resolved", { id: pin.id });
},
transformOutput(output) {
return output + "\n\n_Sent via Pinpoint_";
},
},
actions: [
{
label: "Export to Jira",
handler(element, context) {
createJiraTicket(context);
},
},
],
};
Expose pins to external agents via A2A or MCP:
import {
registerPinpointA2A,
createPinpointMCPTools,
} from "@agent-native/pinpoint/server";
registerPinpointA2A(app); // /.well-known/agent-card.json
const { tools, handleTool } = createPinpointMCPTools(); // MCP tool handlers
| Framework | Detection | Component Info | Source Location |
|---|---|---|---|
| React 18/19 | Auto (via bippy) | Component hierarchy | _debugSource / element-source |
| Vue 3 | Auto (__VUE__) | Component tree | $options.__file |
| Other | Fallback | DOM-only | Not available |
| Adapter | Use Case | Persistence |
|---|---|---|
MemoryStore | Standalone, no server | Session only (lost on reload) |
RestClient | Browser with server | Server-side via REST API |
FileStore | Server-side | data/pins/{uuid}.json |
Inside Builder.io's Fusion, annotations are sent via sendToAgentChat() from @agent-native/core:
<Pinpoint author="Builder User" autoSubmit outputFormat="standard" />
No additional configuration needed when running inside a Builder.io project.
Hosts with their own chat implementation can pass sendToAgent to reuse Pinpoint's pin,
draw, queue, and prompt UI while delivering { message, context, submit } themselves.
MIT
FAQs
Visual feedback and annotation tool for agent-native web applications
The npm package @agent-native/pinpoint receives a total of 176 weekly downloads. As such, @agent-native/pinpoint popularity was classified as not popular.
We found that @agent-native/pinpoint demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.

Security News
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.

Security News
pnpm 11.5 now recognizes npm staged publish approvals in release metadata, preventing those releases from being mistaken for lower-trust package publishes.