Agent bridge

Give the coding agent you already have a seat at the table.

MidMeeting can hand the live meeting straight to an agent CLI running on your own machine instead of an API key. Settings, Copilot provider, Agent bridge. The app then listens on a local connection, and any agent that can run a shell can attach, hear the room, answer what you highlight, and play the agents you armed, with everything it already knows about your repos, your notes and your tools. No key to buy, nothing leaves the machine unless your agent itself calls out.

Step 1. Open MidMeeting once.

The app installs midmeeting-bridge for you the first time it launches, and keeps the binary in step with every update after that. Nothing to download by hand, nothing to keep at the right version yourself.

PlatformInstalled toOn your PATH
Linux~/.local/share/MidMeeting/binsymlinked from ~/.local/bin
macOS~/Library/Application Support/MidMeeting/binsymlinked from ~/.local/bin
Windows%LOCALAPPDATA%\MidMeeting\binadded to the user PATH

If a terminal does not find midmeeting-bridge, open a new one, since a PATH change only reaches terminals started after MidMeeting ran. Still nothing? Settings, Copilot, Agent bridge shows the exact command path.

Manual install (fallback)

The app does this for you on first launch. Use one of these only if a terminal still cannot see the command.

$ curl -fsSL https://midmeeting.com/bridge.sh | sh

It detects your platform, downloads the right binary, and puts it on your PATH as midmeeting-bridge.

On Windows, run this in PowerShell instead:

$ irm https://midmeeting.com/bridge.ps1 | iex

Or download it directly:

Or by hand: put the binary on your PATH as midmeeting-bridge and make it executable.

$ mv midmeeting-bridge-linux-x86_64 ~/.local/bin/midmeeting-bridge

$ chmod +x ~/.local/bin/midmeeting-bridge

Linux x86_64, macOS 14.4 and later on Apple Silicon, and Windows x86_64. Intel Macs are not supported yet.

Platform notes:

Linux and macOS

A Unix domain socket, default $XDG_RUNTIME_DIR/midmeeting/bridge.sock, falling back to /tmp/midmeeting/bridge.sock. macOS normally has no XDG_RUNTIME_DIR, so the path there is /tmp/midmeeting/bridge.sock.

Windows

TCP on loopback, default 127.0.0.1:47621, protected by a random token. MidMeeting writes the address, token and its process id to %LOCALAPPDATA%\midmeeting\bridge.json while the bridge is on, and deletes the file when it stops. Only loopback is ever bound, so the Windows Firewall never prompts. A wrong token makes every midmeeting-bridge subcommand exit 1 with a handshake failed error.

Custom address

Any platform can use TCP instead: enter 127.0.0.1:PORT in Settings, Copilot provider, Agent bridge, Address. On Linux and macOS the state file then moves to $XDG_RUNTIME_DIR/midmeeting/bridge.json (or /tmp/midmeeting/bridge.json).

WSL

WSL2's default NAT mode cannot reach a loopback port on Windows. Turn on mirrored networking (networkingMode=mirrored in %USERPROFILE%\.wslconfig, Windows 11 22H2 or later, then wsl --shutdown) and localhost works from inside WSL; the token file is then readable at /mnt/c/Users/<you>/AppData/Local/midmeeting/bridge.json. Claude Code and Codex also run natively on Windows in PowerShell, where this step is not needed.

Step 2. Install the skill.

A skill is a short markdown file that teaches your agent how to attach to the bridge, when to write a note, and when to stay quiet. The four agent CLIs below read the same SKILL.md format, and the desktop apps at the end of the list read the same folders.

One command installs it into every agent CLI it finds on your machine:

$ npx skills add matpb/midmeeting-web --skill midmeeting -g

Target one agent with -a claude-code, -a codex, -a cursor or -a grok. Update later with npx skills update.

Claude Code

~/.claude/skills/midmeeting/SKILL.md

$ mkdir -p ~/.claude/skills/midmeeting && curl -fsSL https://midmeeting.com/skills/midmeeting/SKILL.md -o ~/.claude/skills/midmeeting/SKILL.md

Codex CLI

~/.codex/skills/midmeeting/SKILL.md (also read from ~/.agents/skills/)

$ mkdir -p ~/.codex/skills/midmeeting && curl -fsSL https://midmeeting.com/skills/midmeeting/SKILL.md -o ~/.codex/skills/midmeeting/SKILL.md

Cursor CLI

~/.cursor/skills/midmeeting/SKILL.md

