Skip to content

Feedback to fix

The widget isn’t only for your customers. When one of your admins is looking at a broken page in your own app, they can file feedback about it from the same chat window — with the page, the element and the render trail already attached — and hand it straight to a coding agent.

This is a loop: notice it, file it, dispatch it, get a PR.

The feedback controls only appear for admins. On your own site, the Ruby gem loads an in-page inspector when the identified user’s role is one of config.admin_roles (admin and owner by default). Where the inspector isn’t present, the feedback menu stays hidden and the slash commands refuse. The Node, Python and WordPress packages don’t load the inspector.

With it loaded, there are three ways in:

The 💡 menu in the widget’s header, with two items:

  • 🎯 Inspect an element — collapses the panel and turns the page into an element picker. Click the thing that’s wrong, add a note, optionally capture a screenshot, submit.
  • 📝 Send a note — opens the note panel for a page-level comment with no element picked.

/inspect — same as the menu item. /inspect the button is misaligned pre-fills the note.

/note — files a page-level note. /note the total is wrong on mobile submits immediately; /note on its own opens the panel.

Filing switches the widget to the feedback’s own conversation, so any reply — from a teammate or from a dispatch agent — lands in the same window you filed from.

A note is capped at 4,000 characters. Alongside it:

  • Where you were — the full page URL, the path, and the controller#action that rendered it.
  • What rendered — the ordered list of partials Rails rendered for that request. This is the single most useful field when you’re hunting for which file to open, and it’s why the Rails gem captures it server-side rather than guessing from the DOM.
  • The viewport — width and height, so “only broken on mobile” is visible rather than guessed.
  • The element, when you picked one — a short CSS selector path, the tag name, its visible text (up to 500 characters) and its outer HTML (up to 4,000).
  • Screenshots, if you captured or pasted any. They’re attached to the ticket and shown on its page.
  • Who filed it — the visitor identity your identify() call supplied: name, email and role.

Everything lands as a ticket on your workspace’s Feedback page, with a linked conversation. Tickets move opentriagedresolved, or are dismissed. Seeing them needs feedback.read; changing status or dispatching needs feedback.manage.

Both are code agents, configured on the Dispatch page — how they’re set up, what they target, and how their changes reach your repo is covered in Code agents. What follows is what each one does with a feedback ticket.

You can run an agent on your own machine that connects to your workspace, receives feedback the moment it’s filed, works the problem with a coding assistant, and streams the result back into the conversation.

To wire one up, provision a token: API tokens → New token, with the platform:dispatch scope. The raw token is shown exactly once, on the page right after you create it — there’s no way to recover it later, only to revoke and issue a new one. Put it in the agent’s environment.

Once it’s connected, a Dispatch card on your Dashboard and on the API tokens page shows live status: online with the age of its last heartbeat and what it’s currently doing, or “Not connected”. The agent pings every 20 seconds, and the card polls, so you can see it drop without refreshing.

What you see in the conversation while it works: progress chips as the agent uses tools, and its replies as normal messages. A reply can carry a proposed code change, which renders as a badge with a summary and how the change is routed — “quick fix” when it will commit to the base branch, “PR” when it will open a pull request for review. Hovering tells you why it chose that: the file count, the line count, or a path you’ve marked as always-reviewed. That routing is your ship policy, not the agent’s decision.

Applying a proposal isn’t a workspace control today — the badge tells you one was made and what would happen to it.

Revoking the token cuts the agent off on its next reconnect.

The same agent also sits in a room of its own, so you can ask it questions directly instead of only through a feedback ticket — see Code agents.

The agent is open source at VroxyAI/vroxy, the same repository as the CLI and the same one-line installer:

Terminal window
curl -fsSL https://raw.githubusercontent.com/VroxyAI/vroxy/main/install.sh | bash

Say yes when it asks about a dispatch agent and it walks you through the rest: the workspace host, the platform:dispatch token from above, and which checkout on this machine the agent may work in. It confirms the workspace by name before wiring anything to it — installing an agent against the wrong token is the kind of mistake you find a week later in somebody else’s rooms.

It installs a systemd unit, so the agent comes back after a reboot and you can manage it the usual way:

Terminal window
./install.sh --dispatch # add another workspace to this machine
./install.sh --list # what's installed, and whether it's up
./install.sh --update # pull, reinstall deps, restart everything
./install.sh --remove ID # stop, disable and forget one instance

One process per workspace. The channel streams for exactly one workspace, so running agents for two of them is two units rather than one process holding two connections — which is why adding the second costs one environment file and no extra configuration.

