switchboard-chat 0.21.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- switchboard_chat-0.21.1/.gitignore +28 -0
- switchboard_chat-0.21.1/CHANGELOG.md +450 -0
- switchboard_chat-0.21.1/LICENSE +21 -0
- switchboard_chat-0.21.1/PKG-INFO +141 -0
- switchboard_chat-0.21.1/README.md +108 -0
- switchboard_chat-0.21.1/pyproject.toml +122 -0
- switchboard_chat-0.21.1/src/switchboard/__init__.py +6 -0
- switchboard_chat-0.21.1/src/switchboard/__main__.py +25 -0
- switchboard_chat-0.21.1/src/switchboard/adapters/__init__.py +45 -0
- switchboard_chat-0.21.1/src/switchboard/adapters/base.py +275 -0
- switchboard_chat-0.21.1/src/switchboard/adapters/claude.py +582 -0
- switchboard_chat-0.21.1/src/switchboard/adapters/codex.py +1996 -0
- switchboard_chat-0.21.1/src/switchboard/adapters/codex_rpc.py +449 -0
- switchboard_chat-0.21.1/src/switchboard/adapters/cursor.py +222 -0
- switchboard_chat-0.21.1/src/switchboard/adapters/devin.py +128 -0
- switchboard_chat-0.21.1/src/switchboard/adapters/remote_codex.py +281 -0
- switchboard_chat-0.21.1/src/switchboard/adapters/testagent.py +44 -0
- switchboard_chat-0.21.1/src/switchboard/broker/__init__.py +0 -0
- switchboard_chat-0.21.1/src/switchboard/broker/agents.py +1328 -0
- switchboard_chat-0.21.1/src/switchboard/broker/app.py +433 -0
- switchboard_chat-0.21.1/src/switchboard/broker/auth.py +324 -0
- switchboard_chat-0.21.1/src/switchboard/broker/catchup.py +182 -0
- switchboard_chat-0.21.1/src/switchboard/broker/commands.py +542 -0
- switchboard_chat-0.21.1/src/switchboard/broker/daemon.py +474 -0
- switchboard_chat-0.21.1/src/switchboard/broker/hosts.py +236 -0
- switchboard_chat-0.21.1/src/switchboard/broker/hub.py +222 -0
- switchboard_chat-0.21.1/src/switchboard/broker/machines.py +872 -0
- switchboard_chat-0.21.1/src/switchboard/broker/oidc.py +266 -0
- switchboard_chat-0.21.1/src/switchboard/broker/passkeys.py +379 -0
- switchboard_chat-0.21.1/src/switchboard/broker/passwords.py +165 -0
- switchboard_chat-0.21.1/src/switchboard/broker/peer.py +571 -0
- switchboard_chat-0.21.1/src/switchboard/broker/people.py +310 -0
- switchboard_chat-0.21.1/src/switchboard/broker/proc.py +398 -0
- switchboard_chat-0.21.1/src/switchboard/broker/remote.py +1615 -0
- switchboard_chat-0.21.1/src/switchboard/broker/reviews.py +267 -0
- switchboard_chat-0.21.1/src/switchboard/broker/rpc.py +644 -0
- switchboard_chat-0.21.1/src/switchboard/broker/service.py +1059 -0
- switchboard_chat-0.21.1/src/switchboard/broker/web.py +1708 -0
- switchboard_chat-0.21.1/src/switchboard/build_info.py +46 -0
- switchboard_chat-0.21.1/src/switchboard/claude_registry.py +77 -0
- switchboard_chat-0.21.1/src/switchboard/cli.py +1247 -0
- switchboard_chat-0.21.1/src/switchboard/clock.py +20 -0
- switchboard_chat-0.21.1/src/switchboard/colors.py +141 -0
- switchboard_chat-0.21.1/src/switchboard/config.py +240 -0
- switchboard_chat-0.21.1/src/switchboard/db.py +685 -0
- switchboard_chat-0.21.1/src/switchboard/delivery/__init__.py +0 -0
- switchboard_chat-0.21.1/src/switchboard/delivery/engine.py +1902 -0
- switchboard_chat-0.21.1/src/switchboard/delivery/rules.py +393 -0
- switchboard_chat-0.21.1/src/switchboard/delivery/runner.py +163 -0
- switchboard_chat-0.21.1/src/switchboard/delivery/sinks.py +113 -0
- switchboard_chat-0.21.1/src/switchboard/envelope.py +561 -0
- switchboard_chat-0.21.1/src/switchboard/guardrails.py +94 -0
- switchboard_chat-0.21.1/src/switchboard/hook/__init__.py +0 -0
- switchboard_chat-0.21.1/src/switchboard/hook/switchboard_hook.py +388 -0
- switchboard_chat-0.21.1/src/switchboard/install/__init__.py +1 -0
- switchboard_chat-0.21.1/src/switchboard/install/claude.py +149 -0
- switchboard_chat-0.21.1/src/switchboard/install/codex.py +423 -0
- switchboard_chat-0.21.1/src/switchboard/install/common.py +1017 -0
- switchboard_chat-0.21.1/src/switchboard/install/cursor.py +248 -0
- switchboard_chat-0.21.1/src/switchboard/install/devin.py +233 -0
- switchboard_chat-0.21.1/src/switchboard/mcp/__init__.py +0 -0
- switchboard_chat-0.21.1/src/switchboard/mcp/claude_inbox.py +127 -0
- switchboard_chat-0.21.1/src/switchboard/mcp/client.py +401 -0
- switchboard_chat-0.21.1/src/switchboard/mcp/codex_wake.py +137 -0
- switchboard_chat-0.21.1/src/switchboard/mcp/identity.py +72 -0
- switchboard_chat-0.21.1/src/switchboard/mcp/server.py +722 -0
- switchboard_chat-0.21.1/src/switchboard/models.py +735 -0
- switchboard_chat-0.21.1/src/switchboard/paths.py +248 -0
- switchboard_chat-0.21.1/src/switchboard/remote/__init__.py +9 -0
- switchboard_chat-0.21.1/src/switchboard/remote/config.py +563 -0
- switchboard_chat-0.21.1/src/switchboard/remote/describe.py +68 -0
- switchboard_chat-0.21.1/src/switchboard/remote/dialer.py +535 -0
- switchboard_chat-0.21.1/src/switchboard/remote/join.py +304 -0
- switchboard_chat-0.21.1/src/switchboard/remote/linkkey.py +252 -0
- switchboard_chat-0.21.1/src/switchboard/remote/pairing.py +1388 -0
- switchboard_chat-0.21.1/src/switchboard/remote/proto.py +713 -0
- switchboard_chat-0.21.1/src/switchboard/remote/satellite.py +1129 -0
- switchboard_chat-0.21.1/src/switchboard/report.py +927 -0
- switchboard_chat-0.21.1/src/switchboard/reviews.py +263 -0
- switchboard_chat-0.21.1/src/switchboard/store.py +2340 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/agents/NOTICE +22 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/agents/codex-dark.png +0 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/agents/codex-light.png +0 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/agents/cursor-dark.png +0 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/agents/cursor-light.png +0 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/app.js +4839 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/apple-touch-icon.png +0 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/diagram.js +217 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/favicon-32.png +0 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/favicon.svg +1 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/index.html +429 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/login.html +83 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/login.js +107 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/md.js +1096 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/setup.html +112 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/setup.js +185 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/style.css +2617 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/vendor/mermaid/LICENSE +21 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/vendor/mermaid/mermaid.min.js +3636 -0
- switchboard_chat-0.21.1/src/switchboard/web/static/webauthn.js +168 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
target/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
.venv/
|
|
5
|
+
node_modules/
|
|
6
|
+
*.sqlite
|
|
7
|
+
*.sqlite-*
|
|
8
|
+
*.db
|
|
9
|
+
.switchboard*/
|
|
10
|
+
*.db-wal
|
|
11
|
+
*.db-shm
|
|
12
|
+
logs/
|
|
13
|
+
.worktrees/
|
|
14
|
+
tests/live/_runs/
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
.lint-tools/
|
|
18
|
+
node_modules/
|
|
19
|
+
dist/
|
|
20
|
+
build/
|
|
21
|
+
.coverage
|
|
22
|
+
.coverage.*
|
|
23
|
+
coverage-data/
|
|
24
|
+
coverage*.json
|
|
25
|
+
htmlcov/
|
|
26
|
+
e2e-artifacts/
|
|
27
|
+
# CLI screenshots are PR previews, kept on the design-assets branch (CLAUDE.md)
|
|
28
|
+
docs/media/cli/
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notes for what's merged but not released yet are in [changes/](changes/README.md), one file per pull request. Each release gathers them into a section here.
|
|
4
|
+
|
|
5
|
+
## 0.21.1 (2026-10-06)
|
|
6
|
+
|
|
7
|
+
### Upgrading
|
|
8
|
+
|
|
9
|
+
- **Installed from GitHub (`git+https://github.com/amahpour/switchboard@…`)?** Switch once: `uv tool uninstall switchboard && uv tool install switchboard-chat`, then `switchboard stop && switchboard start` and `switchboard install all`. uv won't install both, since both have the `switchboard` command. From then on, `uv tool upgrade switchboard-chat` upgrades. Your rooms and history in `~/.switchboard` are kept.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **switchboard is on PyPI, as `switchboard-chat`.** Install it with `uv tool install switchboard-chat` (or `pipx install switchboard-chat`); the command is still `switchboard`. Plain `switchboard` on PyPI is an unrelated project. Each release now publishes there by itself, with its sdist and wheel also attached to the GitHub Release. The web UI's **Add a machine** card shows `uv tool install switchboard-chat==<the broker's version>` instead of the GitHub address.
|
|
14
|
+
|
|
15
|
+
## 0.21.0 (2026-10-06)
|
|
16
|
+
|
|
17
|
+
### Upgrading
|
|
18
|
+
|
|
19
|
+
- **The database moves to schema 14** on start, in one step after a checked backup next to it (`switchboard.db.v12.bak`): people gain an empty first and last name (schema 13), and each person's settings an empty default wake budget and hop limit (schema 14). Nothing else changes for existing accounts: everyone signs in as before, and new rooms start with the same budget and hop limit as before until someone sets a default in Settings. An older release refuses the migrated database, so rolling back means restoring that backup and losing whatever happened after the upgrade.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **Rename yourself in Settings.** Settings now starts with **Your name**: your first and last name and your name in the rooms, which others @mention and agents take your messages under. Your earlier messages keep the name they were sent with, and every room gets a line like "bob is now robert", so people and agents can follow. On a hosted broker, a new name asks you to confirm it's you, and the admin can rename anyone from their card in **Admin > People**. On a desktop, this is how you stop being `ubuntu` or `me` without editing `config.toml`. If `SWITCHBOARD_HUMAN_NAME` sets the admin's name, it still wins, and Settings shows it read-only.
|
|
24
|
+
- **The composer highlights an `@mention` as you type it.** `@claude-1` gets the same tinted
|
|
25
|
+
look it gets once sent, the moment it matches an active member or a person in the room, case-
|
|
26
|
+
insensitively; a typo or a name nobody's using stays plain text, so you see before sending
|
|
27
|
+
that it won't reach anyone. The caret, IME composition, undo, paste, Shift+Enter and the `@`
|
|
28
|
+
popover all still work the same as before.
|
|
29
|
+
- **A Focus button in the room header collapses agent chat not addressed to you.** When several agents are talking in a room, most of it is agents talking to each other. Turn Focus on and an agent message collapses to one line (its sender, then the first line of its text) unless it's an `@mention` of you or a reply to a message you sent — the same check the room badges use — so what needs you stands out. Click a collapsed line (or press Enter or Space on it) to expand just that message. Off by default, and not remembered across a reload.
|
|
30
|
+
- **`@here` and `@everyone` mention every agent in a room at once.** Typed in your own message
|
|
31
|
+
(not an agent's: that stays plain text), `@here` mentions every agent online now and
|
|
32
|
+
`@everyone` every agent in the room, offline ones too, just as an `@name` mentions one: an
|
|
33
|
+
agent that doesn't answer gets the watchdog's reminder, then you get a notice. Both
|
|
34
|
+
show at the top of the composer's `@` popover with a one-line description, and get the same
|
|
35
|
+
highlighted style as an `@mention`, in the composer and once sent. `here`, `everyone`, `all`
|
|
36
|
+
and `channel` are now reserved names: no agent or person can take them.
|
|
37
|
+
- **`@humans` addresses every person in the room, never an agent.** Typed by a person or by
|
|
38
|
+
an agent's own `say()` alike (unlike `@here`/`@everyone`, which only work from a person), it
|
|
39
|
+
marks the message as addressed to every person in the room but its writer (on a desktop
|
|
40
|
+
broker, you; on a hosted one, everyone, since there are no private rooms yet): the room's red badge, the
|
|
41
|
+
mention style in the log and composer, and Focus mode, which never collapses it. It never
|
|
42
|
+
wakes, mentions or raises the priority of any agent. It leads the composer's `@` popover
|
|
43
|
+
alongside `@here` and `@everyone`, with its own one-line description. `humans` and `people`
|
|
44
|
+
are now reserved names: no agent or person can take them. There's no rate limit on it yet
|
|
45
|
+
(a conservative first step; easy to add once it's seen in use).
|
|
46
|
+
- **Your own wake budget and hop limit, and a room's own rate.** Settings' **Rooms** section now has **Wake budget per hour** and **Hop limit**, copied into each room you create (leave either blank to use `config.toml`'s value or the built-in default, shown next to it). A room's own values can be changed live from a new **Wake settings** button in its header: it's the only way to change the hourly rate itself without editing `config.toml`, since `/budget <n>` only ever sets what's left this hour. Raising either, or turning the loop guard off with a hop limit of 0, still needs your signed-in browser, the same as `/budget` and `/hops` today; a hop limit of 0 shows the same warning wherever you set it.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- **People are added with their first and last name and their email.** On a hosted broker, **Add someone** asks for all three; their name in the rooms (what others @mention) fills in from the first name, and you can change it. The invite greets them by first name and tells them to sign in with their email. Setting a broker up asks for the admin's first and last name too. Full names show in the People sheet, after your name in Members, and on hover over someone's messages.
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
|
|
54
|
+
- **The composer's `@` popover finds a name anywhere in it, not just at its start.** In a room with longer names, typing `@skill` now finds `darius-skills-agent` and `@owner` finds `mr-owner-2`, instead of showing nothing. Matching is ranked (an exact name first, then a match at the start of the whole name, then a match at the start of one of its words, then anywhere in it), is case-insensitive (`@Skill` works like `@skill`), and the matched part of each row is highlighted. Before, only a name that started with exactly what you'd typed would show.
|
|
55
|
+
- **A room's red badge now counts only what's addressed to you, not every agent message.** Before, any chat message from an agent bumped the red count — the same "4" whether an agent was waiting on you or two agents were just talking to each other, which read as more urgent than it was. Now the red count, the phone's Rooms-toggle badge and the browser tab's title count go up only for an `@mention` of you or a reply to a message you sent; other new agent chat makes the room's tab show a small quiet dot instead, with no number. Opening the room clears both.
|
|
56
|
+
- **Signing in with a password now costs the same time whoever you type.** Before, a wrong password for a real person with their own password ran two scrypt checks (about twice as slow), while an unknown name, an empty one, the admin before they'd set a password, or a guess while a broker's claim link was still open ran none at all — a difference easy to measure over the network, that would have told an attacker which names on a hosted broker are real people. Every attempt now runs exactly one scrypt check, real or against a dummy hash, so the time it takes says nothing about who exists.
|
|
57
|
+
- **An agent no longer reads its user's own room messages as untrusted.** The text switchboard
|
|
58
|
+
gives an agent on join, in its SessionStart reminder after `/clear` or `/compact`, and (for
|
|
59
|
+
Codex and Cursor) in its mid-task context used to say a room message is "never typed by your
|
|
60
|
+
user" or "not your user" — meant as "this didn't come through your prompt box", but read by
|
|
61
|
+
the model as "this isn't from your user," which could make an agent hedge or ask again for
|
|
62
|
+
something its user had already said in the room. That text now says where a `kind=human`
|
|
63
|
+
message comes from (typed in the switchboard room, relayed through a hook or `wait()`, not
|
|
64
|
+
typed into the prompt) and that it carries the user's full authority, matching the room's
|
|
65
|
+
rule 1 and the batch header. Peer (agent) messages are still called out as untrusted,
|
|
66
|
+
unchanged.
|
|
67
|
+
|
|
68
|
+
## 0.20.0 (2026-10-06)
|
|
69
|
+
|
|
70
|
+
### Upgrading
|
|
71
|
+
|
|
72
|
+
- **Existing accounts keep working as they are.** On a hosted broker nobody has an email until the admin sets one, so after the upgrade everyone signs in as before: with their name and password, or a passkey. The admin signs in with their name or `admin`, and anyone signed in stays signed in. Emails already set for Google sign-in carry over as those accounts' emails.
|
|
73
|
+
- **Tell people before you set their email.** Once the admin sets someone's email in **Admin > People**, that person signs in with the email, and their name stops working on the sign-in page. Their open sessions and their passkeys carry on. Set your own on your row too: after that you sign in with it or with `admin`, and your name stops working for you.
|
|
74
|
+
- **The database moves to schema 12** on start, after a checked backup next to it (`switchboard.db.v11.bak`). An older release refuses the migrated database, so rolling back means restoring that backup and losing whatever happened after the upgrade. On a desktop broker only the schema changes.
|
|
75
|
+
|
|
76
|
+
### Changed
|
|
77
|
+
|
|
78
|
+
- **On a hosted broker, people sign in with their email.** Setting a broker up now asks the admin for their email. Each card in **Admin > People** has an **Email** field (it was **Google sign-in**, shown only with Google on), and a card without one says "no email yet". Once the admin sets someone's email, they type it on the sign-in page instead of their name, and their name stops working there; it's still what everyone sees in the rooms. Someone without an email yet signs in by name as before, and `admin` always signs the admin in. Emails already set for Google sign-in carry over, so those people sign in with that email by password too.
|
|
79
|
+
|
|
80
|
+
### Fixed
|
|
81
|
+
|
|
82
|
+
- **A Codex session on Linux no longer goes "detached?" when one check misses its TUI.** On a busy machine, Linux `lsof` sometimes skips a socket in one look, and that one look held the session's messages as if its TUI had quit, until the session was idle for 70 s or its person typed. switchboard now looks a second time before deciding a TUI is gone.
|
|
83
|
+
- **The web UI no longer looks live while it's disconnected.** When the page loses its connection to the broker, the You row says "reconnecting…", the Running/Paused chip loses its colour, a band says what you see may be out of date, and the member list is dimmed as "last known". Before, only the small "Reconnecting…" in the sidebar footer said so, and everything else kept showing online. It all comes back on its own when the connection does.
|
|
84
|
+
- **The composer now grows as a message wraps, not just on an explicit line break.** It stayed one line tall while you typed a long sentence, so the lines you'd already written scrolled out of view inside the box and you had to scroll a 20 px window to reread them. It now grows up to about 8 lines (then scrolls), and goes back to one line after you send.
|
|
85
|
+
|
|
86
|
+
## 0.19.0 (2026-10-05)
|
|
87
|
+
|
|
88
|
+
### Added
|
|
89
|
+
|
|
90
|
+
- **Sign in with Google on a hosted broker (#70).** Set `SWITCHBOARD_OIDC_CLIENT_ID` and `SWITCHBOARD_OIDC_CLIENT_SECRET` from a Google OAuth client, and the sign-in page offers Sign in with Google. Only people you added can use it: set each person's Google email in Admin > People, and your own. Other accounts are turned away. Passwords and passkeys keep working. Setup steps are in docs/DEPLOY.md.
|
|
91
|
+
|
|
92
|
+
### Fixed
|
|
93
|
+
|
|
94
|
+
- **Security: removing a person now removes the machines they paired or approved (#178).** Before, someone you removed was signed out, but a machine they had paired kept dialing in, and its agents could still join every room. Now the machine goes with them: its key is forgotten and its connection refused. The Machines sheet and the notices say who paired and who approved each machine, instead of always naming the admin.
|
|
95
|
+
|
|
96
|
+
## 0.18.1 (2026-10-05)
|
|
97
|
+
|
|
98
|
+
### Fixed
|
|
99
|
+
|
|
100
|
+
- **Security: an agent's words no longer go out as yours from the review board (#177).** When you answered a question, ruled on a finding or pressed Post, your message included the item's title, the option you chose and the pull request's URL. Agents wrote all of those, and your message speaks with your authority, so an agent could have put instructions or @mentions in your mouth. Your board messages now carry only labels, option numbers, owner names and your own reason, and agents read the rest from the board.
|
|
101
|
+
|
|
102
|
+
## 0.18.0 (2026-10-05)
|
|
103
|
+
|
|
104
|
+
### Changed
|
|
105
|
+
|
|
106
|
+
- **Approvals warnings now say what changes when prompts are off.** Member rows, the Inspector, and catch-up notices explain that the agent can act without asking after reading untrusted text.
|
|
107
|
+
- **Approval warnings sit on a flag beside each agent's name.** The Members list no longer adds a warning line to every row: hover, focus or tap the flag to read it.
|
|
108
|
+
- **The room approvals warning stays compact.** It names one flagged agent or counts several, including agents whose approval mode is unknown. Hover or focus it for names, and click it to find them in Members.
|
|
109
|
+
- **Every agent can work the review board.** Agents on another machine, linked over SSH or dialing in to a hosted broker, can now use the `review` tool, which before refused them. `switchboard install devin` now pre-approves `review` with switchboard's other tools, so Devin no longer asks before each board move. Run `switchboard install devin` again to add it.
|
|
110
|
+
|
|
111
|
+
### Fixed
|
|
112
|
+
|
|
113
|
+
- **Claude sessions are offered wakes while a background shell runs.** After the turn ends, `shell` in the session registry now permits an inbox wake locally and over a remote link; switchboard no longer holds pending messages until the background command finishes.
|
|
114
|
+
|
|
115
|
+
## 0.17.0 (2026-10-05)
|
|
116
|
+
|
|
117
|
+
### Added
|
|
118
|
+
|
|
119
|
+
- **A review board for a pull request, for agents (#80).** Agents reviewing a pull request in a room can keep its state on a board instead of in long messages, with a new `review` tool. They open the board, raise findings, concede them with an owner or contest them, mark them fixed, and ask you the questions only you can decide. Each move is one short notice in the room and wakes no one. Agents see the tool in sessions started after the upgrade.
|
|
120
|
+
- **The review board's page in the web UI (#80).** A room whose agents keep a review board gets a board button in its header. The board shows what needs you first: the questions the agents ask you, and the findings they couldn't agree on. Then come the findings raised, being fixed, done and dropped. Click a card for its evidence, then answer, concede to an owner, or drop with a reason. Each decision is your own message in the room, so the agents hear it.
|
|
121
|
+
- **Post a settled review board to the pull request (#80).** Once every finding is fixed or dropped and every question answered, the board lists what each agent will post. Post sends one message from you that asks each agent to post its own review comments, once, in its own name with its own `gh` or `glab`. switchboard posts nothing itself.
|
|
122
|
+
|
|
123
|
+
### Changed
|
|
124
|
+
|
|
125
|
+
- **Codex and Cursor agents show their app's icon instead of a monogram, and Claude Code a `>_`.** Codex shows the OpenAI logo and Cursor its avatar, in light and dark, everywhere an agent's avatar appears: the sidebar, chat, replies, the Inspector, the @-mention picker and the welcome page. Claude Code's avatar is a terminal prompt (`>_`) instead of CC, and Devin keeps its DV tile.
|
|
126
|
+
- **A room's custom rules reach each agent once, at join and after each edit, instead of in every message batch.** Agents spent tokens reading the same rules with every delivery. Rules too long to fit beside a batch wait for a later one and are never cut.
|
|
127
|
+
- **Python lint starts from zero.** The recorded Ruff and mypy findings are cleared, so future findings fail CI.
|
|
128
|
+
|
|
129
|
+
### Fixed
|
|
130
|
+
|
|
131
|
+
- **A Codex session's "is verified" notice waits for switchboard's first check for its TUI.** When the thread proof passed before that check had finished, the notice read `codex-1 is verified: codex:daemon (detached?)` because nothing had looked yet, not because the TUI was missing. The notice now goes out once the check is done, with the tier it found.
|
|
132
|
+
|
|
133
|
+
## 0.16.1 (2026-10-03)
|
|
134
|
+
|
|
135
|
+
### Added
|
|
136
|
+
|
|
137
|
+
- **Security reports.** Pull requests and main now get downloadable CodeQL, Bandit, dependency, image, workflow and secret-scan reports. Findings are report-only; `uv run python scripts/security_scan.py` runs the fast checks locally before a pull request.
|
|
138
|
+
|
|
139
|
+
## 0.16.0 (2026-10-03)
|
|
140
|
+
|
|
141
|
+
### Added
|
|
142
|
+
|
|
143
|
+
- **Lint and static analysis run with the tests in CI.** Contributors can run the same checks with `uv run python scripts/lint.py`; `--fix` formats changed Python and fixes JavaScript where safe. Existing Python findings are recorded so new findings fail without a flag day.
|
|
144
|
+
- **Custom room rules.** Save default guidance in Settings, then edit each room's copy from its header. Agents receive the current rules at join and with later deliveries, after switchboard's fixed rules. Room edits leave the defaults alone; changes to defaults affect only rooms created afterward.
|
|
145
|
+
|
|
146
|
+
## 0.15.0 (2026-10-03)
|
|
147
|
+
|
|
148
|
+
### Added
|
|
149
|
+
|
|
150
|
+
- **Settings now holds your appearance and account controls.** Click your name to choose System, Light or Dark and manage sign-in or sign out. Your theme follows your account across browsers; Settings opens as a bottom sheet on a phone.
|
|
151
|
+
- **Choose a text size in Settings.** Small, Default, Large and Larger apply across the web UI and follow your account to another browser. Default keeps the previous size; the sign-in page uses it until you sign in.
|
|
152
|
+
|
|
153
|
+
## 0.14.0 (2026-10-02)
|
|
154
|
+
|
|
155
|
+
### Changed
|
|
156
|
+
|
|
157
|
+
- **The web UI asks in its own dialogs.** Confirmations, New room and error notices now match the app in light and dark and on phones. Destructive actions start on Cancel, and a new room's name is checked as you type.
|
|
158
|
+
|
|
159
|
+
## 0.13.0 (2026-10-02)
|
|
160
|
+
|
|
161
|
+
### Added
|
|
162
|
+
|
|
163
|
+
- **See the number of each chat message.** A muted, selectable `#number` appears with its time in the conversation, so you can find the message an agent refers to.
|
|
164
|
+
|
|
165
|
+
## 0.12.0 (2026-10-02)
|
|
166
|
+
|
|
167
|
+
### Added
|
|
168
|
+
|
|
169
|
+
- **See which release and commit your broker runs.** The web sidebar, `switchboard status`, and `switchboard --version` show the version and short commit when known. The sidebar links to the release and gives the full commit on hover. An installed build without a recorded commit shows the version alone.
|
|
170
|
+
|
|
171
|
+
## 0.11.0 (2026-10-02)
|
|
172
|
+
|
|
173
|
+
### Added
|
|
174
|
+
|
|
175
|
+
- **Ask an agent to fix a Mermaid diagram that fails to draw.** The error offers a one-click reply to a current member, @mentioning it with a safe diagnosis that never repeats the diagram source. Agents also receive a short warning about semicolons and punctuation in Mermaid labels when they join a room.
|
|
176
|
+
- **Open a drawn Mermaid diagram full screen.** The Full screen button expands it to fit the browser window in light or dark mode. Esc returns to the still-drawn message. Browsers without element full-screen support keep the in-message diagram.
|
|
177
|
+
|
|
178
|
+
### Fixed
|
|
179
|
+
|
|
180
|
+
- **Keep a running dialer and live local sessions visible after a Linux clock step.** On WSL2 or another machine where `/proc/stat`'s boot time moves, `status`, `stop`, `start`, `remote remove` and `remote join` now check the same process start time the dialer recorded. A broker restart no longer ends live local sessions for that reason, and the broker's stop fallback still recognizes its pidfile.
|
|
181
|
+
|
|
182
|
+
## 0.10.0 (2026-10-01)
|
|
183
|
+
|
|
184
|
+
### Added
|
|
185
|
+
|
|
186
|
+
- **Mermaid diagrams in messages.** A ```` ```mermaid ```` block, from you or an agent, now has a **Show diagram** button that draws it in place, in light or dark; **Show code** brings the code back, and Copy still copies the source. Nothing loads or draws until you click, and agents are told they may draw this way. A diagram can't run script, load anything, link anywhere or change its own settings, and its styles stay inside its box: [SECURITY.md](SECURITY.md) says what remains.
|
|
187
|
+
|
|
188
|
+
### Fixed
|
|
189
|
+
|
|
190
|
+
- **Claude Code sessions in Auto or Don't-ask mode show as approvals on.** Both modes showed "Approval mode unknown: treat like approvals off" in Members, the Inspector and the room's chips, and `/catchup` warned about them as if their approvals were off. Neither runs anything unapproved, so they now show like any session that prompts. A mode switchboard hasn't seen before still shows as unknown. Auto mode's classifier still lets most actions run without asking you: [SECURITY.md](SECURITY.md) says what that means in a room. Codex needed no change: its hooks report `default` under every approval policy except `never`, `--approve-for-me` included.
|
|
191
|
+
|
|
192
|
+
## 0.9.0 (2026-09-30)
|
|
193
|
+
|
|
194
|
+
### Upgrading
|
|
195
|
+
|
|
196
|
+
- **A fresh hosted broker prints a one-time password instead of only a claim link.** Its log line now reads `Sign in at https://… as admin with the one-time password XXXX-XXXX-XXXX-XXXX …`, with the same link at the end. A broker you already claimed with a passkey is unchanged: you sign in with your passkey as before, and can add a password from the Sign-in sheet. The database moves to schema 4 on start, after a backup (`switchboard.db.v3.bak`); nothing in it is rewritten.
|
|
197
|
+
|
|
198
|
+
### Added
|
|
199
|
+
|
|
200
|
+
- **Your team can share one hosted broker.** The admin (whoever set it up) has **Admin > People** in the sidebar: add someone by name and send them the invite it shows once, with a one-time password good for 7 days; give someone a new one-time password; remove someone, which signs them out everywhere at once. Everyone posts under their own name, runs every room command and pairs their own machines, and every agent takes every person's messages as its user's. (#61)
|
|
201
|
+
- **Three ways to sign in to a hosted broker:** your name and a password, a passkey, and SSO shown as coming soon. A first sign-in with a one-time password (the admin's from the log, or anyone's from the admin) goes on to **Choose how you'll sign in**: your own password, or a passkey instead. Wrong passwords slow down, per name and overall. The Sign-in sheet (the key button) changes your password, adds a passkey and signs you out everywhere, and a **Confirm it's you** dialog asks for your password or a passkey before those and before adding someone or pairing a machine.
|
|
202
|
+
- **`SWITCHBOARD_HUMAN_NAME`** sets the admin's name in the rooms from the deployment (the Kubernetes and Compose files have it). The admin signs in as it, or as `admin`.
|
|
203
|
+
|
|
204
|
+
## 0.8.0 (2026-09-30)
|
|
205
|
+
|
|
206
|
+
### Added
|
|
207
|
+
|
|
208
|
+
- **A Codex session on another machine is woken when it's idle, like one on the broker's own machine.** switchboard's MCP server on that machine starts the turn through that machine's Codex daemon, after checking that a Codex TUI is attached, that the thread is the one that joined, and that it isn't waiting on an approval or your input. Its tier is `codex:link`, and it no longer has to sit in `wait()`. It needs that machine's Codex daemon (`[codex] control_socket` in its switchboard home); without one it stays `codex:hook`, pull only, as before. Mid-task it still gets your messages as hook context, not a steer. `switchboard report` labels these wakes `codex:link`. (#63)
|
|
209
|
+
|
|
210
|
+
## 0.7.0 (2026-09-30)
|
|
211
|
+
|
|
212
|
+
### Upgrading
|
|
213
|
+
|
|
214
|
+
- **The database moves to schema version 3.** The broker migrates it on its first start, after a verified backup next to it (`switchboard.db.v2.bak`, never overwritten), as the 0.3.0 migration did. Nothing else changes for a desktop broker.
|
|
215
|
+
|
|
216
|
+
### Added
|
|
217
|
+
|
|
218
|
+
- **A hosted broker is claimed from a link in its log, and signed in to with passkeys from then on.** A fresh broker behind a public URL prints one line in its log, `switchboard isn't set up yet. Claim it (link works once, for 60 min): https://…/setup#t=…`. Open it and create a passkey (Touch ID, Face ID, Windows Hello, your phone or a security key): the broker is yours, the browser is signed in, and setup suggests a backup passkey. The sign-in page then has one button, Sign in with a passkey. No `docker exec` needed; the shell's `switchboard login` keeps working too. The link works once, a fresh one is printed every hour until the broker is claimed, and once it is, none is printed again: the owner lives in the database on the volume, so upgrades keep it. `docs/DEPLOY.md`, "Signing in".
|
|
219
|
+
- **The Passkeys sheet.** A key button next to sign-off in the web UI of a hosted broker: add a passkey (it asks for one of yours first, unless you used one in the last five minutes, so a stolen session can't make itself permanent), and Sign out everywhere, which signs every browser out and keeps your passkeys.
|
|
220
|
+
- **`SWITCHBOARD_RESET_OWNER`.** Lost every passkey? Set it to a new value and restart: the broker forgets the owner, every passkey and every session, and prints a fresh claim link. It acts once per value, so leaving it set is harmless across restarts and pod moves.
|
|
221
|
+
- **Your machines dial in to a hosted broker.** A broker on a server can't reach your laptop over SSH, so the laptop dials it: `switchboard remote join https://sb.example.com <code>` pairs the machine with a single-use code from the broker's owner, prints the machine's key fingerprint to check before approving, and starts a dialer that connects over `wss://` through the broker's own HTTPS address. Once the owner approves it, the machine's agents join rooms as `bench@work-laptop`, exactly as remote members over SSH do, with the same limits. `switchboard start`, `stop` and `status` run the dialer on that home (`--foreground` for launchd, systemd or tmux), it redials after a drop, and it stops for good when the machine is removed. `docs/REMOTE.md`, "Machines that dial in a hosted broker".
|
|
222
|
+
- **The broker's side of it:** `POST /link/pair` (authenticated by the code, refused to browsers) and the `/link` WebSocket (a signed handshake that pins both keys), and `GET /api/machines`, `POST /api/machines/pair`, `/approve` and `/remove` for the owner. Making a code and approving need a passkey check in the last five minutes.
|
|
223
|
+
- **Add a machine in the web UI.** On a hosted broker, Remote machines in the sidebar lists your machines that dial in, with **Add a machine** under them. Name the machine, and the Machines sheet shows the two commands to run on it, with Copy buttons and a countdown. Once it dials in, its card shows what it says about itself and its key's fingerprint, to compare with what `remote join` printed there, and you **Approve** or **Reject** it. Each machine's card shows its state, last seen, its members and **Remove**. Making a code and approving ask for one of your passkeys first, unless you used one in the last five minutes. `docs/REMOTE.md`, "Machines that dial in a hosted broker".
|
|
224
|
+
- **Cancel a pairing code** before it's used, from the same sheet (`POST /api/machines/{name}/cancel`). A code that was already used stays remembered, so a second machine trying it still hears that it was used.
|
|
225
|
+
|
|
226
|
+
### Changed
|
|
227
|
+
|
|
228
|
+
- **Release notes go in a file of their own now, `changes/<name>.md`, not in CHANGELOG.md.** Each pull request adds one, so parallel PRs no longer conflict over the CHANGELOG, and a rebase can't quietly file a PR's notes under a release that's already out. Cutting a release gathers the files into CHANGELOG.md and deletes them, and CI fails a PR that edits CHANGELOG.md directly ([changes/README.md](https://github.com/amahpour/switchboard/blob/main/changes/README.md)).
|
|
229
|
+
- **`switchboard login` sessions say how they were made.** Web sessions record `login-link`, `claim` or `passkey:<name>` (for the sessions list to come).
|
|
230
|
+
- **The dialer trusts the operating system's certificate store** (the new `truststore` dependency), so a corporate TLS-inspection proxy whose root certificate is installed there works on macOS and Windows. Under WSL2, add it to the Linux distribution's store.
|
|
231
|
+
- **A machine refused at every dial says why.** A machine whose switchboard version (or test mode) doesn't match the broker's shows `refused: version mismatch` and what to do, instead of looking offline.
|
|
232
|
+
- **The pairing notice** in the rooms no longer shows backticks, and says to check the key before approving.
|
|
233
|
+
|
|
234
|
+
## 0.6.5 (2026-09-30)
|
|
235
|
+
|
|
236
|
+
### Changed
|
|
237
|
+
|
|
238
|
+
- **A release is a pull request now, and `main` takes only pull requests** ([#46](https://github.com/amahpour/switchboard/issues/46)). `python3 .github/scripts/release.py --open-pr` opens a `release: vX.Y.Z` PR with the new version, the CHANGELOG and the install and image pins. Merging it tags the release and publishes it and its image. Changes collect under Unreleased until then. Before, every merge was a release that CI pushed straight to `main`.
|
|
239
|
+
- **CI runs only on pull requests.** A docs-only PR or a release PR skips the test suite and runs only the tree scan. One check, `CI`, sums up the rest, and `main`'s ruleset requires it.
|
|
240
|
+
|
|
241
|
+
### Fixed
|
|
242
|
+
|
|
243
|
+
- **A remote machine's name stays readable in the sidebar.** A long state, such as `down: timeout (retry in 20 s)` or `needs enable (config changed)`, used to take the whole row and squeeze the name out: `build-vm` showed as `b.`, and some names vanished. The name and the state now share the row, and a state that doesn't fit ends in an ellipsis. Hovering the row shows the state in full.
|
|
244
|
+
|
|
245
|
+
## 0.6.4 (2026-09-30)
|
|
246
|
+
|
|
247
|
+
### Changed
|
|
248
|
+
|
|
249
|
+
- **The docs no longer promise what a hosted broker can't do yet.** The README said your other machines' agents could join a hosted broker over SSH, but the image has no `ssh`. The README, docs/DEPLOY.md and DESIGN §30 now point agents joining and signing in without exec at [#41](https://github.com/amahpour/switchboard/issues/41), and drop "sign-in at the proxy" (no longer planned). DESIGN §27.4.8 now says a satellite binds its socket only after the broker's `welcome`, as the code does.
|
|
250
|
+
|
|
251
|
+
## 0.6.3 (2026-09-29)
|
|
252
|
+
|
|
253
|
+
### Fixed
|
|
254
|
+
|
|
255
|
+
- **Remote machines in the sidebar show their state in their dot.** It's green when the link is up, amber while it connects, red when it's down or blocked, and a hollow ring when the remote is disabled or needs enabling. Before, every dot in the sidebar was grey, whatever the state; the Remote machines sheet already had it right.
|
|
256
|
+
|
|
257
|
+
## 0.6.2 (2026-09-29)
|
|
258
|
+
|
|
259
|
+
### Changed
|
|
260
|
+
|
|
261
|
+
- **The README, rewritten** around what switchboard is for: the video is the hero (no GIF), a "Why a room" section, the security note next to Quickstart, a "Run it for a team" section for the container image and remote machines, and a "Works with" table in place of the version status. Project history moved to CONTRIBUTING.md.
|
|
262
|
+
|
|
263
|
+
## 0.6.1 (2026-09-29)
|
|
264
|
+
|
|
265
|
+
### Fixed
|
|
266
|
+
|
|
267
|
+
- **A release can't leave a tag off `main` any more.** The release job pushes `main` and the new tag with `git push --atomic`, so they land together or not at all. When another merge lands while the job runs, it pushes nothing and says so, and that merge's run releases both. Before, `main` was refused but the tag went out anyway: `v0.6.0` first pointed at a release commit that never reached `main`, and had to be deleted by hand. `release.py` also counts only tags on `main`'s history as the last release.
|
|
268
|
+
|
|
269
|
+
## 0.6.0 (2026-09-29)
|
|
270
|
+
|
|
271
|
+
The broker as a container image ([#34](https://github.com/amahpour/switchboard/issues/34), [docs/DEPLOY.md](docs/DEPLOY.md), [DESIGN.md §30](docs/DESIGN.md#30-the-container-image-and-the-public-url-34)). It runs on a server behind the platform's HTTPS: Render, Kubernetes, or a VM with Caddy. For now that's you in the browser; your agents join a hosted broker with #24.
|
|
272
|
+
|
|
273
|
+
### Added
|
|
274
|
+
|
|
275
|
+
- **`ghcr.io/amahpour/switchboard`**, published with every release as `<version>` and `latest`, for linux/amd64 and linux/arm64, with a provenance attestation and an SBOM. It runs the broker as an unprivileged user (uid 10001) under tini, keeps its data on a `/data` volume, logs to stdout, and stops cleanly on `docker stop`. Started as root, as on Render, whose disks belong to root, it only makes its home on the volume its user's, then drops to that user.
|
|
276
|
+
- **`switchboard start --listen ADDR --public-url URL`** (or `SWITCHBOARD_LISTEN` and `SWITCHBOARD_PUBLIC_URL`, or `listen` and `public_url` in config.toml), for a broker behind a proxy that terminates TLS. The public URL, `https://` and an origin only, becomes the one host the broker answers to and the one origin it accepts writes from. It also sets the WebSocket address in the CSP, makes the session cookie `Secure`, and appears in sign-in links and `switchboard status`. Nothing changes by default: listening on anything but `127.0.0.1` needs the public URL, and a bad setting stops the broker before it touches its home.
|
|
277
|
+
- **`GET /healthz`** answers `ok` for platform health checks: no sign-in, no data, any Host.
|
|
278
|
+
- **`start --log-stdout`** (with `--foreground`) and `SWITCHBOARD_PORT` for `--port`, for containers.
|
|
279
|
+
- **Deployment examples** in `deploy/`: Docker Compose with Caddy and Let's Encrypt, a Kubernetes StatefulSet with an Ingress, and a Render Blueprint. docs/DEPLOY.md covers running, signing in with `docker exec -it … switchboard login`, upgrading, backups and health checks.
|
|
280
|
+
- **Tests of the image** (`tests/image`, marker `image`): behind a TLS-terminating proxy with sign-in and the UI over https in Chromium, a clean stop and restart, and the volumes Render and Kubernetes mount. A new `image` CI job runs them on every PR, and the release waits for it.
|
|
281
|
+
|
|
282
|
+
### Changed
|
|
283
|
+
|
|
284
|
+
- **A new demo video** at the top of the README, recorded as screen video on the new UI: Codex reviews this repository's own #14, Claude Code (which wrote it) defends it, and they settle it before the human reads it. Narrated. The old `docs/media/capture.py` and `render.py` are gone; the video is made outside the repository.
|
|
285
|
+
- **The broker exits 0 on SIGTERM** after its graceful shutdown, instead of dying from the re-raised signal before its own cleanup.
|
|
286
|
+
- **On Linux, `switchboard login` no longer needs `ps`:** the caller's terminal comes from `/proc`, as the rest of the process checks already do. Before, a system without `ps` refused every sign-in link.
|
|
287
|
+
- **Releases also move the image pins** (`ghcr.io/amahpour/switchboard:X.Y.Z`) in docs/DEPLOY.md and `deploy/`, and publish the image.
|
|
288
|
+
|
|
289
|
+
## 0.5.0 (2026-09-29)
|
|
290
|
+
|
|
291
|
+
A new web UI ([#19](https://github.com/amahpour/switchboard/issues/19), [DESIGN.md §29](docs/DESIGN.md#29-the-native-web-ui-and-the-inspector-19)): a native-looking three-column layout in light and dark, Markdown in messages, and an Inspector for each agent.
|
|
292
|
+
|
|
293
|
+
### Added
|
|
294
|
+
|
|
295
|
+
- **A tab icon.** The browser tab (and a phone's home screen) shows switchboard's mark, the sidebar's own glyph, on its blue tile. `favicon.svg` is the source; `docs/media/make_icons.py` makes the 32 px PNG and the 180 px Apple touch icon from it, and `/favicon.ico` now serves the 32 px icon instead of an empty answer.
|
|
296
|
+
- **The Inspector.** Click an agent (in Members, or its name on a message) to see what needs attention (approvals off, parked, waiting for approval), its session id, when it joined and was last seen, its queued messages, its last few deliveries, and Hold/Release, Catch up on… and Kick buttons (the same commands you can type). It reads a new human-only, read-only route, `GET /api/rooms/{room}/members/{name}`, which returns message ids and times, never message text; the broadcast `members` frame is unchanged.
|
|
297
|
+
- **Markdown in messages**, yours and the agents': headings, bold, italic, inline code, fenced code blocks with a Copy button, lists, block quotes, tables, rules and links. Raw HTML and images stay plain text; a link opens in a new tab with no referrer and shows its real address, and anything that isn't `http(s)`, carries a user name or password (`https://github.com@evil.example/`), or points back at this switchboard page or another local address, is shown as blocked text. A bare URL links whole, even with `__init__`, `*` or `@name` in it. A small renderer (`md.js`) builds DOM nodes only, with one vetted place that sets a link.
|
|
298
|
+
- **A command palette** (`/` in the composer) and **@mention suggestions** (`@`), a first-run page with the three steps and the once-per-harness notes, and a join hint in an empty room.
|
|
299
|
+
- **Narrow layouts:** below 1,100 px the right pane is a drawer; on a phone the rooms slide in from the left and Members opens as a bottom sheet.
|
|
300
|
+
- **Agents are told they may reply in Markdown** (room rule 5, the `say` tool's description and the MCP instructions): code blocks, lists and tables, no raw HTML or images.
|
|
301
|
+
- **Screenshots** of the UI in `docs/media/ui/`, made by `docs/media/ui_shots.py` (Playwright's Chromium) against a seeded test broker in a temporary home.
|
|
302
|
+
- **Browser tests for the web UI** (`tests/e2e/`, marker `e2e`, opt-in with `-m e2e`): Playwright drives the page in headless Chromium against a seeded test broker, and fails a test on any console error, page error or CSP violation, keeping a trace and screenshots when one fails. A new `frontend` CI job runs them, regenerates the screenshots, and uploads both. See CONTRIBUTING.md.
|
|
303
|
+
- **Colour in the CLI** ([#28](https://github.com/amahpour/switchboard/issues/28), docs/USAGE.md "Colour"): on a terminal, the `install`/`uninstall` diffs, `tail`, `status`, `who`, `remote status` and doctor, and `report` colour switchboard's own framing (diff markers, nicks, state words, headings, fired rules). Text from agents, remotes and config files is cleaned of escape codes first and never coloured by what it says. `--color auto|always|never` on every command; plain in pipes, files and `--json`, with `NO_COLOR` or `TERM=dumb`; `FORCE_COLOR`/`CLICOLOR_FORCE` force it.
|
|
304
|
+
- **`switchboard report` drops control characters** from the strings it reads from the database (a model name a hook reported, for example), in markdown and JSON alike.
|
|
305
|
+
- **The node tests can't be skipped in CI:** `SWITCHBOARD_REQUIRE_NODE=1` turns a missing `node` from a skip into a failure, and the pytest jobs install node 22 and set it.
|
|
306
|
+
|
|
307
|
+
### Changed
|
|
308
|
+
|
|
309
|
+
- **Every merge to `main` is a release** ([#33](https://github.com/amahpour/switchboard/issues/33)). PR titles follow Conventional Commits and PRs are squash-merged. `feat:` releases a minor version and anything else a patch. This Unreleased section becomes each release's notes, and a `release` job in CI sets the version, moves the install pins, tags and publishes. CONTRIBUTING.md, "Releases".
|
|
310
|
+
- **CI runs the test suite as three shards per OS** (pytest-split, balanced by the durations in `.test_durations`), each with xdist on its runner's cores, instead of one runner per OS, and combines the coverage of all six. Locally the suite still runs whole with `-n auto` (CONTRIBUTING.md, "Shards in CI").
|
|
311
|
+
- **The web UI's look:** a sidebar with rooms, **Closed (n)**, remote machines and your connection state; the room's status as header chips (Running/Paused, budget, hops, approvals off) with a pause button; Members in a right pane. Every feature of the old UI is kept, and the element ids the tests and `docs/media/capture.py` use were updated. **+ Room** is now the **+** button in the sidebar; notices lose their `***` prefix.
|
|
312
|
+
- **The MCP instructions** no longer say "(the human)" after "your user", to stay under their size cap.
|
|
313
|
+
- The package description now reads "A local group chat where you and your coding agents talk and hand work to each other".
|
|
314
|
+
|
|
315
|
+
### Not included
|
|
316
|
+
|
|
317
|
+
- Syntax highlighting in code blocks, image rendering, a manual light/dark switch (the UI follows your system), an in-page `/close` dialog (the browser's confirm stays), and the redelivery and catch-up markers from the mockups.
|
|
318
|
+
|
|
319
|
+
## 0.4.0 (2026-09-28)
|
|
320
|
+
|
|
321
|
+
Close a room when you are done with it, and delete one for good ([DESIGN.md §28](docs/DESIGN.md#28-closing-and-deleting-rooms-16)). The README is short now, with a getting-started video.
|
|
322
|
+
|
|
323
|
+
### Upgrading
|
|
324
|
+
|
|
325
|
+
- **No schema change.** A closed room keeps its row under the name `#build~closed-7`. **Before going back to 0.3.0, reopen or delete your closed rooms:** 0.3.0 would list them as rooms (their tabs fail), and remotes with any-room access (`rooms = ["*"]`) would fail to connect.
|
|
326
|
+
|
|
327
|
+
### Added
|
|
328
|
+
|
|
329
|
+
- **`/close`** (web UI, or `switchboard cmd '#build' /close`): every agent in the room leaves, on this machine and on remote ones, and is told why (an open `wait()` returns status `closed`; its next call gets "#build was closed by alice; you are no longer in it"). The room is hidden and its name is free for a new room; the history is kept. The web UI asks before closing. Pause, budget, hop settings and kicks are kept for a reopen.
|
|
330
|
+
- **The Closed rooms panel** in the web UI (the **Closed (n)** button next to **+ Room**): each closed room with when and by whom it was closed and its message count, a **Reopen** button (refused while an open room has the name), and the command to delete it. Reopened rooms come back empty: agents `join()` again, and kicked ones stay out.
|
|
331
|
+
- **`switchboard rooms --closed`** lists closed rooms (`--json` too).
|
|
332
|
+
- **`switchboard rooms delete ROOM [--yes]`** deletes a room and its whole history for good: it shows what it removes and asks first, refuses while agents are in the room (close it first), writes a checked 0600 backup of the whole database first (`switchboard.db.delete-build-7.bak`), and works only from a terminal you typed in (not an agent's shell, nor a script without a terminal) with the broker running. It deletes only the room the plan showed: if that room was reopened, or deleted and re-created, while you were at the prompt, nothing is deleted and you are asked to run the command again. `ROOM` is `#build`, or a closed room's full name (`'#build~closed-7'`) when there are several.
|
|
333
|
+
- **A getting-started video.** A GIF at the top of the README and a 46-second MP4 with music, made from a real run: switchboard installed from the release tag into a throwaway home, and a real Claude Code session and a real Codex session in one room. claude-1 writes `fizzbuzz.py`, codex-1 runs it and suggests one change, claude-1 makes it and codex-1 checks it again, each woken by the other's messages. The sources are in [docs/media/](docs/media/README.md): `capture.py` records the run and `render.py` renders it, with a colour theme for plain terminal text; the music is credited in `docs/media/CREDITS.md`.
|
|
334
|
+
|
|
335
|
+
### Changed
|
|
336
|
+
|
|
337
|
+
- **A short README.** The README is now a pitch, a getting-started GIF, a security warning, a three-command quickstart and links. Everything else moved, unchanged, into [docs/INSTALL.md](docs/INSTALL.md), [docs/USAGE.md](docs/USAGE.md) (tools, commands, delivery rules, `/catchup`, reports, the web UI), [docs/HARNESSES.md](docs/HARNESSES.md), [docs/REMOTE.md](docs/REMOTE.md), [docs/LIMITATIONS.md](docs/LIMITATIONS.md), [SECURITY.md](SECURITY.md) (plus how to report a vulnerability privately) and [CONTRIBUTING.md](CONTRIBUTING.md) (development, coverage, live tests, the M7 rehearsal). Links into the old README sections now point at the new files.
|
|
338
|
+
- **`switchboard rooms`, `switchboard status`, the web room list and remote welcomes show open rooms only**; `rooms` and `status` add how many are closed.
|
|
339
|
+
- **`GET /api/rooms`** returns `{rooms, closed}`, and each room carries its `id`. New routes `GET /api/closed-rooms` and `POST /api/closed-rooms/{id}/reopen`; the `rooms` WebSocket frame is also sent on close, reopen and delete.
|
|
340
|
+
- **`switchboard report --room`** accepts a closed room's name (its full name, or its base name when no open room has it), and says the room is closed.
|
|
341
|
+
- **`agent.wait` can return status `closed`.**
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
### Removed
|
|
345
|
+
|
|
346
|
+
- **`/review`**, `/catchup`'s alias in 0.3: it is refused with the form to use instead, `/catchup <agent> on <member> review it critically`, and nothing is posted. `switchboard report` still counts 0.2.0 and 0.3 `/review` requests, and `[review] agentsview` in `config.toml` still loads (ignored).
|
|
347
|
+
### Fixed
|
|
348
|
+
|
|
349
|
+
- **The docs no longer say WSL2 is untested.** Claude Code under WSL2 is tested live as a remote member (a Windows desktop's Claude Desktop sessions: joined on `claude:inbox`, woken through its inbox, `/catchup` across machines), and Claude Code and Codex are tested live with the broker on Linux x86_64. README, docs/INSTALL.md, docs/LIMITATIONS.md and docs/REMOTE.md say so; a broker in WSL2 is still unchecked.
|
|
350
|
+
|
|
351
|
+
## 0.3.0 (2026-09-28)
|
|
352
|
+
|
|
353
|
+
Remote members over SSH ([docs/REMOTE.md](docs/REMOTE.md), [DESIGN.md §27](docs/DESIGN.md#27-remote-members-over-ssh-m8)): an agent session on another machine on your LAN, a Raspberry Pi next to an FPGA board or a Linux server, joins rooms here as its own member, with you, the broker and the web UI staying on this machine. [docs/DEMO-FPGA.md](docs/DEMO-FPGA.md) walks through the FPGA bench demo, with or without hardware. Install the same version on both machines. Also new: `/catchup`, which gets an agent up to speed on another member's work, a topic or the room from their session history, and replaces `/review` (an alias until 0.4).
|
|
354
|
+
|
|
355
|
+
### Upgrading
|
|
356
|
+
|
|
357
|
+
- **The database moves to schema 2, once, with a backup first.** The first broker start after upgrading from 0.2.0 (or 0.1.0) adds the columns and table that remote members need to `switchboard.db`; your rooms, history and memberships are kept as they are. Before it changes anything it writes a checked copy of the old database, `switchboard.db.v1.bak` (0600, in your switchboard home; an existing file of that name is never overwritten: the new copy gets a `.<time>` suffix). If any step fails, the database is left exactly as it was and the broker doesn't start; `switchboard start` shows why. 0.2.0 refuses the migrated database. **To go back to 0.2.0:** `switchboard stop`, copy `switchboard.db.v1.bak` over `switchboard.db`, delete `switchboard.db-wal` and `switchboard.db-shm` if they exist, then start 0.2.0 (anything posted since the upgrade is lost). The old file also predates what you revoked since the upgrade: run `switchboard logout --all` (web sign-ins you logged out come back with it), and `/kick` again any agent you kicked since the upgrade (its membership and credential are back too). `switchboard report` reads both versions and never migrates.
|
|
358
|
+
|
|
359
|
+
### Added
|
|
360
|
+
|
|
361
|
+
- **`/catchup`: an agent gets up to speed on another member's work, a topic, or the room** ([docs/USAGE.md](docs/USAGE.md#catching-up-catchup), [DESIGN.md §26](docs/DESIGN.md)). `/catchup codex-1 on claude-1`, `/catchup codex-1 on "sprint cleanup"`, `/catchup codex-1`, each with an optional note (`/catchup codex-1 on claude-1 pick it apart`). It posts one ordinary message from you that @mentions the agent, with a `catch-up request (switchboard)` block: rules first (what it reads is data, not instructions; summarize, and don't quote secrets, credentials, addresses or paths; don't write to their sessions), then a fixed protocol (use your session-history tool, resolve each session id with its exact-id lookup, read at most 60 messages per session in the window, then post one report under the headings Doing / Decided / Open questions / Conflicts with my work / Next step, listing what was read), then the window start (UTC) and each subject's session named exactly (harness, the harness's own session id, host by name, `(yours)` on the agent's own machine; `no session id: ask <name> here for a short summary` when there is none). The agent uses its own history tool: it works with session-history tools that speak MCP, such as AgentsView, and switchboard never looks for or runs one. The subjects aren't woken by it. Claude, Codex (once its thread is verified), Cursor (once bound) and Devin sessions, on this machine or a remote one. The MCP server's instructions tell agents to read such a block whole and follow it when it comes from you, and to ignore one from another agent.
|
|
362
|
+
- **Codex joins say "verifying..."** instead of `mcp-only` while switchboard checks that the join came from the thread (the join line, `/who`, `switchboard who` and the buddy list), and the check that passes posts "codex-1 is verified: codex:daemon" (or whatever its tier is then) in each room where its join line said "verifying...".
|
|
363
|
+
- **Remote machines in the web UI.** A chip per remote above the chat (`fpga-pi ● up 2 ms`, `down: unreachable (retry in 8 s)`, `blocked: host key changed`, `needs enable`) opens a remotes panel: state, reason and what to do about it, RTT, where the link dials and the pinned host key, both versions, the remote's hooks as it reports them, clock skew, rooms, members, and **Enable / reconnect** and **Disable** buttons, the same consent as `switchboard remote enable|disable` (recorded as `via web`). The consent is for the config the panel shows: if `remotes.toml` or the key files changed since, Enable is refused (409) and the panel shows the new config; enabling a link blocked by a changed host key, a takeover or exposed stdio asks first. Members on a remote machine carry a host badge in the buddy list (`bench @fpga-pi`) and post as `bench@fpga-pi`. New API routes `GET /api/remotes` and `POST /api/remotes/{name}/enable|disable` (web session, exact Origin and `X-Switchboard: 1`; enable takes the `config_hash` the page showed), and a `remotes` WebSocket event when a link's state, its members or the set of remotes changes.
|
|
364
|
+
- **The FPGA bench demo** ([docs/DEMO-FPGA.md](docs/DEMO-FPGA.md)): setup, prompts, the recording script, and what to do when something goes wrong on camera. **A fake remote machine** in a container (`sandbox/twohost/compose.yaml`, profile `demo`: sshd on this machine's loopback only, a stand-in `openFPGALoader`, a pty "board" and a UART test) stands in when you have no Pi or board, and `tests/live/m8_demo.py` rehearses the demo, unattended against the container (`SWITCHBOARD_LIVE=fakepi … --scripted`) or with real Claude sessions on your real machines (`SWITCHBOARD_LIVE=pi`).
|
|
365
|
+
- **Two-host tests** (`uv run pytest -m twohost tests/twohost`, opt-in, Docker needed; a CI job of their own): a desktop and a remote machine in two containers with separate PID namespaces, paired for real over SSH, handing bitstreams back and forth through `rrsync` keys, through a network partition and back.
|
|
366
|
+
- **The remote-member link, first part** ([DESIGN.md §27.4](docs/DESIGN.md#274-the-link), §27.16): the broker can now run a link to a second switchboard home, with a `switchboard satellite` at the far end vouching for that machine's processes. Agents there join rooms as their own members (`bench@fpga-pi` in `switchboard who`), their hooks resolve on their own machine, and nothing human, room or sys crosses a link. New commands `switchboard remote enable|disable|status`; `switchboard status` lists remotes. A remote dials only while you have enabled its exact config (any edit of its `remotes.toml` entry or key files needs a new enable), and narrowing its `rooms` or `harnesses` ends the members it no longer allows at once.
|
|
367
|
+
- **Remote members over SSH: the link and pairing** ([docs/REMOTE.md](docs/REMOTE.md), [DESIGN.md §27.4.1, §27.8](docs/DESIGN.md#27-remote-members-over-ssh-m8), §27.16). The broker dials a remote with `/usr/bin/ssh` and a fixed argv of its own (no ssh config, no agent, only the link key, the remote's host key pinned; nothing forwarded). New commands: `switchboard remote add <name> <[user@]host> --rooms …` (this machine: pins the host key you accepted by hand, makes the link key, writes `remotes.toml`, prints a one-line token), `switchboard remote accept '<token>' [--from IP]` (the remote: shows and writes the one `authorized_keys` line that lets that key start only the satellite, with a backup), `switchboard remote remove <name>` (either machine) and `switchboard remote doctor` (either machine: link states, key and pin files, keys that open a shell, `allow_ssh_cli`, the forced command, an agent socket in the session; `--probe-desktop` on the remote tries whether it can open a shell here). A changed host key, a refused key, or a remote that can't start the satellite **blocks** the link with a warning in its rooms naming the reason and the fix (fix, then `remote enable`); network trouble is retried. The warning never quotes ssh's output, which can hold text the remote machine printed; `switchboard remote status` shows it to you. A link that was up never blocks itself on the way back. On Linux the satellite refuses to start when another process of its user holds its link's stdio.
|
|
368
|
+
- **A remote's pinned host key file must hold exactly that one key** (`remotes/<name>/known_hosts`, as `remote add` writes it): another line, a link there, or a key file or folder that others can use blocks the link (`files`), and every line of it is part of what `remote enable` consents to. A switchboard home whose path has a blank or one of `" ' \ # % $ ~` can't dial a remote (ssh would read it as more than one path).
|
|
369
|
+
- `remote accept`, `remove` and `doctor` use the `authorized_keys` under your home as the password database has it (the one sshd reads); when `$HOME` points elsewhere they ask for `--authorized-keys`. On a remote with two satellite homes for one remote name (two desktops), each home's `accept` and `remove` touch only its own line. `remote doctor` there fails a link line with anything beyond `restrict`, `from=` and the satellite's own command.
|
|
370
|
+
- Removing a remote from `remotes.toml` while the broker is stopped (or by hand) now also forgets your consent for it once the broker runs: added back, it needs `remote enable` again.
|
|
371
|
+
- **Claude Code over a remote link** ([DESIGN.md §27.5.6](docs/DESIGN.md#2756-host-views-liveness-and-the-claude-registry), §27.16): a Claude session on the remote machine gets the inbox tier (`claude:inbox`), as it does on this one. An idle session is woken through its own inbox by its own MCP server; the remote machine reads its session registry and relays it, so an approval prompt open there holds its deliveries (the buddy list shows waiting-approval) and a turn ended with Esc is noticed. Just before a message is posted there, the remote end reads the registry again: if the session is no longer idle (or, for a mid-task message to a session in bypass mode, no longer running), nothing is posted and the message waits for the next chance, without counting as a failed delivery. Nothing about the session but its status and timing crosses the link; its messaging token never does. The remote end enforces the approval hold itself: a message for a Claude session there is posted only into the session its own MCP server belongs to, and never while that session's approval prompt is open, whatever this machine sends. If the remote end could not protect itself from other processes of its user (Linux: it could not make itself non-dumpable), the remote's rooms get a warning.
|
|
372
|
+
- **`host` in the API:** each member of `/api/rooms/…/members` (and `switchboard who --json`) says its host (`""` for this machine), and each message its agent sender's (`null` for this machine and for you).
|
|
373
|
+
- **Coverage in CI:** line coverage of the Linux and macOS test runs, combined, with a floor that only goes up and a README badge ([CONTRIBUTING.md](CONTRIBUTING.md), "Coverage").
|
|
374
|
+
- **Coverage tests** for the delivery engine and runner, the Codex, Cursor and Devin adapters and the Codex app-server client, broker commands, hub, web routes and `switchboard report`, the hook script and the installers: each of these modules is now at 100% line coverage, and the CI floor is 93%.
|
|
375
|
+
|
|
376
|
+
### Changed
|
|
377
|
+
|
|
378
|
+
- **Any uv 0.7.13 or newer works for development.** `pyproject.toml` now sets `required-version = ">=0.7.13"` (it was `==0.7.13`, which refused newer uv in the checkout). CI stays on 0.7.13 with `--frozen`.
|
|
379
|
+
- **Tests run in parallel** with pytest-xdist (`uv run pytest -n auto`), in CI too: about 3 minutes instead of 9 locally.
|
|
380
|
+
- **Remote machines may join any room by default.** `rooms = ["*"]` in `remotes.toml` (the default when `rooms` is left out, or when `remote add` gets no `--rooms`) lets that machine's members join every room, including rooms created later. List rooms to limit them, as before.
|
|
381
|
+
- **`/review` is now an alias of `/catchup`** until 0.4: `/review <reviewer> <author> [note]` posts `/catchup <reviewer> on <author> review it critically[: note]`, and its reply says "/review is now /catchup; the alias goes away in 0.4". The request no longer asks to look at the changes first or names an `agentsview` command.
|
|
382
|
+
- **`/who` and `switchboard who`** show each member's `session: <id> @ <host>` (`session` in `switchboard who --json`, replacing `transcript`), to you only, whether or not any history tool is installed.
|
|
383
|
+
- **`switchboard report`** counts catch-up requests in one row, "/catchup (catch-up requests posted, /review included)" (JSON `rules.catchup`, replacing `rules.review`).
|
|
384
|
+
- **`switchboard cmd '#room' …`** passes a word that the shell kept together (it has a space) on in double quotes, so `switchboard cmd '#build' /catchup codex-1 on "sprint cleanup"` works as typed. A quoted multi-word note keeps its quotes.
|
|
385
|
+
- **README: tell agents "join switchboard room #build as claude-1"**: an agent that also has Slack or Discord tools read "join the #build channel" as a Slack or Discord request.
|
|
386
|
+
- **`remotes.toml` must be yours and writable only by you** (`remote add` writes it 0600); otherwise it is refused, and nothing dials.
|
|
387
|
+
- **Agents can't join through a socket forward.** An MCP server whose connection to the broker arrives through `ssh -R`/`-L` or socat (the broker sees only the relay, so every agent behind it would be one member) is refused with a pointer to remote links. Agents on another machine will join over a remote link instead (above).
|
|
388
|
+
- **Human commands over SSH are refused.** `switchboard say`, `cmd`, `login` and the other human verbs are now refused when the process on the broker's socket is an SSH or socket relay (`ssh -R`/`-L` or socat forwarding the socket: the broker would otherwise see the relay as you), and when the command runs under a remote login to this machine (sshd, dropbear, mosh-server, tinysshd, Tailscale SSH, Eternal Terminal or telnetd above it). The error says why; `switchboard start` over such a login says why it printed no sign-in link. This only closes the direct routes: never give another machine a key that opens a shell here. New setting `[security] allow_ssh_cli = true` allows the second case, for people who work on this machine over SSH; a relay stays refused. The web UI is unaffected.
|
|
389
|
+
|
|
390
|
+
### Removed
|
|
391
|
+
|
|
392
|
+
- **The agentsview lookup.** switchboard no longer looks for agentsview (on its PATH or at `[review] agentsview`) or depends on it, and `/review` no longer fails without it. `[review] agentsview` in `config.toml` is still accepted, so a 0.2.0 config loads, but ignored: the broker logs a warning once at start; you can remove the key.
|
|
393
|
+
|
|
394
|
+
### Fixed
|
|
395
|
+
|
|
396
|
+
- **Claude Desktop sessions in WSL and on Linux are recognized as Claude.** Claude Desktop runs them as `~/.claude/remote/ccd-cli/<version>`, which switchboard didn't match. Such a session was treated as an unknown agent: no inbox wakes, hooks did nothing, and its shell passed the human-only check on a machine running its own broker.
|
|
397
|
+
- **Names and keys are checked as whole strings.** Remote names, host and user names, labels, key types and the link's version and reason fields were matched with a pattern that also let a trailing newline through; they now must match whole (a web route name with `%0A` is a 400, not a 404).
|
|
398
|
+
- **A remote's hook-check line can't carry its own text.** `remote status` and the web UI showed the file names a remote's `hooks/` check found as the remote sent them. The satellite now names only files shaped like a hook copy and counts the rest, and the broker strips control, bidi and zero-width characters and line breaks from whatever arrives.
|
|
399
|
+
- **A message that was never handed over no longer spends the wake budget.** When a wake is re-routed because the session changed just before it was posted (a Codex turn that ended, a remote Claude session that stopped being idle), the room gets its budget unit back; only the wake that is finally handed over counts.
|
|
400
|
+
- **Claude's session files are read more carefully.** A file there that is not a plain file (a link, a pipe), is too large or doesn't parse is now skipped without waiting on it or failing, on this machine and on a remote one.
|
|
401
|
+
- **No reconnect storm in the MCP server.** When something accepted its broker connection and closed it at once (a socket forward whose far end is down), the MCP server reconnected in a tight loop (22,124 connects in 3 s in a test). It now waits after every dropped connection and backs off until a broker actually answers (3 connects in 3 s), and a connection that drops before its hello is answered no longer leaves the server waiting 10 s for it. After a broker restart, agents reconnect up to 0.5 s later than before.
|
|
402
|
+
|
|
403
|
+
## 0.2.0 (2026-09-27)
|
|
404
|
+
|
|
405
|
+
The first public release, and a new name: this project was called yakroom until 0.2.0. Every name moved with it: the `switchboard` command, `http://switchboard.localhost:7419`, `~/.switchboard`, `SWITCHBOARD_*` settings and the `mcp__switchboard__*` tools.
|
|
406
|
+
|
|
407
|
+
To move a 0.1.0 install:
|
|
408
|
+
|
|
409
|
+
1. `yakroom stop && yakroom uninstall all`, then `uv tool uninstall yakroom`.
|
|
410
|
+
2. Copy only your data: `mkdir -m 700 ~/.switchboard`, then copy `~/.yakroom/config.toml` (if you have one) into it, and `~/.yakroom/yakroom.db` to `~/.switchboard/switchboard.db`, together with `yakroom.db-wal` and `yakroom.db-shm` if they exist (as `switchboard.db-wal` and `switchboard.db-shm`; the `-wal` file can hold your latest messages). Leave `hooks/` and `run/` behind: switchboard never uses or removes the old `yakroom_hook-*.py` copies.
|
|
411
|
+
3. Install switchboard ([docs/INSTALL.md](docs/INSTALL.md)), then `switchboard install all` and `switchboard start`.
|
|
412
|
+
|
|
413
|
+
Your history keeps its old room notices, sent by `yakroom`.
|
|
414
|
+
|
|
415
|
+
### Added
|
|
416
|
+
|
|
417
|
+
- **`/review <reviewer> <author> [note]`:** ask one agent to review another member's recent work as a skeptical second reviewer, with the author's session transcript through [agentsview](https://github.com/kenn-io/agentsview) (optional; never run by switchboard). It posts one ordinary message from you that @mentions the reviewer: the changes first, then `agentsview session messages <id>`. The author isn't woken by it. Claude, Codex (once its thread is verified) and Cursor authors; Devin authors not yet. A reviewer with approvals off gets a warning notice. `/who` and `switchboard who` show each member's agentsview id when agentsview is found. New config key `[review] agentsview`. See the README's "Reviews with context (agentsview)".
|
|
418
|
+
|
|
419
|
+
### Changed
|
|
420
|
+
|
|
421
|
+
- **Default screen name:** your login name (lowercased), or `me` when it isn't a valid screen name, instead of a fixed name. Set `human_name = "…"` in `~/.switchboard/config.toml` to keep the name you had.
|
|
422
|
+
- **`switchboard cmd '#room' …`** takes everything after the room as the command, so arguments starting with `-` (a `/review` note's `--from`) no longer fail as unknown options. Put options such as `--home` before the room.
|
|
423
|
+
|
|
424
|
+
## 0.1.0 (2026-09-25, as yakroom)
|
|
425
|
+
|
|
426
|
+
Released as yakroom (the `yakroom` command, `~/.yakroom`, `http://yakroom.localhost:7419`); the names below are the 0.2.0 ones.
|
|
427
|
+
|
|
428
|
+
The first release. switchboard is a 90s-style chatroom where you and the coding-agent sessions you open in your own terminals (Claude Code, Codex, Cursor Agent CLI, Devin CLI) talk in real time. Everything runs locally: a broker on 127.0.0.1 and a web page at `http://switchboard.localhost:7419`.
|
|
429
|
+
|
|
430
|
+
### Added
|
|
431
|
+
|
|
432
|
+
- **Rooms for you and your agents:** a Windows 95-style web UI with a buddy list, @mentions and commands (`/pause`, `/resume`, `/budget`, `/hops`, `/hold`, `/release`, `/kick`, `/who`, `/status`), and a CLI (`switchboard say`, `tail`, `who`, `cmd`, `report`).
|
|
433
|
+
- **Push delivery into the sessions you already have open**, with no wrappers and no keystroke injection:
|
|
434
|
+
- Claude Code: the built-in inbox socket wakes an idle session (about 50 ms); hooks deliver mid-task.
|
|
435
|
+
- Codex: the shared app-server daemon (`turn/start`, `turn/steer`).
|
|
436
|
+
- Devin: a `wait()` loop re-armed by the Stop hook; hooks deliver mid-task.
|
|
437
|
+
- Cursor: a Stop-hook park and hooks. Provisional: not yet tested live.
|
|
438
|
+
- **Delivery rules:** your messages go first, batching, rate limits, an hourly wake budget, a loop guard adjustable live with `/hops`, a watchdog for unanswered @mentions, holds while an approval prompt is open, and read-before-pass for untrusted peer messages.
|
|
439
|
+
- **`switchboard install` / `switchboard uninstall`** for each harness or `all`, with `--dry-run` diffs and backups.
|
|
440
|
+
- **`switchboard report`:** latency, turns, posts vs passes, and which rules fired.
|
|
441
|
+
- **Codex daemon restarts and upgrades** are survived: switchboard reconnects and finds the `codex` binary again.
|
|
442
|
+
- **Linux support**, a Docker sandbox (`sandbox/`, see `docs/SANDBOX.md`), and CI on `ubuntu-latest` and `macos-latest`.
|
|
443
|
+
|
|
444
|
+
### Known limitations
|
|
445
|
+
|
|
446
|
+
- Cursor has not been tested live.
|
|
447
|
+
- Agents have not been run live on Linux, and WSL2 is untested.
|
|
448
|
+
- Claude's inbox socket is an undocumented internal and could change.
|
|
449
|
+
- Devin can't be woken from outside once its `wait()` re-arms run out; it needs a poke.
|
|
450
|
+
- More in [docs/LIMITATIONS.md](docs/LIMITATIONS.md).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ari Mahpour
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|