$ mkdir -p ~/.cursor/skills/midmeeting && curl -fsSL https://midmeeting.com/skills/midmeeting/SKILL.md -o ~/.cursor/skills/midmeeting/SKILL.md

Grok Build

~/.grok/skills/midmeeting/SKILL.md (Grok also reads ~/.claude/skills)

$ mkdir -p ~/.grok/skills/midmeeting && curl -fsSL https://midmeeting.com/skills/midmeeting/SKILL.md -o ~/.grok/skills/midmeeting/SKILL.md

Claude Desktop, Code tab

reads ~/.claude/skills

Same file as Claude Code, nothing more to install. Open the Code tab, pick a folder, and say "listen to my meeting."

ChatGPT desktop, Codex tab

reads ~/.codex/skills

Same file as Codex CLI. Open the Codex tab and say "listen to my meeting."

Once it is installed, type /midmeeting in the agent, or just say "listen to my meeting."

The full file, to read or copy by hand:

---
name: midmeeting
description: Use on "/midmeeting", "listen to my meeting", "join the meeting", "watch MidMeeting", "attach to the bridge": attaches this session to the MidMeeting desktop app's agent bridge, streams the live transcript in, answers questions asked in the app, and plays the advisors the user armed. Not for summarising a finished transcript and not for transcribing a file.
---

# MidMeeting agent bridge

MidMeeting is a local meeting recorder with a live transcript. When its copilot is set to
Agent bridge, the app hands the transcript to an agent running on the same computer instead
of a cloud key. This skill makes this session that agent. It works the same on Windows,
macOS and Linux through one command, `midmeeting-bridge`, which the app installs.

## The one rule that matters: silence

Everything you write in this chat becomes a notification on the user's screen while they
are in a call. So:

- A `tail` or `segment` line with nothing to act on produces no visible output at all. No
  "no action needed", no "still listening", no summary of what was just said, no emoji,
  no one-word acknowledgement.
- Answers to asks and agent turns go through `midmeeting-bridge`, never mirrored into the
  chat. The app shows them.
- Write in the chat only when the user speaks to you here, when the meeting ends, or when
  the bridge itself breaks and the app cannot say so.
- When in doubt, say nothing. A quiet agent is doing its job.

## Attach

1. `midmeeting-bridge status`. Exit 0 prints `connected <endpoint>`. Anything else means
   MidMeeting is not running with Agent bridge selected: say so once, then stop. If the
   command is missing, the path is shown in the app under Settings, Copilot, Agent bridge,
   and midmeeting.com/agents explains the install.
2. Start `midmeeting-bridge tail --events ask,agent,cycle` under a monitor that wakes
   this agent on EVERY line of output and stays up for the whole meeting (in Claude
   Code: the Monitor tool with `persistent: true`). A background shell job will not do:
   it reports only when the process exits, and a tail never exits, so every ask and
   advisor turn queues unanswered while the app tells the user the agent has been
   thinking for ten minutes. If the only long-running option is a background job, do
   not attach: say so and stop. Never block on the tail in the foreground, and never
   poll instead of a monitor. `--events` tells the bridge which broadcast types to send
   this client, one of `segment, tail, ask, agent, cycle, pause`, and it survives the
   tail's automatic reconnect. Read every JSON line as it arrives:
   - `{"type":"ask","id","question","selection":{"text"}}`: the user highlighted text in
     the app and asked a question. `question` comes before `selection` because a
     wrap-up selection is the whole transcript; if your client truncates long
     lines, read the question first and never answer an ask you cannot see.
   - `{"type":"agent","id","agent","name","system","user"}`: a poke from the Jump in
     button, or a highlighted-span question, for one advisor. `system` is its role and
     rules, `user` is the transcript window.
   - `{"type":"cycle","id","user","agents":[{"id","agent","name","system","cards"}]}`:
     every advisor due this turn, sharing one `user` transcript window. Answer each
     entry in `agents` by its own `id`, exactly like an `agent` line; PASS is the
     default for each.
   - `{"type":"pause","id","from_ms","to_ms","text"}`: sent only to a client that lists
     `pause` in `--events`; `text` is every line finalised since the previous pause,
     plus the current provisional tail. It exists for a conversational agent that
     answers in its own chat every time the user stops talking, not for the standard
     advisor flow above, which does not need it.
   - If the line you received looks cut (your monitor truncates long lines), never
     answer from it: fetch it whole first with `midmeeting-bridge turn <id> --out
     /path/to/turn.txt`, using the id at the start of the line, which is always
     visible. Read the file, then answer each advisor id.

   If you also want to follow along as words land, add `segment` (or `tail`) to
   `--events`, at the cost of one model turn per line received. For most agents the
   answer is no: pull the transcript on demand instead (see Respond).
