
Loopback
io.github.joshidikshant由 GitHub 帳號 joshidikshant 發布v0.9.4更新於 Oct 24, 2026
Feedback bus for coding agents: pin feedback on the app you're building; a fix turns the pin green
概覽
讓編碼代理處理共享回饋佇列:在本地執行中的應用程式上以元素為錨點釘選回饋,並附帶主控台、網路與執行脈絡。
- 可以做什麼
- Loopback 是給編碼代理使用的本地回饋中樞。嵌入本地執行中應用程式的元件讓你在頁面元素上釘選回饋,釘選時會擷取主控台訊息、含回應內容的失敗請求、路由歷程與 AI 執行中介資料。十個 MCP 工具讓代理提交、列出、讀取、修改、認領、留言、連結變更、解決與統計回饋項目;修復經驗證後,頁面上的標記會變成綠色。
- 適用情境
- 當你希望 Claude Code、Codex 或 Gemini CLI 等代理直接處理執行中應用程式的真實回饋,而不是重新描述提示時使用。適合本地開發的網頁應用程式、Electron/Tauri 應用程式、WebView、模擬器,以及把項目寫入同一個依專案標記佇列的 CI 或排程工作。
- 執行需求
- 需要 Node.js 22.13 或更新版本;npm 套件 loopback-mcp-server 以 stdio 執行,或作為 127.0.0.1:7077 上的常駐 HTTP 服務執行(元件需要後者)。每個應用程式需加入元件指令碼標籤與專案代稱。未宣告帳號或 API 金鑰;非回送位址綁定需要 LOOPBACK_TOKEN 或自動產生的權杖。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Loopback,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
Loopback
Pin feedback on the app you're building. Any coding agent claims it. The pin turns green when the fix is verified.
Loopback is the interactive feedback layer between real product usage and your
coding agents: one script tag makes the app you're running locally commentable
(Vercel-toolbar-style toolbar, element-anchored pins; deployed public sites go
via the /ingest rails instead — see surface compatibility), every pin auto-captures
the functional context — failing requests with response bodies, console
trail, the route journey that led there, LLM run metadata, typed repro steps —
and lands in one project-tagged queue that Claude
Code, Codex, and Gemini CLI all work over MCP. When an agent's fix is
verified, the pin turns green on the page, live.
[CI] [npm] [node] [License: MIT]
https://github.com/user-attachments/assets/1e1b2f9f-0130-4b1d-a0dd-3aff8d801d5a
![The loop, closed: a green verified pin on the form claude-code fixed (PR linked), an amber open pin on the AI answer, and the Loopback panel listing both]
Seeded demo capture (generated by scripts/screenshot.mjs): the contact form's
backend bug pinned, claimed by claude-code, marked fixed with a linked change,
verified — pin and badge green. The wrong AI answer is still amber/open.
Why
Coding agents can fix anything you can describe — but the loop back from real usage is missing. You notice a broken flow, screenshot it, re-describe it in a prompt, paste console output, explain which project it belongs to. Every time, for every agent. Vercel's comments have no public API; Claude Design's anchored comments are artifact-scoped; error trackers don't know your queue.
Loopback is that missing loop, built as a hub:
- One instance, all projects. Every item is tagged with a
projectslug in one shared SQLite DB (~/.loopback/loopback.db). Agents registered once per machine; consuming repos add only a widget tag and a slug. - One queue, all agents. MCP is the interface, so Claude Code, Codex, and Gemini CLI are peers — same tools, same playbook, same audit trail.
- A pin is an anchor, not a scope. Pin a "broken" contact form and the
agent gets the failing
POSTwith its 500 response body — a frontend pin carries the backend root cause. Pin an AI answer and the run metadata (run_id,model,trace_url) rides along.
Run it per-invocation over stdio (each agent spawns it; same DB = same
queue) or as one long-running --http service on 127.0.0.1:7077
(required for widgets — keep it alive with pm2/launchd/systemd:
integrations/keep-alive.md).
Quickstart (see the whole loop in 2 minutes)
Requires Node ≥ 22.13 (built-in node:sqlite — zero native deps).
Open http://127.0.0.1:5173 → submit the form (it fails politely) → ✦ Loopback → Pin feedback on an element → click the submit button → Send. The form shows the captured failed request. Then tell any connected agent "work the feedback queue for acme-demo" — or watch the item at http://127.0.0.1:7077/queue and be the agent yourself over MCP. When it's resolved, the open page announces it and the pin goes green.
Install once per machine
Register the MCP server + instructions once per agent; after this, new projects
are a two-minute init. The copy-paste version — Claude Code (.mcp.json in
your project, or ~/.claude.json for all projects):
Codex and Gemini CLI take the same command/args in their own config — the
server is the same binary over stdio. All three are equal citizens — full
per-agent pages in integrations/:
All three also accept the long-running instance over streamable HTTP
(http://127.0.0.1:7077/mcp) instead of spawning — see the per-agent pages.
Integrate a new project (2 minutes)
- Central instance running (once per machine):
loopback-mcp-server --http, kept alive per keep-alive.md. - Paste the widget tag into the app, with your slug (template):
- From the repo root:
One canonical playbook
(integrations/instructions-src.md) is
rendered into every agent's native mechanism: the AGENTS.md queue
section (canonical; Codex + Gemini read it natively),
@AGENTS.mdimports in CLAUDE.md and GEMINI.md, the same SKILL.md installed for Claude (.claude/skills/) and Codex (.agents/skills/), MCP registration for all three (.mcp.json,.gemini/settings.json,.codex/config.toml), and a/loopbackGemini command. Merges are non-destructive and idempotent — re-run it anytime. - In any of the three agents, say: "work the feedback queue for my-app" — or say nothing: the skill descriptions and AGENTS.md section make feedback-ish requests trigger the loop on their own.
Using it day to day
With the hub running (loopback-mcp-server --http), everything happens on two
surfaces and one sentence to an agent:
Writes that change an item (comment, status) are same-origin only — see Security below.
Giving feedback about Loopback
Loopback is its own reference integration — it eats its own dog food, and so can you. Four ways in, from most to least convenient:
- Pin it on the queue page. With the hub running, open
http://127.0.0.1:7077/queue— the capture widget is embedded there withdata-project=loopback. Click ✦ Loopback → Pin feedback on an element, click whatever is wrong, describe it. Same loop as any other project. - Tell an agent. In this repo (self-onboarded with its own
init), say "file feedback for loopback: <what's wrong>" — the skill and AGENTS.md section are already installed for Claude, Codex, and Gemini. curlit from anywhere:- GitHub issues for anything a stranger should see: https://github.com/joshidikshant/loopback/issues.
Then work it like any queue: "work the feedback queue for loopback". Every Loopback defect in this repo's history was filed and closed exactly this way.
The dashboard
/queue is a React + shadcn app (dashboard/, built with the real shadcn
CLI). Filter by clicking status tiles or any project / severity / type cell —
filters compose and live in the URL, so every view is linkable. Open an item to
read everything captured, edit it (title, body, severity, type — every change
lands on the audit trail), comment, change status, and attach files.
Attachments declare why they exist, because that decides what an agent does:
Blobs live in ~/.loopback/blobs/<item>/, beside the DB rather than inside it,
and agents get an absolute local path so they copy the file instead of
decoding it out of the protocol.
The build output is committed to public/dashboard/, so
npx loopback-mcp-server still needs no React, no Tailwind and no build step —
the hub just serves files. npm run dashboard:build after changing
dashboard/src; dashboard-gate fails CI if the committed build has drifted.
Design system (shadcn-compatible, zero dependencies)
Both surfaces — widget and /queue — are built from one token set in vanilla
CSS that speaks shadcn/ui's contract (oklch variables, .dark, the
multiplicative radius scale). No React, no Tailwind, no build step; drop
design/tokens.css into any shadcn/v0 project and it themes from that
project's palette. Full rationale and the shadow-DOM isolation rules:
design/README.md.
Loopback also publishes a shadcn registry, so React projects can install its pieces and the shadcn MCP can discover them:
Three items:
loopback-themeships the FULL shadcn theme contract (background, foreground, primary, muted, ring, radius…) alongside the--lb-*feedback status/severity tokens, so installing it replaces your palette. If you only want the Loopback-specific tokens, copy the--lb-*block out ofdesign/tokens.cssinstead.loopback-components— vanilla CSS recipes for the shadcn component vocabulary (lb-btn,lb-badge,lb-card…), for surfaces that want the look without React.loopback-widgetdrops the capture widget intopublic/.
Register "@loopback" in your components.json to install by name and let an
agent with the shadcn MCP browse the registry.
Where it works (surfaces)
The queue is transport-agnostic — the widget is just its richest producer. Full matrix, native snippets (Swift/Kotlin/C#/shell), and the honest edges: docs/05-surface-compatibility.md.
The widget
~58KB (19KB gzipped) of dependency-free vanilla JS in a shadow-DOM host — it never fights your app's CSS or framework.
- Capture: pin mode highlights elements on hover; a click opens a
viewport-clamped form (title / what happened / what you expected / type /
severity). Type is pre-guessed:
backendwhen failed requests exist,usagewhen AI context is present. - Functional context, always on: ring buffers from page load keep the last
30 console lines (log/warn/error + window errors + unhandled rejections) and
the last 30 fetch/XHR calls (url/method/status/ms); a filed report carries
the most recent 15 of each, plus — for failures (status ≥ 400 or network
error) — up to 2KB of response body into
extra.failed_responses. Calls to Loopback itself are never recorded. - AI/automation context: the nearest ancestor with
data-loopback-context='{"run_id":...}'is parsed intoextra.context. - Selector + element: stable CSS selector (
#id/[data-testid]preferred,nth-of-typefallback, depth-capped) + outerHTML snippet + viewport + UA. - SPA-aware: client-side route changes (
pushState/popstate) refresh pins immediately — no stale pins from the previous route. - Live status pins: hydrate from
GET /feedbackon load and every 10s — amberopen, deeper ambertriaged, bluein_progress, pale greenfixed(an agent says it is done), full greenverified(confirmed against the running app), graywontfix. The two greens are deliberately different: the pin earning its full colour only atverifiedis the whole point, sofixedreads as provisional. Click a pin for id/status/assignee/PR. - The loop closes visibly: when a status changes under an open page, the widget announces it — toast ("… open → verified by claude-code · PR linked"), pulsing pin, and a 🔔 tab-title flash if you're on another tab (adapted from make-pages-interactive's reload walkthrough, MIT).
- Page API:
window.__loopback={ pins, refresh(), project, endpoint, version }(adapted from DOM-Review's__domReviewAPI, MIT) — used by the E2E suite, usable by any agent driving a browser.
The MCP bus — 10 tools
Responses are markdown (default) or JSON via response_format, always with
structuredContent; long output truncates at 25k chars with guidance.
HTTP surface (--http, port 7077 / LOOPBACK_HTTP_PORT / --port)
Security: the trust boundary is not "localhost" — a loopback port is reachable from every page open in your browser. So:
- CORS is granted to
POST /ingest,GET /feedbackandGET /widget.jsonly — the three things the widget genuinely needs from a foreign origin. - Cross-origin reads get the pin projection (id, status, title, assignee,
selector, PR link).
extra— captured response bodies, which routinely contain auth headers — is never served cross-origin. - Everything that reads full context or changes state, including
/mcp, requires an origin pinned at startup from the bind config. Local tooling that sends noOrigin(curl, MCP clients) still works. - URLs on items are rendered as links only when they are
http(s)— enforced bysafeHref()in the dashboard, which resolves the URL and reads its protocol.data:,vbscript:andfile:render as plain text.
A non-loopback bind requires a token. On 127.0.0.1 there is none — it
would protect nothing the OS does not already protect. The moment --host /
LOOPBACK_HOST widens the bind, the server generates one (or takes
LOOPBACK_TOKEN) and prints a ?token=… URL; the token is accepted once from
the query string, moved into an HttpOnly cookie, and stripped from the URL so
it does not persist in history or referrers. Tools send
Authorization: Bearer <token>. Comparison is constant-time over a digest, so
neither the value nor its length leaks through timing.
Four endpoints stay open on a LAN bind, deliberately:
Everything else — the dashboard, full reads, every write, and /mcp, which
exposes all ten tools — refuses an unauthenticated caller with 401. The split
is asserted in scripts/e2e.mjs in both directions, and
npm run canary proves that assertion fails when the check is disabled.
This is a shared secret on a trusted network, not a substitute for real auth. Before exposing Loopback beyond a LAN, put it behind a reverse proxy.
Publishing to the MCP Registry
Loopback carries the identity the official MCP Registry uses to prove package ownership:
The registry fetches the published npm version metadata and requires
mcpName to equal server.json's name exactly; GitHub-based authentication
additionally requires the io.github.<username>/ prefix. server.json stays in
the repo and out of the npm tarball — the package only needs to carry mcpName.
Because npm versions are immutable, a mismatch costs a version number rather
than a retry. npm run smoke therefore asserts all six coupled fields (three
versions, the name pair, the npm identifier) and npm run canary proves that
assertion fails when they drift.
To release and submit:
Run validate before publish — it checks the manifest against the real
registry without spending an attempt. Run verify:release after, and read what
it prints: it installs the published tarball into a clean directory, renders
init from it, speaks real MCP to the result, confirms the registry listing
resolves to the version you just shipped, and runs the plugin's own registered
command from an empty directory. Every one of those steps has caught a real bug
that the source-side gates could not see. description is capped at 100
characters and is rejected, not truncated, past it, so npm run smoke
asserts that limit locally as well.
Tests
CI runs all of them on every push (LOOPBACK_E2E_CHROMIUM overrides the
browser binary if needed).
Several of these are built to resist passing for the wrong reason, because the
underlying tools fail open: a stale dashboard build serves happily with no error
anywhere, and impeccable detect exits 0 when it scans nothing. So
dashboard-gate rebuilds and compares rather than trusting mtimes, and
impeccable-gate scans a canary fixture that is required to trip before it
will believe a clean result.
a11y-gate and widget-token-gate exist because the two things they check —
accessibility and cross-surface token parity — regressed silently more than
once. The widget inlines its own copy of the tokens (it ships as one file and
cannot @import them) and had already drifted; components.css hardcoded a
near-white pin colour that broke the moment a status token went pale. Every gate
here has had both of its failure paths verified by deliberately breaking them.
Companions (borrow, don't rebuild)
Loopback is deliberately only the bus + capture layer. Pair it with the mature MCP-native pieces — the build-vs-borrow memo is the full analysis:
- chrome-devtools-mcp / playwright-mcp — the agent sees and verifies the running app (the "verify" step of the loop)
- Sentry MCP — production errors (incl. mobile) →
POST /ingestwithsource: "sentry" - PostHog MCP — analytics/replays/surveys →
source: "posthog",replay_urlattached
Design decisions
The full history lives in docs/ (original spec, build-vs-borrow memo, interaction-layer analysis, technical path). Calls made in this build:
node:sqlite, never better-sqlite3 — native builds fail in clean environments; zero native deps is the feature.- stdio + stateless streamable HTTP only, no SSE — the exact transport intersection of Claude Code, Codex, and Gemini CLI (SSE is deprecated in Claude Code and absent in Codex).
- AGENTS.md is canonical — Codex and Gemini read it natively; Claude
imports it via
@AGENTS.md(imports beat symlinks for Windows safety). One playbook source renders into every native mechanism; no agent is "the default". - Codex gets project-scoped
.codex/config.toml— verified supported (loads once you trust the repo);initalso prints the global block. initwrites a repo-relative path when the server lives inside the onboarded repo,npx loopback-mcp-servereverywhere else — committed configs must work on every clone; a machine path works on exactly one. (Originally: absolute path for stable checkouts,npx github:for ephemeral runs — both retired once the package was on npm.)/ingestaccepts unknown extra fields (no.strict()) — older hubs must not reject newer widgets; forward compatibility beats strictness at the ingestion boundary.- Widget is 58KB / 19KB gzipped, not the ~10KB sketch — ring buffers, failure-body capture, live pins, repro steps, the route journey and the walkthrough earn their bytes; still zero deps, one file, served pre-compressed with an ETag.
- Marker-based merges —
initre-runs are byte-idempotent; files a human has taken over (generated marker removed) are left untouched. - Interaction patterns adapted with attribution (MIT): make-pages-interactive's visible-closure walkthrough; DOM-Review's page API.
Repo map
Two manifests at the root do different jobs: registry.json publishes the
shadcn components, and server.json is the MCP Registry entry (see
Publishing to the MCP Registry).
The root also carries agent config that init itself writes — the repo
onboards itself, so these are working proof the command produces what it
claims, and init-gate re-renders them on every CI run to prove they have not
drifted:
.claude-plugin/ is the one root dot-directory init does not write: it is
the marketplace manifest for the plugin this repo hosts, maintained by hand and
bumped by npm run bump. init-gate asserts its version matches rather than
re-rendering it.
MIT © Dikshant Joshi
來源:README.md,提交 9e3395e
工具
0版本歷史
1- v0.9.4最新Sep 16, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分