Skip to main content
Glama
camilochs

vitela-bridge

by camilochs

vitela-bridge

The agent bridge for Vitela, the editor for ExactTeX.

It is a small program that runs on your machine. Your coding agent talks to it over the Model Context Protocol (MCP); it talks to the Vitela tab open in your browser. Every tool the agent calls runs inside that tab — the project, the compiler and the TeX engine are all there — and the answer comes back. Nothing leaves your machine.

One rule makes it safe to hand an agent the keys: the agent never edits text. A change it proposes lands in your document as an ExactTeX revision, signed agent, that you accept or reject in Vitela's review margin like any other suggestion.

The full guide, with screenshots: https://vitela.artificialfallibility.com/agent.

Install

Node 20 or newer. No install step: npx fetches and runs it.

Claude Code

claude mcp add vitela-bridge -- npx -y github:camilochs/vitela-bridge

Codex

codex mcp add vitela-bridge -- npx -y github:camilochs/vitela-bridge

Cursor, Windsurf, Zed, Claude Desktop and other MCP clients — add to the client's MCP configuration:

{
  "mcpServers": {
    "vitela-bridge": {
      "command": "npx",
      "args": ["-y", "github:camilochs/vitela-bridge"]
    }
  }
}

Related MCP server: vscode-agent-bridge