3. Say "Listening" once, then apply the silence rule.

Track labels: `you` is the user's microphone, `them` is the computer's audio, normally the
other side of the call. Several people sharing the user's room all land on `you`, so a
track is a side of the call, not a person.

## Respond

- An `ask` is always answered, quickly, grounded in the transcript seen so far. Verify a
  factual claim with your tools first when you can.
  `midmeeting-bridge answer <id> "<answer>"`
  A question starting with `Over the whole meeting:` is a wrap-up preset: `selection.text`
  is the full transcript, and the answer may run long (a summary, action items, or a
  complete HTML document when asked for one). Never answer a wrap-up from the event line:
  the transcript in it is long and your tooling may have cut it, so fetch it whole first:
  `midmeeting-bridge ask <id> --out /path/to/transcript.txt` prints the question and writes
  the full transcript to the file. Read the file, then answer through a file or stdin:
  `midmeeting-bridge answer <id> @/path/to/answer` or `midmeeting-bridge answer <id> -`.
  The same fetch works for any ask whose line looked truncated. When an ask needs more
  context than its `selection` alone, pull it on demand rather than keeping the whole
  meeting in the chat: `midmeeting-bridge transcript --since <ms>` (or `--out FILE`)
  prints the finalised lines since that offset, plus the current provisional tail.
- An `agent` line is you playing that advisor by its `system` prompt, not by your own
  taste. PASS is the default: `midmeeting-bridge answer <id> PASS`. Most turns deserve no
  note. Reply with a card only when a sharp colleague in the room would interrupt: a wrong
  number, a risk nobody named, a contradiction with something said earlier.
  `midmeeting-bridge answer <id> '{"kind":"idea","text":"<40 words or fewer>","why":"<20 words>"}'`
  with `kind` one of `claim_check`, `risk`, `question`, `idea`, `correction`. The 40 and
  20 word limits are hard: the app cuts a longer `text` or `why` at the limit and shows
  it with a trailing ellipsis, so the reader sees a truncated card, not a warning. Count
  the words before answering; one sentence is usually enough. The app still spaces cards
  by the advisor's chattiness; a dropped reply just clears its thinking state. A poke from the Jump in button arrives the same way and is expected to
  produce a card.
- A `cycle` line bundles every advisor due this turn. Answer each entry in its `agents`
  list separately, by that entry's own `id`, exactly as you would an `agent` line: PASS
  is still the default, and a card uses the same JSON shape, and if the line looked cut
  fetch it whole first with `midmeeting-bridge turn <id> --out FILE` as in Attach.
- Reply to every `ask`, `agent` and `cycle` id within about a minute. The app forgets a
  request after 180 s, and it never sends an advisor a new `cycle` turn while its previous
  one is unanswered, so a slow reply costs that advisor its next turn. If several lines
  still pile up in your monitor, answer the newest and PASS the rest at once.
- Run the meeting on a fast model or a low effort level. Measured on one advisor turn:
  Sonnet answers in 2 to 3 seconds at any effort, Opus in 4 to 8 seconds, and Opus at
  xhigh in about 14 seconds through Claude Code, before the tool calls a real cycle
  adds. Deep thinking belongs in the report after the call, not in the live lane.
- `tail` and `segment` lines are context, never answered.
- One agent per meeting. The bridge sends every line to every attached client, so two
  attached agents both answer everything.

## Detach

When the user says the meeting is over, or the bridge goes away, stop the `tail` process
and do not leave it running. Then, if you have a memory, save a short record of the
meeting: what was decided, what you answered, what is still open. Keep it to a few lines.

## Gotchas

- The tail reconnects on its own when the app restarts, printing `reconnecting…` and
  `reconnected` on stderr. That is normal, not a failure. If replies still stop landing,
  run `status`.
- The tail cadence is a floor, not a promise. A delayed line is not a dropped connection.
- From WSL, point the command at the Windows state file:
  `midmeeting-bridge --state /mnt/c/Users/<you>/AppData/Local/midmeeting/bridge.json status`
  (needs mirrored networking, see midmeeting.com/agents).

Download SKILL.md

