Running your own agent
One of the two ways a filed piece of feedback becomes a change — see Feedback to fix for the other.
An agent you run
Section titled “An agent you run”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.
Installing one
Section titled “Installing one”The agent is open source at VroxyAI/vroxy, the same repository as the CLI and the same one-line installer:
curl -fsSL https://raw.githubusercontent.com/VroxyAI/vroxy/main/install.sh | bashSay 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:
./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 instanceOne 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).
Several agents on one machine
Section titled “Several agents on one machine”One agent works one checkout, but a single machine can run several — each its own process, its own room, and its own @-mentionable name in the workspace. That’s how one workspace gets an agent for its backend and another for its frontend, each answering only its own room.
Every instance is a separate systemd unit
(vroxy-dispatch@<id>.service) with its own environment file at
/etc/vroxy-dispatch/<id>.env. Two things in that file keep instances
apart:
VROXY_INSTALL_ID— a random id written once at install, and the instance’s identity on the server. Two agents sharing one are the same agent (one room), so never copy one instance’s environment file to make another — run the installer again and let it mint a fresh id.CODE_ROOT/PROJECT— which checkout this instance works in, resolved asCODE_ROOT/PROJECT. Two shapes work: a folder holding several repos (CODE_ROOT=/home/you/code,PROJECT=backend), or a single repo pointed at directly (CODE_ROOT=/home/you/code/backend), which the installer lifts to the parent-plus-name form for you.
Two agents on one box is just the installer twice:
./install.sh --dispatch # agent one → "Backend", /home/you/code + backend./install.sh --dispatch # agent two → "Frontend", /home/you/code + frontend./install.sh --listThe second run notices the workspace already has an agent and offers to
add another under a distinct instance id rather than overwriting it.
Each agent lands in its own room on first connect; mention one by name
(@Frontend) to route a message to it specifically, even in a room
whose default is the other.
Waking a sleeping box
Section titled “Waking a sleeping box”A local agent on a machine that isn’t always on can still take work: when the agent is offline, vroxy holds the message and POSTs its Wake URL (set on the agent’s Configure page) to ask the box to start. The held work is sent the moment the agent reports in.
The wake request is a JSON POST:
POST <wake url>X-Vroxy-Wake-Token: <the token you set on the agent>{"agent": "<agent hashid>", "reason": "queued_work"}A Lambda function URL is authless unless the function checks something, so treat the token as the only thing standing between a stranger and your box — verify it before starting anything.
Here is the whole Lambda (Python, boto3) — it checks the token and
starts an EC2 instance:
import jsonimport osimport boto3
INSTANCE_ID = os.environ["INSTANCE_ID"]WAKE_TOKEN = os.environ["WAKE_TOKEN"]
def handler(event, _context): headers = event.get("headers") or {} if headers.get("x-vroxy-wake-token") != WAKE_TOKEN: return {"statusCode": 403, "body": json.dumps({"error": "forbidden"})} boto3.client("ec2").start_instances(InstanceIds=[INSTANCE_ID]) return {"statusCode": 200, "body": json.dumps({"ok": True, "instance": INSTANCE_ID})}Set INSTANCE_ID to the EC2 instance the agent runs on and WAKE_TOKEN
to the same token you saved on the agent, then paste the function URL as
the agent’s Wake URL. Work is held here until the box boots and the
agent’s first heartbeat picks it up — nothing is dropped.
Choosing who dispatch runs as
Section titled “Choosing who dispatch runs as”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:
- Opens a GitHub issue in that repo containing the feedback context, filed with the App’s installation token.
- Starts a Copilot agent task on that repo against its base branch, asking for a pull request — using your personal authorization.
- 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.
- 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.
Dispatching without a browser
Section titled “Dispatching without a browser”The same thing works over the REST API, so a script or your own admin can dispatch without anyone opening the workspace:
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.