Pair

  1. Start your agent. The bridge starts with it. Ask the agent for the pairing code once — or for the pairing link (bridge_status returns both: code, and link of the form https://vitela.artificialfallibility.com/app?pair=123456, which pairs the tab by itself when opened).

  2. Open Vitela, press Agent in the header, type the code (or open the link). The card says Connected and closes.

  3. Work. The agent reads the project, runs the check, compiles, verifies the bibliography, and proposes changes you accept or reject in the margin. Reply on a card writes a note the agent reads; it withdraws that proposal and sends a better one.

The code is stable on this machine — made once, kept in ~/.config/vitela-bridge/code, reused on every start — and Vitela remembers it in the browser, so after the first time pressing Agent connects by itself. To get a new code, delete that file or set VITELA_BRIDGE_CODE.

Several sessions, one bridge

One machine runs one shared bridge, and every tab pairs with it using the same code — so two agent sessions can drive two papers at once, with no ports or codes to juggle.

  1. Start each session as usual; both spawn the bridge with the same port and code. The first to start holds the port and becomes the shared bridge; the next finds the port busy and attaches to it. Nothing to configure.

  2. Open a Vitela tab per paper and pair each with the same code (Agent button, or …/app?pair=123456).

  3. In each session, open its paper with project_open(id). The bridge binds that session to the tab showing that paper; from then on the session's tools go to that tab. A lone session with a lone tab needs no project_open.

bridge_status says whether a session is the shared bridge or attached to it, and how many tabs the bridge holds. The bridge lives with the session that started it: if that session ends, an attached session loses it and must be restarted.

Editing through cards

The bridge tells the agent how to edit when it connects (the MCP server's instructions), and every refusal says what to do instead. The rules, for a human reader:

  1. Few, large cards. One card per block the author reads as a unit: a paragraph, a section, the front matter, everything before or after a figure. Never a burst of small cards for one change; never one per sentence. A cut or rewrite of a paper is two substitutions, one before the figure and one after it.

  2. A set when several pieces are one change (revision_propose_set): one card, one Accept. Not a way to bundle unrelated edits.

  3. Anchor on exact live text, first occurrence; an anchor inside a pending card is refused.

  4. What a card cannot carry, and the way round: a bare % on the last line of a piece (end the piece a line earlier, or escape it as \% — a comment line inside a long piece is fine); a -> inside a substitution (cut the piece around the figure, or send a deletion and an addition as one set); braces that do not balance (cut where they close); an anchor inside a command's argument or a braced group (propose the enclosing block whole, or force: true when the cut must start there — force reaches every piece of a set).

  5. Pages and errors are measured in Vitela: compile after the author accepts. Nothing is compiled elsewhere first.

  6. A reply on a card is feedback: revisions_list carries it as notes; withdraw and propose again, improved.

Tools

Tool

What it does in the tab

bridge_status

Whether a tab is paired, the pairing code, the link that pairs a tab when opened — and, with several sessions, whether this one is the shared bridge or attached to it, and how many tabs it holds

projects_list, project_open

The projects in the tab; switch to one. With several sessions, project_open binds this session to the tab showing that paper

files_list, file_read

The open project's files and assets; read one

check

The ExactTeX check: diagnostics, coverage, bibliography state

compile

Compile to PDF; page count and diagnostics

claims, verify

The document's external claims; verify them against the public registries and write the dated record

report

The submission report's data

revision_propose

Propose an addition, deletion or substitution as a revision the author accepts or rejects — prose, or a whole structure (a typed table, a figure, a TikZ picture) with placement: "block"; braces travel as long as they balance. Signed with the client and version (read from the MCP handshake) and the model and provider the agent states — e.g. agent · claude-code 2.1.250 · claude-fable-5-1 (Anthropic) — so every proposal is traceable. Checked before it is written: an error the document does not already have refuses the proposal and answers with the diagnostic, leaving the file untouched; an advisory travels back beside the answer; force: true writes it anyway. Refused at the door, nothing written: a bare %, a -> inside a substitution, an anchor inside a command's argument, a space right after a macro's opening brace (TeX drops it — put the space before the macro), and a file that cannot carry a revision (a .cls, a .sty); suggestions live in .xtex, .tex and .bib files

revision_propose_set

Propose several edits as one change: one card, one group in the sidecar, one Accept for all of them. The check runs over the result of the whole set, and an edit that cannot be placed fails the set — nothing half-applied

asset_put

Write an image or PDF into the project (base64, up to 8 MB) so a proposed figure can point at it

page_image

One page of the compiled PDF as an image, so the agent can judge what only the eye can judge

revision_withdraw

Take back a proposal the agent made: the construct leaves and the document returns to what it said before

revisions_prune

Drop sidecar records whose construct is no longer in the text

revisions_list

Pending revisions and their authors, and the notes the author left on a card with Reply — feedback to read, then withdraw and re-propose

Configuration

Variable

Default

Meaning

VITELA_BRIDGE_PORT

4329

The local port the tab connects to

VITELA_BRIDGE_HOST

127.0.0.1

Bind address. 0.0.0.0 to reach a tab on another machine of your own network (a dev server over a tailnet, for instance)

VITELA_BRIDGE_CODE

stable per machine

Fix the pairing code; otherwise it is made once and kept in ~/.config/vitela-bridge/code

VITELA_BRIDGE_CERT, VITELA_BRIDGE_KEY

unset

A certificate and key. When both are set the bridge listens as wss://, which a page served over HTTPS can reach

VITELA_BRIDGE_PUBLIC

unset

The address (host:port) the tab should use for this bridge. bridge_status adds it to the pairing link as &bridge=

From another machine

A Vitela tab served over HTTPS (production, in a browser on your laptop) can only open an encrypted socket, and "localhost" there is the laptop, not the machine running the agent. Three things make it work over a tailnet:

  1. A certificate for the agent's machine. With Tailscale: tailscale cert <machine>.<tailnet>.ts.net (it needs HTTPS enabled for the tailnet). Keep the two files somewhere stable.

  2. The bridge bound to the network and given the certificate, in .mcp.json:

    "env": {
      "VITELA_BRIDGE_HOST": "0.0.0.0",
      "VITELA_BRIDGE_CERT": "/path/to/machine.tailnet.ts.net.crt",
      "VITELA_BRIDGE_KEY": "/path/to/machine.tailnet.ts.net.key",
      "VITELA_BRIDGE_PUBLIC": "machine.tailnet.ts.net:4329"
    }
  3. The link from bridge_status, opened on the laptop: https://vitela.artificialfallibility.com/app?pair=123456&bridge=machine.tailnet.ts.net:4329. The tab keeps the bridge address, so the next time the Agent button connects on its own.

The certificate expires; renew it with the same command and restart the agent. If the port is already held by another session's bridge, this one attaches to it (see Several sessions, one bridge); bridge_status says which role it has.

The tab connects to the bridge on the machine that serves the page for a plain-http dev server, and on 127.0.0.1 for localhost and for the published site.

License

MIT.

If the bridge is useful to you, a star on this repository helps others find it — and tells us it is worth the care.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to access live VS Code editor state, symbol navigation, diagnostics, and language-aware editing through MCP, bridging the gap between what the agent can infer from disk and what the editor actually knows.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides IDE-like coding capabilities for AI agents via MCP, enabling semantic code retrieval, symbol-level editing, refactoring, and navigation across many programming languages.
    MIT