Step 3. Turn it on in MidMeeting.

01

Settings, Copilot provider.

Choose Agent bridge instead of an API key or a local model.

02

Start a meeting.

MidMeeting opens the bridge and waits for a watcher.

03

In your agent, type /midmeeting.

It attaches, starts listening, and stays quiet until it has something worth saying.

Let your AI build your advisors.

The midmeeting-advisors skill teaches your agent to create, edit and tune MidMeeting advisors for you. It edits settings.json safely, so your advisor lineup still loads.

One command installs it into every agent CLI it finds on your machine:

$ npx skills add matpb/midmeeting-web --skill midmeeting-advisors -g

Claude Code

~/.claude/skills/midmeeting-advisors/SKILL.md

$ mkdir -p ~/.claude/skills/midmeeting-advisors && curl -fsSL https://midmeeting.com/skills/midmeeting-advisors/SKILL.md -o ~/.claude/skills/midmeeting-advisors/SKILL.md

Codex CLI

~/.codex/skills/midmeeting-advisors/SKILL.md (also read from ~/.agents/skills/)

$ mkdir -p ~/.codex/skills/midmeeting-advisors && curl -fsSL https://midmeeting.com/skills/midmeeting-advisors/SKILL.md -o ~/.codex/skills/midmeeting-advisors/SKILL.md

Cursor CLI

~/.cursor/skills/midmeeting-advisors/SKILL.md

$ mkdir -p ~/.cursor/skills/midmeeting-advisors && curl -fsSL https://midmeeting.com/skills/midmeeting-advisors/SKILL.md -o ~/.cursor/skills/midmeeting-advisors/SKILL.md

Grok Build

~/.grok/skills/midmeeting-advisors/SKILL.md (Grok also reads ~/.claude/skills)

$ mkdir -p ~/.grok/skills/midmeeting-advisors && curl -fsSL https://midmeeting.com/skills/midmeeting-advisors/SKILL.md -o ~/.grok/skills/midmeeting-advisors/SKILL.md

Claude Desktop, Code tab

reads ~/.claude/skills

Same file as Claude Code, nothing more to install.

ChatGPT desktop, Codex tab

reads ~/.codex/skills

Same file as Codex CLI.

Or hand your agent this prompt directly:

Install the MidMeeting advisors skill: download https://midmeeting.com/skills/midmeeting-advisors/SKILL.md into your skills folder as midmeeting-advisors/SKILL.md (Claude Code: ~/.claude/skills, Codex: ~/.codex/skills, Cursor: ~/.cursor/skills, Grok: ~/.grok/skills). Then follow it to create a MidMeeting advisor that [describe what it should watch for, and who the meeting is with].

The full file, to read or copy by hand:

---
name: midmeeting-advisors
description: Creates or tunes MidMeeting advisors in settings.json without breaking the app. Use on "create a MidMeeting agent", "add an advisor", "my agent never speaks". Not for joining a meeting (midmeeting).
---

# MidMeeting advisors

Produces one advisor entry in MidMeeting's `settings.json` that loads cleanly and speaks when it should. Needs first: what the advisor is for, and for a meeting advisor, who the meeting is with and what it is about.

This skill writes to the app's settings file and stops and restarts the app.

## The file

`<data dir>/MidMeeting/settings.json`:
- Linux: `~/.local/share/MidMeeting/settings.json`
- macOS: `~/Library/Application Support/MidMeeting/settings.json`
- Windows: `%APPDATA%\MidMeeting\settings.json`

Advisors live in the `agents` array. One entry:

```json
{
  "id": "custom-<short-slug>",
  "name": "<shown in the app, 1 to 3 words>",
  "role_prompt": "<see step 4>",
  "glyph": "gear",
  "cadence": "balanced",
  "mode": "proactive",
  "thinking": "brief",
  "enabled": true,
  "builtin": false
}
```

| Field | Allowed values |
|---|---|
| `glyph` | `gear`, `crown`, `pen`, `megaphone`, `flame`, `magnifier`, `list` |
| `cadence` | `relaxed`, `balanced`, `chatty` (how often its cards may appear) |
| `mode` | `proactive` (joins every cycle), `on_demand` (only when poked) |
| `thinking` | `quick`, `brief`, `deep` |

## Steps