It needs Python 3.9+, git, and whichever coding CLI you want it to drive (Claude Code or Codex).

The other path needs no daemon of your own: link a GitHub repository and hand a feedback ticket to GitHub’s Copilot coding agent, which works the issue and opens a pull request.

Setup lives at Settings → GitHub (or /w/<workspace-id>/<slug>/ github) and needs settings.read to view, settings.write to change. If the deployment doesn’t have the Vroxy GitHub App configured, the page says so and the whole feature stays dark.

Be aware of what this path actually requires, because it’s more than a checkbox:

  1. Install the Vroxy GitHub App on the account or organization that owns your repositories, and grant it the repos you care about. You’re returned to the picker.
  2. Authorize Copilot access for your own GitHub account. This is a separate step and it is not optional: Copilot’s agent APIs reject app-installation tokens outright, so dispatch has to run on a personal authorization.
  3. Then link repositories. Linking verifies that your GitHub account can actually see the installation, which is why step 2 has to come first. A repo you can’t access won’t link.

The account that authorizes is the account that pays. Copilot tasks run on the authorizing user’s Copilot plan and bill to it. That account needs write access to the repository and an active Copilot seat. If the person who authorized leaves, or revokes their authorization, dispatch stops until someone else authorizes.

Authorization belongs to the person, not the workspace: each member authorizes their own GitHub account once, and it then works across every workspace they belong to. The App installation is remembered separately, so a colleague can link repositories from an installation somebody else set up without repeating that step.

One Copilot agent can cover several repositories — see Code agents. Each linked repo has a base branch that agent work starts from, and an enabled/disabled toggle so you can pause dispatch to a repo without unlinking it. The base-branch field offers the branches the repository actually has, rather than trusting you to type one correctly, and saves as soon as you pick or tab away — a typo here would otherwise point dispatch at a branch that doesn’t exist. A disabled repo keeps its link, its base branch and its history but drops out of the dispatch picker; that’s the difference between Disable and Remove.

Repos are kept in sync with GitHub: uninstalling or suspending the App disables its repos, removing a repo from the installation disables that repo, and pull-request activity is recorded against it.

Because Copilot bills the authorizing account, a workspace has to say which member’s authorization to use. Pick one under GitHub → Dispatch identity. The list offers members who have authorized GitHub; their Copilot seat is the one that pays, and their access decides which repositories are reachable.

Without a designated identity, dispatches started from the browser still run as the person clicking. API dispatches have nobody to run as and are refused — see below.

Dispatching. On a feedback ticket, pick a linked, enabled repo and send it. Vroxy then:

  1. Opens a GitHub issue in that repo containing the feedback context, filed with the App’s installation token.
  2. Starts a Copilot agent task on that repo against its base branch, asking for a pull request — using your personal authorization.
  3. If the agent-task API isn’t available to that account, falls back to assigning the issue to Copilot, which is the same work by a different door.
  4. Marks the ticket triaged.

Progress comes back into the feedback’s conversation as messages: when Copilot opens a PR (with the link), when the task completes, when it fails and why, and when it’s waiting on you.

Only one dispatch to the same repo can be in flight for a given ticket at a time — sending it twice tells you it’s already running.

The same thing works over the REST API, so a script or your own admin can dispatch without anyone opening the workspace:

Terminal window
curl -X POST https://vroxy.ai/api/v1/feedback/<feedback-id>/dispatch \
-H "Authorization: Bearer $VROXY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"repo": "<repo-id>"}'

GET /api/v1/repos lists the repositories you can target and reports dispatch_ready — check that first, because an API token authenticates a workspace rather than a person, so this path needs a designated dispatch identity and fails clearly without one.

Then poll GET /api/v1/feedback/<feedback-id> and watch the dispatches array. The token needs tenant:write.

What leaves your database. The issue body contains the feedback note, the reporter’s label, role and email, the page URL, path and controller#action, the viewport, the ordered list of rendered partials (up to 40), the picked element’s selector, tag, text and the first 400 characters of its outer HTML, and the linked conversation’s title. Screenshots are not sent. Nothing beyond what the feedback page already shows goes to GitHub — but the issue does land in your repo, so treat it as you’d treat any issue your team can read.

The Copilot path is the one to reach for if your code is on GitHub and your team already has Copilot: nothing to run, nothing to keep alive, and the output is a PR in the normal place. The dispatch-agent path suits a repository that isn’t on GitHub, or a workflow where you want the agent running against a working tree you control.

Neither replaces reading the ticket. Both give you a starting point with the page, the element and the render trail already attached — the context that usually costs you ten minutes of “which page was this again?”.