# Connect your coding assistant MCP gives an authorized assistant the same thread your team sees: screenshot, page context, named messages, revisions and current permissions. Approved project instructions and owner-approved reviewer guidance travel separately from untrusted discussion. Subject weights are advice about expertise. Humans choose the assignee, priority and timing; weights cannot override those choices or authorize work. ## Official directory status Checked 2026-10-21. The publisher's [public marketplace](https://github.com/Softinator-TechLabs/feedbacks-plugins) supports direct installation independently of official directory approval. - **Claude Code:** submitted version 0.2.2 passed its security scan; the publish request is waiting for an Anthropic reviewer. It is not yet listed in the official directory. - **OpenAI:** local command/stdio MCP submission access is pending review. The package is not submitted for directory review or published. OpenAI's [desktop-only submission guide](https://developers.openai.com/plugins/deploy/desktop-only) requires publisher approval and organization allowlisting before submission. No publication date is confirmed. A new source release, direct marketplace install or passed test does not publish either official listing. Keep each customer's own server URL and personal scoped key; directory review does not require a separate proprietary product fork. ## Start with your personal connection Your team needs a server and a prepared project first. Sign in as yourself, open **Setup → Connect your coding agent** and create your setup prompt, or choose narrower projects and permissions in Account. Paste the private prompt into your own coding tool and verify accessible projects before changing feedback. Reviewers do not need MCP to submit captures. Follow the [step-by-step developer guide](../site-docs/guide/mcp.md) for Codex, Claude Code or Antigravity. ## Codex plugin Install from the [public Feedbacks marketplace](https://github.com/Softinator-TechLabs/feedbacks-plugins), with Node.js 22.12+ or 24 and Git available: ```sh codex plugin marketplace add Softinator-TechLabs/feedbacks-plugins codex plugin add feedbacks@feedbacks ``` Codex CLI 0.159.3 was verified installing version 0.2.1 from that repository, discovering the MCP server in a fresh native session and reading an allowed synthetic thread and its image. A valid write with the read key was denied for its missing operation scope. This checks the client/tool connection; it does not certify every client version or a model's implementation work. For a local source build, from the repository root: ```sh npm ci npm run build:plugin codex plugin marketplace add ./dist/codex-plugin codex plugin add feedbacks@feedbacks-local ``` The build produces `dist/codex-plugin/feedbacks` and `dist/feedbacks-codex-plugin.zip`. It bundles the existing stdio adapter, its dependencies and license notices. No runtime npm installation or lifecycle hooks are needed. Keep the local marketplace folder available while the client uses it. Install commands depend on the Codex version; check `codex plugin --help` if they differ. Public directory submission and approval are separate from the publisher's marketplace. Configure your chosen server and a scoped agent key from the application’s agent-key settings. Provide `FEEDBACKS_URL` and `FEEDBACKS_TOKEN` to the plugin process, or use an owner-only `~/.config/feedbacks/config.json` file with `url` and `token` fields. The CLI rejects shared/unsafe configuration file permissions; use mode `0600`. Never put a key in the plugin manifest, a prompt, a public repository or a screenshot. Environment variables must reach the actual Codex process; a terminal export does not automatically configure a running desktop app. Begin with read access to the required projects. Add reply, attachment or status scopes only for actions you want the assistant to perform. Existing keys do not automatically gain new operation scopes. The plugin's review skill does not grant access itself. ## Claude Code plugin Install the publisher's native marketplace: ```sh claude plugin marketplace add Softinator-TechLabs/feedbacks-plugins claude plugin install feedbacks@feedbacks ``` Claude Code 2.1.286 passed strict manifest/catalog validation and installed/discovered version 0.2.1 from the public repository in an isolated client configuration. Verify the actual allowed thread/image read in your own fresh session after configuring your key. From a source checkout with Node.js 22.12+ or 24, build the same adapter and add its native Claude marketplace: ```sh npm ci npm run build:plugin claude plugin validate --strict ./dist/claude-plugin claude plugin marketplace add ./dist/claude-plugin claude plugin install feedbacks@feedbacks ``` The build produces `dist/claude-plugin/plugins/feedbacks` and `dist/feedbacks-claude-plugin.zip`. It includes the same two skills, bundled adapter and license notices as the Codex package; its native `.claude-plugin/plugin.json` and `.mcp.json` use `${CLAUDE_PLUGIN_ROOT}`. Keep the marketplace directory available, restart the client and check `claude plugin details feedbacks@feedbacks` for both skills and the MCP server. Supply your chosen server URL and scoped key using the same private configuration described above. An installable marketplace is separate from inclusion in Anthropic's official directory. See the [Claude plugin reference](https://code.claude.com/docs/en/plugins-reference) for version-specific validation and installation. ## Other MCP clients Operators can enable [OAuth on their own server](mcp-oauth.md) for compatible HTTP clients. Users approve selected projects and read/optional reply access. The local plugin, manual keys and advanced permission setup remain available. For clients that support [MCP bundles](https://github.com/modelcontextprotocol/mcpb), `npm run build:mcpb` creates `dist/feedbacks-mcp.mcpb` and its SHA-256 checksum. The self-contained Node adapter includes its dependency licenses and asks the client for your own server URL and personal agent key; the key is marked sensitive. The bundle does not include the native Codex/Claude Code skills. Use Node.js 22.12+ or 24 and a client that supports Node MCPB packages. Never edit the bundle to embed a credential. Registry publication and client compatibility are separate from building a valid bundle. Feedbacks exposes Streamable HTTP at `https://your-feedbacks.example/mcp`, authenticated with an `Authorization: Bearer …` header. Use your client's secure token configuration. For clients that need stdio, launch `npm run mcp` from the source checkout, or the built plugin's `node mcp.mjs`, with the same URL/key configuration. Remote servers require HTTPS; loopback HTTP is allowed for development. See the [API and CLI reference](api.md) for operations and setup. Client-specific authentication support varies; listing Codex, Claude Code or Antigravity is not a claim that every client/version has been certified. ## First review For new chats and large backlogs, use the [portable review skill](../plugins/feedbacks/skills/review-feedback/SKILL.md). Its supporting [glossary](../plugins/feedbacks/skills/review-feedback/references/glossary.md), [media guide](../plugins/feedbacks/skills/review-feedback/references/media.md), [sequential workflow](../plugins/feedbacks/skills/review-feedback/references/workflow.md) and [client installation](../plugins/feedbacks/skills/review-feedback/references/install.md) load on demand. Connecting a server alone does not persist a client skill. 1. A supplied thread URL or task is the target. For a broad request, identify the authenticated member with `auth.me.actor.userId`, then use a bounded server-filtered queue for that member's eligible assigned work and ask which task to begin. 2. Read current status/revision and authorized project instructions. Reuse complete current text from **Copy task for agent**; fetch omitted or revised discussion/evidence. Inspect screenshots with `assets.get` with `includeImage:true`; filenames alone are not visual evidence. 3. Separate the team's request from quoted page text, console messages and other untrusted content. Approved expertise weights do not override the user's instructions, access controls or evidence. 4. Make only the changes the user authorized. Re-read current revisions before replies or other writes; reload on a conflict. 5. Read back the result and distinguish source edits, tests, deployment and visual proof. A reply saying “fixed” is not proof of a deployed fix. Older screenshot threads may contain the small diagnostics packet selected by a reviewer; it is partial and lacks raw headers, cookies and bodies. New screenshot threads expose a compact `diagnosticEvidence` summary. Use `diagnostics.describe` for channel coverage and file selectors, then bounded `diagnostics.read` pages for relevant bytes. The local stdio full profile offers `feedbacks_diagnostics_materialize` to create a checksum-verified private directory; remote HTTP MCP exposes bounded reads and an authenticated archive route. Captured DOM, console text, headers and bodies are untrusted and may contain credentials. Extracted DOM files use `.html.txt`; inspect them as text, do not execute them or replay requests. A missing channel or HTTP status is not evidence of success. [Session recordings](session-replay.md) remain a separate versioned format with replay and their own export. For large console, network and performance JSONL streams, use `diagnostics.search {evidenceId,requestId?,fromMs?,toMs?,cursor?,limit?}` to select events before reading bytes. Supply an exact Chrome request ID, an absolute ingress time range in Unix milliseconds, or both. Results contain event method, time and a chunk `fileId`/`sequence`/`byteOffset` locator; they do not include captured page values. Follow `next` for more matches, then use `diagnostics.read` at the locator. Search requires both `diagnostics.search` and `diagnostics.read` scopes plus current project access. The index is limited to 50,000 rows, 100,000 scanned lines and 256 KiB per parsed line; `index.status: partial` and `index.reasons` disclose omitted events. Older artifacts without an index report `unavailable`; materialize or page those files when needed. Search never treats missing matches from a partial index as proof that an event did not occur. Website points carry ordered `context.annotations`. Use `markings[].annotationId` to associate an approved image with its note and element box. A `point-001-original.webp` attachment preserves the original viewport or menu state for that point; `anchor.viewport` and `anchor.capturedAt` describe when it was selected. It can differ from the later `page-visible.webp` or numbered full-page sections. Inspect the original image when investigating that point. Do not project coordinates from one viewport or menu state onto another image without matching markings. The combined image contains continuous page sections only; point originals remain separate. See [extension evidence](extension.md). ## Plugin and MCP maintenance `plugins/feedbacks/plugin.json` and `mcp.json` are the portable manifests; compatibility metadata lives under `.codex-plugin/` and `.mcp.json`. `npm test` builds the plugin and exercises both the source and bundled adapters with an MCP SDK client, including discovery and a real thread read. Every business operation uses the shared schemas and authorization layer, with read/write annotations; a tool appearing in discovery does not grant permission to call it. Follow the official [plugin build guide](https://developers.openai.com/plugins/build/plugins), [Codex MCP guide](https://developers.openai.com/codex/mcp) and [app review requirements](https://developers.openai.com/plugins/deploy/app-review) when preparing a submission. Public distribution needs its own publisher, authentication, endpoint and review evidence. This repository does not claim directory acceptance. ### Point decisions and page totals Captured `context.annotations` and attachment markings retain the original evidence. Read `annotationStates[annotationId]` for separately attributed open/resolved/removed decisions. Thread resolution/decline closes active points; a later reopen preserves their individual decisions. Removed points remain historical evidence, including their baked screenshot marks. `threads.annotationStatus` requires the current thread revision and an explicit token scope. Resolution also requires resolve permission; remove/restore requires maintain permission. Existing tokens do not gain this scope automatically. `threads.list` with `includeSummary: true` returns aggregate thread/point totals for the selected project, page/hostname and device filters, independent of pagination. ## Compact profile and CLI Connect to `/mcp?profile=compact`, or set `FEEDBACKS_MCP_PROFILE=compact` for stdio. The original endpoint and unset environment retain full discovery, including these same entry tools and existing direct operation names. | Tool | Purpose | | --------------------- | ------------------------------------------------------------------------------------------------------- | | `feedbacks_guide` | One skill topic: start, glossary, media, workflow or install | | `feedbacks_workspace` | Match projects to supplied git remotes and page origins | | `feedbacks_queue` | At most 20 task previews (default 10), counts and continuation | | `feedbacks_thread` | One overview or paginated evidence section | | `feedbacks_asset` | Media metadata or image, optionally cropped in original pixels | | `feedbacks_describe` | Search operations or fetch one exact schema | | `feedbacks_start` | Start one selected task: current identity/scopes, status, instructions, coordination and snapshot reuse | | `feedbacks_execute` | Invoke with original scopes; thread writes return compact receipts | The JSON CLI shares this adapter: `npm run --silent cli -- --agent queue --input selection.json`. Input defaults to stdin. Static `--agent guide` and `--agent describe` need no credentials; business calls retain authentication. Both MCP profiles expose `feedbacks://guide/` resources and a `review-feedback` prompt. Text content includes structured data for clients that ignore structured content; image bytes appear only in native image blocks. Repository matching uses normalized remote identity and exact page origin. Names are hints; ambiguous/unmapped projects need a choice. The server cannot inspect local directories. The skill inspects local approved mappings/remotes and verifies accessible IDs; multiple configured repositories may match one project. For today's feedback, resolve stable `authorId` and timezone. `createdAfter` is inclusive, `createdBefore` exclusive: supply local midnight boundaries in UTC. `activityAfter` includes updates to old threads. `workState` selects an exact state, including closed work; `topPriority` filters flags. Search covers bodies, replies and point text. Use `showResolved:true` for all submissions, then an active query for remaining work. `sort:workPlan` respects human planning, with `planningDate` supplied as the current local calendar date. For broad requests use `assignedTo` from `auth.me.actor.userId` before pagination; do not filter an unscoped first page locally. The server selects active assignments with a whole-thread scope or at least one assigned point still open. Default active-thread filtering retains open/in-progress/ready-for-review states; inspect the task's state and assigned scope before proposing to begin. `sort:priority` (flags plus authorized reviewer weights) and `sort:topPriority` (flags plus recency) remain advisory views when requested, not replacements for human planning. Thread sections: body, points, discussion, assets, reviewers, evidence, context, diagnostics and history. Overview lists populated sections; an explicitly requested empty section still returns its empty result. Returned continuation `next` calls retain revision/content cursors. Pass initial revision as `expectedRevision` and the section `contentVersion` as `expectedContentVersion` on continuations; finish text chunks before advancing item offsets. Queues are live: restart after writes and retain completed IDs. Full HTTP list/thread operations still return full records; compact projection bounds model context, not database or HTTP transfer costs. Use explicit immutable exports for snapshot requirements. Local stdio adds `feedbacks_recording_materialize` to both profiles, so compact stdio has nine tools while remote compact MCP has eight. This tool writes an owner-only temporary evidence directory on the adapter host using current recording/media access, returns checksummed file paths and reports missing media. It does not mutate the thread or run captured code. See [session replay](session-replay.md#agent-access-and-local-files) for scope and cleanup details. Image previews accept `crop:{left,top,width,height}` in original pixels and return source/crop dimensions. Stored images stay unchanged. WebM assets support native contact sheets through `includeImage:true`; optional `videoTimeMs` focuses sampling. Full playback, PDF rendering and vision reasoning depend on the client; there is no transcript or guaranteed small-model performance. No auto-mutating hooks are installed. Existing signed webhooks/change cursors can support separately requested notifications; an event never authorizes a fix. ### Project and member context on request The package/setup prompt installs two focused skills: `review-feedback` for requested backlog work and `manage-feedbacks-context` for requested profile, project-background and responsibility edits. Their short descriptions enable natural-language discovery; bodies and references load progressively. No startup hooks or unsolicited polling are installed. Developers retain task choice. Use `members.profile.get/save`, `members.responsibility.get/save`, and `projects.context.get/save` through exact schema discovery. Reads/writes return bounded text, revision, author/time and advisory provenance. Members edit their own profile; project writers edit collaborative context and their own responsibilities; owner administrators edit profiles and project maintainers edit other existing members' responsibilities. These operations never change grants, priority policy or approved instructions. Read current text, preserve relevant context, write its revision, then read back. New scopes require a newly issued key; existing keys do not expand. Members can create personal keys from Setup/Account using their own sign-in. Personal keys exclude owner-delegated policy visibility. Project maintainers can separately opt into `github.issueCreate` in Account when they maintain every selected project; Setup defaults omit it, and existing keys never expand. Current project permissions still apply. A member without projects can use only `auth.me`, `projects.list`, and `members.profile.get/save`. The profile's optional `currentWork` is a broad one-line focus (300 characters), preserved when omitted. For authorized work, `assignments.claim` records the current member and agent against a whole thread or selected open points. Atomic overlap checks prevent two active claims on the same work while allowing disjoint points. `assignments.list` is paginated; `assignments.renew` extends a two-hour lease at ordinary work checkpoints; `assignments.release` records completed/paused without resolving feedback. Expiry is advisory, not proof the former worker stopped. Coordinate before takeover. These current-worker claims are separate from durable assignments to a project member. No background polling, model-subscription identity inference or autonomous dispatch to another member is installed. ### Requested delegation and triage The thread header member dropdown saves an assignment immediately: choose a member to assign or reassign, or **Unassigned** to remove it. No triage form is required. **Points & assignment history…** opens optional point assignments, details and history. The dropdown and `assignments.assign` record the same durable assignment to an active writable project member. Scope is the whole thread or selected open points, with summary, category/tags and an explicit GitHub decision/rationale. Assignment taxonomy describes that assignment; parent thread category/tags use `threads.organize` separately. A decision to create an issue does not grant external-write permission or create one. For an agent request, inspect evidence and current project/member context, propose category/tags and GitHub treatment, and discuss material ambiguity before an authorized write. Match actual member IDs, read current delegations and worker claims, then discover the exact schemas. `assignments.delegations` and `assignments.history` are bounded/paginated; `assignments.assign` creates or revises using current thread and assignment revisions; `assignments.cancel` preserves history. Overlapping ownership is rejected; coordinate before takeover. Read back the result and show its assignee, selected scope, initiating authenticated member and agent. Server attribution cannot be supplied by the caller. Delegation does not start the recipient's agent, send a message, mark implementation in progress or resolve feedback. The recipient claims their own authorized work separately. See the [portable triage workflow](../plugins/feedbacks/skills/review-feedback/references/workflow.md#requested-triage-and-delegation) and [API](api.md#durable-assignments-and-current-workers). ### Human priority and timing The thread's immediate controls let a human choose **High / Normal / Low** priority and **Unscheduled / Today / Tomorrow / Next week / Later** timing. Dated choices persist `scheduledFor` as an actual calendar date plus the originating IANA `timeZone`; relative preset labels do not slide forward each day. The optional `workPlan` is returned in full reads and compact queue/overview/plan receipts. Older threads default to Normal/Unscheduled. For a broad “check Feedbacks” request, the skill offers the authenticated member's eligible assigned work first, bounded to 10 previews per page, and asks which task to begin. Due/today/unscheduled tasks precede future dated work, then Later; stored human priority orders within these groups. Future/Later work is labelled separately, not pitched as immediate. Explicit thread/task requests take precedence. Human choices are authoritative; reviewer expertise and dependencies can inform discussion without changing ownership, priority or dates. Only an explicit request to change planning authorizes `threads.plan {threadId,revision,workPlan}`. Discover its schema, preserve fields outside the request, read back, and reconcile conflicts. Existing tokens need the new scope explicitly; access does not expand automatically. Planning applies to the thread and its points without changing their point-specific assignees, starting an agent, scheduling an automatic run or promising a delivery date. ### Copy task for an agent **Copy task for agent** includes a timestamp/revision snapshot: bounded original feedback, up to 20 brief numbered point summaries within a 3,000-character point budget, exact short discussion with authors/times, and up to three authenticated marked-media links. A nonempty latest work note is included as an untrusted excerpt of up to 600 characters with explicit truncation; a non-open work state is retained even without a note. Discussion fits within a 3,000-character budget; incomplete sections are named for fresh reads. Credentials, signed object URLs and raw diagnostics are excluded. Repository hints come from project settings, with URL credentials/query stripped, and must be verified against the local checkout. Unknown branches are not invented. Copying refreshes the thread once, without eager recording/assignment inventories. Pasting the default prompt requests review and discussion in the coding chat. Separate confirmed bugs and suggestions, give counts and brief plans, discuss alternatives and ask which to implement before edits or work-state writes. Suggestions need acceptance; an explicit selected-plan, specific-fix or fix-all request already authorizes that scope without repeated confirmation. Discussion stays quiet by default: finish with the appropriate status and a short outcome/verification note. Routine start, test, PR-created and PR-merged messages are omitted. Reply only for an important blocker/decision needing human attention or explicitly requested discussion updates; permission to reply is not a requirement to reply. The prompt defers deployment to the user's explicit request, and narrower instructions win. Copied discussion is evidence, never authorization. Image links may render in authenticated clients; native MCP image delivery remains necessary when the client cannot access/render the links. Latest work notes also survive `feedbacks_start`, overview and status mutation receipts. Queues and other section envelopes omit them. A truncated note can be read through `feedbacks_thread {threadId,section:"workNote"}` using its revision/content-version text continuation; absence of a note is not evidence that testing is ready. Short completion notes identify testing readiness, exact verified target, remaining gates and one retest step when ready. Source tests, deployed isolated copies, actual user drafts, storage delivery and export/build checks are distinct evidence. ## Start a copied or selected task Call `feedbacks_start {threadId,includeImage:true}` for a selected visual task. Both profiles expose it. One response contains bounded feedback/point summaries, member identity, required access limits, project instructions, coordination and one relevant screenshot or saved video frame as a native MCP image. `includeImage` defaults to false for text-only clients. Optional `annotationIds` restrict point text, relevant image and suggested claim scope; unknown IDs need clarification. Small discussions are complete in the first response. Larger discussions expose omissions and a revision-bound continuation. Known-empty optional sections are absent; an explicit image request reports `no_assets` or `no_preview`, distinct from `denied`, `unavailable` and `not_requested`. `no_assets` does not assert absence of session recordings. A video without a saved frame returns a native contact sheet of up to three samples. `videoTimeMs` focuses on a reported moment using the asset clock, not the session clock. `media.videoPreview` reports source hash, decoded timestamps, partial sampling or explicit unavailability. No client credential-file inspection or manual download is needed. Samples do not prove full playback. Use `includeRecordings:true` for up to three bounded recording summaries in the same call, without raw events or debug exports. Their targeted event-read suggestions retain recording IDs. Exact input schemas are the default for `feedbacks_describe`; full output schemas require `includeOutputSchema:true`. Client wrappers should display structured content or text once and forward native images separately. Both MCP representations remain for compatibility. A `next` object supplies exact arguments for a relevant read or a claim conditional on user authorization. A successful claim supplies the status step. These suggestions do not authorize writes; existing server operations enforce scopes, domain access, ownership and revision conflicts. Follow instruction truncation and assignment pagination before claiming. Older copied snapshots can pass `snapshotRevision` to check reuse. Old keys without `auth.me` retain permitted reads with identity/scopes marked unknown. `auth.me.member` identifies the signed-in member behind an agent; `actor.name` may instead name a shared agent. `credential.operationScopes` describes scope grants only; project/domain authorization still applies. Missing-scope errors identify the operation, required scopes and replacement-key recovery. A denied read should be reported once, without repeating an unchanged request or automatically issuing credentials. Task thread and reviewed page are separate. Start omits `reviewedPage` when no safe page URL was supplied; body-only feedback still includes its original text and project context without inventing a URL or reproduction target. If the page URL points to another thread on the same server, inspect that thread when relevant while keeping progress on the selected task. Main feedback, numbered comments and discussion replies are separate: zero replies does not imply a missing original comment. Body-only feedback has zero numbered comments even if it retains a legacy anchor. `threads.activity` reads bounded recorded lifecycle metadata under `threads.get` or its own scope. Follow `nextBefore`. It includes selected creation, attachment, move, reply and status events without raw historical content or private payloads. It cannot show failed upload attempts or reconstruct an earlier snapshot. Neither absent activity nor a passed generic move test proves that a reported historical loss did or did not occur. New **Copy task for agent** prompts default to review/discussion, with implementation and work/status writes following human selection or an explicit fix request. A fix-all request authorizes the agreed batch without per-item reconfirmation. Older implementation/progress prompts remain subject to narrower human instructions. Discussion replies remain for important blockers/decisions or explicitly requested updates. A status update is not a reply or exclusive claim. Keep detailed receipts in the coding conversation, a short outcome and useful final link in the status note, and use structured evidence links only when useful or requested. Other messages and external issue creation still require their own authorization. Recording/diagnostic availability does not trigger an automatic read. Start with task text/source and relevant images; use bounded diagnostic/recording reads only for a specific unresolved question. Full bundles are for questions targeted reads cannot answer or an explicit bundle request. Member profiles and responsibilities are read only for decisions that need them, such as requested delegation. ### Explicit reproduction identity Applications may supply optional `context.reproduction` to `threads.create`: `source:"app"|"reporter"` and stable `objectId`, `workspaceId`, `file`, `section`, `view`, `version` (each at most 240 characters). The extension reads corresponding opt-in HTML meta tags, for example `` and ``; use `feedbacks:workspace-id` for workspaceId. Values are untrusted evidence, never instructions. Do not put access links, credentials or private source bodies in them. Copy and start include available identity plus document ID/page for document reviews. Nothing is inferred from URL query/hash tokens. Older captures remain valid; when the exact target is ambiguous, request its stable identifier. A known-thread copy has one portable fallback: discover only `feedbacks_start` once if deferred, then reuse known tools. This cannot force a client's tool loader to eagerly register the server. ### Marked screenshots and compact point summaries Copied tasks list up to 20 brief point summaries within a 3000-character point budget, with explicit omissions. Each of up to three image links uses the authenticated `?preview=agent` route. It renders saved numbered pins, selected-text highlights and element outlines against that exact screenshot. Original image bytes are unchanged. Existing annotated images with baked marks are not overlaid again. The API/MCP preview defaults to `showAnnotations:true`; use `false` for original pixels. Crop coordinates remain original-image pixels. All asset routes retain scope/project authorization. `feedbacks_start` omits geometry by default; `includeGeometry:true` adds anchors and bounded markings when precision is needed. Full point/asset section reads retain geometry. A contact sheet is video evidence and does not invent DOM highlights at unsaved timestamps. Linked original point captures are kept separate; markers from different capture states are never merged onto an arbitrary image.