1. Check whether the app is running. If the user is at the screen, offer the app's own agent editor instead: it validates what it saves. Otherwise, before writing, ask the user to close it or stop it yourself by its process id. Never kill by a name pattern that also matches your own shell command. The app may save over this file while it runs, so an edit made with it open can be lost.
2. Copy the file to `settings.json.bak-<date>` beside it.
3. Pick a `glyph` from the table. Never an emoji: some color emoji crash the app's web view on launch.
4. Write the `role_prompt` in this order:
   1. Who the advisor is and who it serves, in one sentence.
   2. The context it cannot get from the transcript: the other party, the project, what the user already knows and does not know. Only what the user told you; ask for anything missing instead of filling it in.
   3. A list of triggers, each starting "Write a note when". Name concrete situations, never "when relevant".
   4. What never to do: summarise, cheer, repeat a point, invent facts.
   5. Which card kinds to prefer: `idea`, `question`, `risk`, `claim_check`, `correction`.

   A prompt that says only "speak when it truly matters" stays silent all meeting. For a learning call, say "speak up readily".
5. Set `cadence` and `mode` to what the user asked for. When unsure, pick `balanced` and `proactive`.
6. Append the entry, or replace the one with the same `id`. Keep every other field of the file untouched, and keep emoji in other entries as they are.
7. Check the copilot setting (`brain.provider`). With `agent_bridge`, the advisor speaks only while an AI agent is attached to the bridge (the midmeeting skill). Tell the user in one line if the provider is not what they expect.
8. Start the app the way it was running before (desktop launcher, Start menu or Applications folder; on Linux `gtk-launch midmeeting` when a desktop entry exists) and wait 15 seconds.
9. Check: the app process is still running, the file still parses as JSON, the new `id` is in `agents` with a glyph from the table, and there is no new crash report for the app's web process. On Linux: `coredumpctl list --since "-1min"` prints nothing. Any failure: restore the backup, restart, and tell the user what failed.

## Stopping rule

If the app fails to start twice with the new entry, restore the backup and stop. Tell the user which field you suspect, and suggest creating the advisor in the app's editor instead.

Download SKILL.md

What your agent receives.

Every line from midmeeting-bridge tail is one JSON object on its own line. Add --events ask,agent,cycle (or any subset of segment, tail, ask, agent, cycle, pause) to receive only those types; without it a client gets everything except pause, which is opt-in only, and the filter survives the tail's automatic reconnect.

typefieldsmeaning
readytransportthe first line, {"type":"ready","transport":"unix"} or {"type":"ready","transport":"tcp"}, sent right after the connection is accepted (after a correct hello on TCP); midmeeting-bridge swallows it, so tail output is unchanged, and status only prints connected once it has seen it
taillines[].track, text, from_ms, to_msthe provisional live line, replaced on every push
segmenttrack, text, from_ms, to_msa finalised line, sent once, 25s or more after it was spoken
askid, selection.text, questionthe user highlighted text and asked a question
agentid, agent, name, system, usera poke or a highlighted-span question for one armed agent: system is its role prompt, user is the transcript window
cycleid, user, agents[].id, agents[].agent, agents[].name, agents[].system, agents[].cardsevery agent due this turn, sharing one user transcript window; answer each entry in agents by its own id, same as an agent line
pauseid, from_ms, to_ms, textopt-in only, sent when speech stops after a run of talking; text is every line since the previous pause, for a conversational agent that answers in its own chat

Answer an ask with midmeeting-bridge answer <id> <text>. Reply to an agent or cycle turn the same way, or with PASS, its default. Pull a long ask in full, past any line truncation, with midmeeting-bridge ask <id> --out <file>, and an agent or cycle line the same way with midmeeting-bridge turn <id> --out <file>. Pull the transcript on demand with midmeeting-bridge transcript [--since <ms>] [--out <file>], so an agent that only wants ask and agent/cycle never has to pay a model turn for every spoken line. Volunteer an unprompted card with midmeeting-bridge card <agent-id> <kind> "<text>". Track you is your mic, them is everyone else.

Every command explains itself: midmeeting-bridge --help for the full list, or midmeeting-bridge tail --help for one command. It answers with no app running and never blocks.

Limits.

Intel Macs are not supported yet. Linux x86_64, Apple Silicon and Windows x86_64 all work.

One agent per meeting. The bridge sends every line to every watcher, so two attached agents would both answer every question.

The tail cadence is a floor. Provisional lines update within a second of a pause and at least every 5 seconds while someone talks. Finalised segments land 25s or more after they were spoken.

Bring your own brain, your own agent.

Download MidMeeting Back to the overview