AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
翻譯準備中
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證A portable, zero-dependency visual review & annotation tool you drop into any web project. MIT.
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
A tiny, framework-agnostic visual review tool you drop into any web project.
Load one of your pages into a centered, resizable stage — pick a device size from a list
(phones, tablets, watches, desktop viewports), type a custom size, or drag the stage corners. If the
size is bigger than your window it scales down to fit, with an orange border and a glowing size
control so you know you're zoomed. The stage even wears the right corners: flat-top /
rounded-bottom for a browser window, fully rounded for a phone, tablet, or watch.檢視完整 README ↗A tiny, framework-agnostic visual review tool you drop into any web project.
Load one of your pages into a centered, resizable stage — pick a device size from a list (phones, tablets, watches, desktop viewports), type a custom size, or drag the stage corners. If the size is bigger than your window it scales down to fit, with an orange border and a glowing size control so you know you're zoomed. The stage even wears the right corners: flat-top / rounded-bottom for a browser window, fully rounded for a phone, tablet, or watch.
Turn on Inspect (button or ⇧⌘I) — the page's own clicks are swallowed, the cursor becomes
a crosshair, and rulers appear along the top and left. Drag a guide out of a ruler: it
snaps to element edges (and remembers which). Click a guide for its menu — leave a note on the
guide, delete it, or delete all. Hold ⌘/Ctrl between two guides to read the distance, and
click that readout to leave a note on that space. Click any element to select it: a bar floats just above
it with its size, name, z-index, id and selector, plus buttons to Add Note or Ruler wrap it —
four guides snapped to its edges. Shift+drag to select an area instead — the note records every element
the box touches, so an assistant knows where to look. Each object can
hold multiple notes, living in a draggable frosted modal whose marker stays pinned to
the element through resizes and reflows. Clicking a marker on a hidden element (a closed menu,
say) temporarily reveals it. Every note captures the element's identity — a unique CSS
selector, the React component chain if present, data-testid, box metrics — so an AI coding
assistant knows exactly which element you mean.
A note is a draft until you Save it (⌘↩); Cancel discards a new one or reverts edits, and nothing is written behind your back. Notes carry a state — open (yellow) → noted (purple, the assistant has seen it) → done (green) — and an agent flips those as it works, live in the browser or by editing the notes file. A marker is colored by its least-finished note and shows a count, so it stays yellow until every note on that object is done.
Also: a light/dark toggle, a page search box with history (⌘K), screenshots (⇧⌥⌘Space grabs
the screen exactly as it is — open menus, tooltips and notes included), a keyboard
button under the stage that lists every shortcut (or press ?), and it remembers the last
size you were using. On a fresh install the stage opens a bundled welcome page that walks
through the workflow and gives you things to click.
backdrop-filter; icons are inline Lucide SVGs).localStorage by default; an optional file bridge persists them
to a JSON file on disk.Infospector is one folder of static files. It has to be served from the same origin as the pages you want to review (that's what lets it read the page's DOM), so it lives inside your project's static/public directory.
1. Put the folder in your static directory
| framework | put it at | then open |
|---|---|---|
| Next.js, Vite, Create React App, Nuxt, Remix, Rails, Laravel | public/labs/infospector/ | /labs/infospector/ |
| Astro | public/labs/infospector/ | /labs/infospector/ |
| SvelteKit | static/labs/infospector/ | /labs/infospector/ |
| Hugo / Jekyll / Eleventy | static/labs/infospector/ (or the passthrough dir) | /labs/infospector/ |
| Django | your STATICFILES_DIRS folder, then collectstatic | /static/labs/infospector/ |
| WordPress | wp-content/infospector/ | /wp-content/infospector/ |
| plain HTML | anywhere your server serves | that path |
labs/ is just a convention — any path works. Don't put it in a route that's authenticated
differently from your pages.
2. Open it and follow the first-run setup
Open the folder's index.html in the browser (e.g. http://localhost:3000/labs/infospector/).
A small Set up card asks for your default page, theme, accent, and where notes live — or
Skip. It appears only on a true first run (a browser with no Infospector state and no
config.js settings); reopen it any time with ?setup, and get a full self-check with ?doctor.
Tip: Copy config on that card and paste into config.js — then every browser and every
port starts set up.
3. Check the frame headers (only if the stage says "This page can't be framed")
Your pages must allow being framed by their own origin. Either header below is fine; DENY /
'none' is not:
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
That's it. Nothing to build, no dependencies, and deleting the folder removes it completely.
Installing with an AI assistant? Point it at INSTALL.md — it's written as a
checklist an agent can follow (detect the framework, copy, verify with ?doctor, ask the
questions that matter, write config.js).
| how | what |
|---|---|
?url=/path | page to open |
?setup / ?doctor | reopen first-run setup / run the self-check |
?bridge=http://localhost:7331 | use the file bridge (see below) |
window.INFOSPECTOR_HOME = "/path" | default page (in config.js) |
window.INFOSPECTOR_BRIDGE = "http://…" | default bridge URL |
pages.json (next to index.html) | curated list of pages for the search box — [{ "title", "path", "type" }] |
window.INFOSPECTOR_PAGES = [...] in config.js | same shape, for projects that generate the list |
Nothing to set up for the basics — the list builds itself, and gets better with a little help:
/sitemap.xml (or the one named in robots.txt), so a Next.js,
Astro, WordPress, Hugo… site is searchable immediately.pages.json next to index.html (or set window.INFOSPECTOR_PAGES in
config.js) to name and order the pages you care about; those always list first.Sizes are one array at the top of host.js (PRESETS) — add or edit devices there, including each
device's corner radius.
Right-click the background to dial in the pattern, colors and glass (blur, saturation, highlight, shadow, opacity, tint). Backing is a solid legibility layer under the glass — your tint's hue, pushed dark in dark mode and light in light mode — so text stays readable over any page. Colors are theme-aware: pick one in light mode and dark mode gets a hue-matched dark version automatically (and vice versa); set it in both themes to control each exactly.
Every color swatch opens a glass color picker — a saturation/brightness square, hue and opacity sliders, and your recently used colors. Read and type the value as HEX, RGB, HSL, HSB, or any CSS color (it remembers the format you last used), and copy it with one click. Its eyedropper samples a color from anywhere on your screen (Chrome, Edge, and other Chromium browsers; it's hidden where the browser can't reach outside the page). Then:
window.INFOSPECTOR_DEFAULTS = {…} block; paste it into
config.js so every browser (and every project you drop the folder into) starts with your look.The inspector runs inside the framed page, which the browser only allows for same-origin pages. So:
X-Frame-Options / CSP frame-ancestors). The toolbar chip says "view only" or "blocked".
This is a browser security boundary, not a bug.Default — localStorage. Nothing to run. Notes are keyed per page, per browser.
Optional — file bridge. Run the included zero-dependency server to persist notes to a JSON file on disk (great for committing review notes, or letting an agent read/edit them):
node public/labs/infospector/server.mjs # http://localhost:7331, ./infospector-notes.json
node public/labs/infospector/server.mjs --port 7331 --file .infospector-notes.json
Then point Infospector at it:
/labs/infospector/index.html?bridge=http://localhost:7331&url=/your/page
The browser polls the bridge, so edits you (or an agent) make to the notes file show up live. The ⋯ menu also has Export / Import to move notes around as JSON.
Two ways an assistant can read your notes and update their state:
Live, via the browser. A documented global is exposed on the Infospector window
(window.__previewTester is kept as an alias):
window.__infospector.listTargets() // -> Target[] (objects + their notes)
window.__infospector.listNotes() // -> flat [{ targetId, id, text, state, element }]
window.__infospector.getNote(id)
window.__infospector.setNoteState(id, "noted") // open|noted|done (old reviewed/working/complete accepted)
window.__infospector.updateNote(id, { text, state })
window.__infospector.deleteNote(id) // removes its object if it was the last note
window.__infospector.setTargetRuler(targetId, true)
window.__infospector.openTarget(targetId) // open its modal + reveal if hidden
window.__infospector.clearAll()
window.__infospector.exportJSON() / importJSON(str)
window.__infospector.allNotesText() // paste-ready text of every note (also "Copy all notes" in the menu)
window.__infospector.pageKey() / store() // store: "localStorage" | "file bridge"
Durable, via the notes file. With the bridge running, the agent reads and edits
infospector-notes.json directly — a map of { "<pageKey>": { version, pageKey, targets: [] } }.
Flip a note's "state" to "working" when it starts and "complete" when done; the browser
picks up the change on its next poll.
An object you've annotated is a target; it owns one or more notes.
{
"id": "t…", "createdAt": "…", "updatedAt": "…",
"ruler": false, // dimension rulers shown
"modal": { "x": 900, "y": 90, "open": true }, // draggable modal position/visibility
"anchor": { "selector": "…", "frac": { "fx": 0.5, "fy": 0.5 }, "rectAtCapture": { … } },
"element": {
"name": "…", "tag": "a", "id": null,
"selectors": ["body > … > a:nth-of-type(1)"], // [0] is the best/unique one
"components": ["LinkComponent", "HomeNavDesktop"], // React chain, if detectable
"attrs": { "data-testid": "…", "href": "…" },
"rect": { "x": 0, "y": 0, "width": 0, "height": 0 },
"zIndex": "auto",
"style": { "borderRadius": "…", "padding": "…" }
},
"notes": [
{ "id": "n…", "text": "Tighten the logo lockup spacing", "state": "open",
"createdAt": "…", "updatedAt": "…" }
]
}
*; keep it on localhost.bookmarklet.js is a standalone element inspector for any page (no stage, no notes):
javascript:(()=>{const s=document.createElement('script');s.src=location.origin+'/labs/infospector/bookmarklet.js?t='+Date.now();document.body.appendChild(s)})()
Shift+click an element for a copy-ready identity block.
| file | purpose |
|---|---|
CHANGELOG.md | what changed in each version (PRs add to Unreleased; releases are tagged on GitHub) |
INSTALL.md | step-by-step install checklist written for an AI assistant to follow |
index.html | the host page (floating toolbar + stage) |
welcome.html | the how-to page the stage opens on a fresh install |
host.css / host.js | UI, sizing, presets, typeahead + history, theme, screenshot, notes, robot API |
inspector.js | injected into the framed page: element picking, pins, rulers, reveal |
adapters.js | persistence adapters (localStorage + file bridge) |
server.mjs | optional zero-dependency file-bridge server |
pages.json | optional page manifest for the search box |
bookmarklet.js | standalone shift+click inspector for any page |
vendor/html-to-image.js | enables the screenshot button (html-to-image, MIT) |
lib.js | pure helpers (colors, pages, migration) shared by host.js and the unit tests |
test/ | unit/ (node --test), e2e/ (Playwright), serve.mjs (zero-dep static server) |
The tool itself has no dependencies; the tests do (Playwright, dev-only). From this folder:
npm install # once: @playwright/test
npx playwright install chromium
npm test # unit (node --test, pure helpers in lib.js) + e2e (real Chromium against welcome.html)
npm run test:unit is instant and dependency-free; npm run test:e2e starts test/serve.mjs on
:7377 and drives the real UI: inspect, select, notes, ruler wrap, guide snapping, ⌘-hover gap
notes, clear-all, shortcuts. Never run npm install inside a project's public/ copy — run the
tests from a clone of the repo.
MIT © 2026 Q Manning. See LICENSE.
Made by Q Manning · Source on GitHub · See it live in the Labs